複数の行と列を効率的に更新する方法
PostgreSQLでサブクエリから複数の行と列を更新または挿入する方法
更新
構文:
UPDATE target_table
SET column1 = value1, column2 = value2, ...
FROM subquery;
説明:
target_table
: 更新対象のテーブルcolumn1, column2, ...
: 更新する列subquery
: 更新に使用するサブクエリ
例:
UPDATE customers
SET email = LOWER(email), last_login = CURRENT_TIMESTAMP
FROM customers
WHERE last_login < NOW() - INTERVAL '1 month';
この例では、customers
テーブル内のすべての顧客の電子メールアドレスを小文字に変換し、1 か月以上ログインしていない顧客の最終ログイン日時を現在時刻に更新します。
挿入
INSERT INTO target_table (column1, column2, ...)
SELECT value1, value2, ...
FROM subquery;
INSERT INTO orders (customer_id, product_id, quantity)
SELECT customer_id, product_id, quantity
FROM shopping_carts;
この例では、shopping_carts
テーブル内のすべてのカート内の商品を orders
テーブルに挿入します。
注意事項
- サブクエリは、更新または挿入する列と同じ数の列を返す必要があります。
- サブクエリは、WHERE 句を使用して更新または挿入する行を制限することができます。
PostgreSQLにおけるサブクエリを使用した更新と挿入のサンプルコード
更新
例1:顧客の電子メールアドレスを小文字に変換し、ログインが1か月以上経過していない顧客の最終ログイン日時を現在時刻に更新する
UPDATE customers
SET email = LOWER(email), last_login = CURRENT_TIMESTAMP
FROM customers
WHERE last_login < NOW() - INTERVAL '1 month';
- このクエリは、
customers
テーブル内のすべての顧客の電子メールアドレスを小文字に変換します。 - さらに、1 か月以上ログインしていない顧客の
last_login
列を現在時刻に更新します。 - サブクエリは、更新対象の顧客を特定するために使用されます。
例2:注文ステータスを「処理中」に変更し、発送予定日を1日後に設定する
UPDATE orders
SET status = 'processing', estimated_shipping_date = CURRENT_DATE + INTERVAL '1 day'
FROM orders
WHERE status = 'pending';
- このクエリは、ステータスが「保留中」のすべての注文のステータスを「処理中」に変更します。
- また、これらの注文の発送予定日を1日後に設定します。
挿入
例1:ショッピングカート内のすべての商品を新規注文として挿入する
INSERT INTO orders (customer_id, product_id, quantity)
SELECT customer_id, product_id, quantity
FROM shopping_carts;
- 各新しい注文には、顧客 ID、商品 ID、および数量が含まれます。
- サブクエリは、挿入するデータを提供します。
例2:各顧客の最高購入金額を customer_orders テーブルに新しい行として挿入する
INSERT INTO customer_orders (customer_id, max_order_amount)
SELECT customer_id, MAX(amount)
FROM orders
GROUP BY customer_id;
- 各行には、顧客 ID と最大注文金額が含まれます。
PostgreSQLでサブクエリ以外でデータを更新または挿入する方法
JOIN を使用した更新
UPDATE target_table
SET column1 = value1, column2 = value2, ...
FROM target_table
JOIN other_table ON join_condition
WHERE ...;
other_table
: JOIN するテーブルjoin_condition
: JOIN の条件WHERE
: 更新する行を制限する条件
UPDATE orders
SET status = 'shipped', shipping_date = CURRENT_TIMESTAMP
FROM orders
JOIN shipments ON orders.order_id = shipments.order_id
WHERE shipments.status = 'shipped';
この例では、shipments
テーブルで発送済みとしてマークされているすべての注文のステータスを「発送済み」に変更し、発送日を現在時刻に更新します。
利点:
- サブクエリよりも効率的な場合がある
- JOIN の条件が複雑になる場合がある
CTE (Common Table Expression) を使用した更新
WITH cte AS (
SELECT ...
)
UPDATE target_table
SET ...
FROM cte;
cte
: 共通表式 (CTE) の名前SELECT ...
: CTE で定義するクエリSET ...
: 更新する列と値
WITH customer_orders AS (
SELECT customer_id, SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
)
UPDATE customers
SET highest_order_amount = total_amount
FROM customer_orders;
この例では、各顧客の最高購入金額を customers
テーブルの highest_order_amount
列に更新します。
- 複雑な更新を複数のクエリに分割できる
- CTE を再利用して別のクエリで使用できる
INSERT 文を使用した挿入
INSERT INTO target_table (column1, column2, ...)
VALUES (value1, value2, ...), ...;
INSERT INTO orders (customer_id, product_id, quantity)
VALUES
(1, 23, 1),
(2, 17, 2),
(3, 42, 3);
この例では、3 件の新しい注文を orders
テーブルに挿入します。
- シンプルでわかりやすい
- 挿入するデータが多い場合は冗長になる可能性がある
COPY コマンドを使用した挿入
COPY target_table (column1, column2, ...) FROM 'data_file.csv' DELIMITER ',' CSV HEADER;
data_file.csv
: 挿入するデータを含む CSV ファイルDELIMITER ','
: CSV ファイルの区切り文字CSV HEADER
: CSV ファイルの最初の行にヘッダーが含まれていることを示す
COPY orders (customer_id, product_id, quantity) FROM 'orders.csv' DELIMITER ',' CSV HEADER;
この例では、orders.csv
という名前の CSV ファイルから orders
テーブルにデータを挿入します。
- 大量のデータを効率的に挿入できる
- CSV ファイル形式のデータである必要がある
最適な方法を選択する
最適な方法は、更新または挿入するデータの量と複雑性によって異なります。
- 少量のデータを更新または挿入する場合は、INSERT 文または UPDATE 文を使用するのが最も簡単です。
- より多くのデータを更新または挿入する場合は、JOIN
sql postgresql sql-update