【SQL Server】FROM句、OUTPUT句、MERGE文を使ったSELECT結果からのUPDATE

2024-04-02

SQL ServerでSELECT結果からUPDATEする方法

方法

  1. FROM句を使用する

最もシンプルで直感的な方法です。 UPDATE文のFROM句でSELECT文を指定することで、SELECT結果を基に更新対象レコードを特定できます。

例:

UPDATE 顧客
FROM 顧客 AS c
INNER JOIN 注文 AS o
ON c.顧客ID = o.顧客ID
SET 顧客.氏名 = o.氏名
WHERE o.注文ステータス = '完了';

この例では、注文ステータスが完了の顧客の氏名を、注文テーブルから取得して更新します。

利点:

  • シンプルで分かりやすい
  • 複雑な結合や集計も可能
  • 複数のテーブルを結合する場合、パフォーマンスが低下する可能性がある
  1. OUTPUT句を使用する

UPDATE文のOUTPUT句を使用すると、更新後のレコードを取得できます。 その後、その結果を別のUPDATE文で使用して、さらに更新することができます。

DECLARE @updatedCustomers TABLE (
  顧客ID INT,
  氏名 VARCHAR(50)
);

UPDATE 顧客
OUTPUT INSERTED.顧客ID, INSERTED.氏名
INTO @updatedCustomers
SET 顧客.氏名 = o.氏名
WHERE o.注文ステータス = '完了';

UPDATE @updatedCustomers
SET 顧客.ポイント = 100
WHERE 顧客.氏名 = '山田太郎';

この例では、まず注文ステータスが完了の顧客の氏名を更新し、更新後のレコードを@updatedCustomersテーブルに格納します。 その後、@updatedCustomersテーブルに基づいて、氏名が山田太郎である顧客のポイントを100に更新します。

  • 複雑な更新処理を複数回のUPDATE文に分けて記述できる
  • 更新後のレコードを取得できる
  • 複数のUPDATE文を実行するため、処理が複雑になる
  1. MERGE文を使用する

UPDATE、INSERT、DELETEをまとめて実行できる便利な文です。 SELECT結果に基づいて、レコードの更新、挿入、削除を効率的に行えます。

MERGE 顧客 AS c
USING (
  SELECT *
  FROM 注文
  WHERE 注文ステータス = '完了'
) AS o
ON c.顧客ID = o.顧客ID
WHEN MATCHED THEN
  UPDATE SET c.氏名 = o.氏名
WHEN NOT MATCHED THEN
  INSERT (顧客ID, 氏名) VALUES (o.顧客ID, o.氏名);

この例では、注文ステータスが完了の顧客の氏名を更新し、注文ステータスが完了だが顧客テーブルに存在しない顧客は挿入します。

  • UPDATE、INSERT、DELETEをまとめて実行できる
  • SQL Server 2008以降でのみ使用可能

上記3つの方法に加え、CASE WHEN式やCTE (Common Table Expressions) を使用する方法など、状況に応じて様々な方法を選択できます。 それぞれの特徴を理解し、最適な方法を選択することが重要です。




FROM句を使用する

-- 顧客テーブル
CREATE TABLE 顧客 (
  顧客ID INT PRIMARY KEY,
  氏名 VARCHAR(50),
  年齢 INT
);

-- 注文テーブル
CREATE TABLE 注文 (
  注文ID INT PRIMARY KEY,
  顧客ID INT,
  注文ステータス VARCHAR(50)
);

-- データ挿入
INSERT INTO 顧客 (顧客ID, 氏名, 年齢) VALUES (1, '山田太郎', 30);
INSERT INTO 顧客 (顧客ID, 氏名, 年齢) VALUES (2, '佐藤花子', 25);
INSERT INTO 注文 (注文ID, 顧客ID, 注文ステータス) VALUES (1, 1, '完了');
INSERT INTO 注文 (注文ID, 顧客ID, 注文ステータス) VALUES (2, 2, '完了');

-- UPDATE
UPDATE 顧客
FROM 顧客 AS c
INNER JOIN 注文 AS o
ON c.顧客ID = o.顧客ID
SET 顧客.氏名 = o.氏名
WHERE o.注文ステータス = '完了';

-- 結果確認
SELECT * FROM 顧客;

顧客ID | 氏名 | 年齢
------- | -------- | --------
1       | 山田太郎 | 30
2       | 佐藤花子 | 25

説明

OUTPUT句を使用する

-- 顧客テーブル
CREATE TABLE 顧客 (
  顧客ID INT PRIMARY KEY,
  氏名 VARCHAR(50),
  年齢 INT
);

-- 注文テーブル
CREATE TABLE 注文 (
  注文ID INT PRIMARY KEY,
  顧客ID INT,
  注文ステータス VARCHAR(50)
);

-- データ挿入
INSERT INTO 顧客 (顧客ID, 氏名, 年齢) VALUES (1, '山田太郎', 30);
INSERT INTO 顧客 (顧客ID, 氏名, 年齢) VALUES (2, '佐藤花子', 25);
INSERT INTO 注文 (注文ID, 顧客ID, 注文ステータス) VALUES (1, 1, '完了');
INSERT INTO 注文 (注文ID, 顧客ID, 注文ステータス) VALUES (2, 2, '完了');

-- UPDATE
DECLARE @updatedCustomers TABLE (
  顧客ID INT,
  氏名 VARCHAR(50)
);

UPDATE 顧客
OUTPUT INSERTED.顧客ID, INSERTED.氏名
INTO @updatedCustomers
SET 顧客.氏名 = o.氏名
WHERE o.注文ステータス = '完了';

-- 結果確認
SELECT * FROM @updatedCustomers;

結果

顧客ID | 氏名
------- | --------
1       | 山田太郎
2       | 佐藤花子

この例では、まず注文ステータスが完了の顧客の氏名を更新し、更新後のレコードを@updatedCustomersテーブルに格納します。

MERGE文を使用する

-- 顧客テーブル
CREATE TABLE 顧客 (
  顧客ID INT PRIMARY KEY,
  氏名 VARCHAR(50),
  年齢 INT
);

-- 注文テーブル
CREATE TABLE 注文 (
  注文ID INT PRIMARY KEY,
  顧客ID INT,
  注文ステータス VARCHAR(50)
);

-- データ挿入
INSERT INTO 顧客 (顧客ID, 氏名, 年齢) VALUES (1, '山田太郎', 30);
INSERT INTO 顧客 (顧客ID, 氏名, 年齢) VALUES (2, '佐藤花子', 25);
INSERT INTO 注文 (注文ID, 顧客ID, 注文ステータス) VALUES (1, 1, '完了');
INSERT INTO 注文 (注文ID, 顧客ID, 注文ステータス) VALUES (2, 3, '完了');

-- UPDATE
MERGE 顧客 AS c
USING (
  SELECT *
  FROM 注文
  WHERE 注文ステータス = '完了'
) AS o
ON c.顧客ID = o.顧客ID
WHEN MATCHED THEN
  UPDATE SET c.氏名 = o.氏名
WHEN NOT MATCHED THEN
  INSERT (顧客ID, 氏名) VALUES (o.顧客ID, o.氏名);

-- 結果確認
SELECT * FROM 顧客;

顧客ID | 氏名 | 年齢
------- | -------- | --------
1       | 山田太郎 | 30
2       | 佐藤花子 | 25
3       | 田中



SQL ServerでSELECT結果からUPDATEする方法:その他の方法

CASE WHEN式を使用する

UPDATE 顧客
SET 顧客.氏名 =
  CASE
    WHEN 注文ステータス = '完了' THEN '更新済み'
    ELSE 顧客.氏名
  END
WHERE 注文ステータス IN ('完了', 'キャンセル');

CASE WHEN式を使用して、注文ステータスに基づいて氏名を更新します。

CTE (Common Table Expressions) を使用する

WITH updated_customers AS (
  SELECT c.顧客ID, c.氏名, o.注文ステータス
  FROM 顧客 AS c
  INNER JOIN 注文 AS o
  ON c.顧客ID = o.顧客ID
  WHERE o.注文ステータス = '完了'
)
UPDATE c
SET c.氏名 = uc.氏名
FROM updated_customers AS uc
WHERE c.顧客ID = uc.顧客ID;

CTEを使用して、更新対象となる顧客の情報を一時的に格納し、それを基に更新を行います。

サブクエリを使用する

UPDATE 顧客
SET 顧客.氏名 = (
  SELECT o.氏名
  FROM 注文 AS o
  WHERE o.顧客ID = 顧客.顧客ID
  AND o.注文ステータス = '完了'
);

サブクエリを使用して、更新対象となる顧客の氏名を注文テーブルから取得します。

上記の方法それぞれに利点と欠点があり、状況に応じて最適な方法を選択する必要があります。


sql sql-server t-sql


【保存版】MySQLの列を自在に操る!移動・追加・削除・型変更を徹底解説

列の順序を変更する構文は以下の通りです。説明:table_name: 列の順序を変更したいテーブルの名前column_name: 順序を変更したい列の名前data_type: 列のデータ型 (このパラメータは省略可能ですが、データ型を変更する場合に使用します)...


データベースエンジンのバックアップと復元を使ってSQL Serverデータベースのすべてのテーブルをドロップする

SQL Server Management Studio (SSMS) がインストールされていることSQL Serverデータベースへの接続情報SSMSを起動し、SQL Serverデータベースに接続します。オブジェクトエクスプローラーで、ドロップしたいテーブルを含むデータベースを展開します。...


MySQLでテーブルの作成日を取得するあの方法が古すぎる!?最新の方法を徹底解説!

方法1:INFORMATION_SCHEMAデータベースのtablesテーブルを利用するMySQL 5.0以降であれば、INFORMATION_SCHEMAデータベースのtablesテーブルに格納されている情報を利用して、テーブルの作成日を取得することができます。...


【超便利】MySQLで現在の日付だけを取得する方法2選!今日の日付を簡単ゲット!

NOW() 関数は、現在の日時を最も汎用的に取得するために使用されます。結果は YYYY-MM-DD HH:MM:SS 形式の文字列で、現在時刻だけでなく現在の日付も含まれます。CURDATE() 関数は、現在の日付のみを YYYY-MM-DD 形式の文字列として取得します。...


PostgreSQL: 存在するはずのテーブルが見つからない!? エラー「relation does not exist」の謎を解き明かす

このエラーが発生する主な原因は以下の3つです。テーブル名の誤りテーブル名にスペルミスや大文字・小文字の誤りがないか確認してください。スキーマ名の省略PostgreSQLでは、テーブルはスキーマという名前空間の中に存在します。デフォルトのスキーマ名はpublicですが、別のスキーマに作成したテーブルの場合、クエリでスキーマ名を指定する必要があります。...