「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > 主キーまたは一意制約を使用しない DB 内の行を更新/挿入します

主キーまたは一意制約を使用しない DB 内の行を更新/挿入します

2024 年 11 月 8 日に公開
ブラウズ:959

Upsert a row in a DB that doesn

プログラマーとしての 7 年間のキャリアの中で、私はほとんどの場合 ORM を介して SQL を操作してきました。私が特に便利だと思う Laravel の Eloquent ORM の機能の 1 つは、その updateOrInsert() メソッドです:

DB::table('posts')
    ->updateOrInsert(
        ['slug' => 'about'], // matching condition
        ['content' => 'Like and subscribe'] // created or updated values
    );

上記の例では、Eloquent は、posts テーブル内でスラッグが「about」に等しい行を探します。そのスラッグを含む行が存在する場合、Eloquent はその行のコンテンツを「いいね!」と「購読」に更新します。そのスラッグを含む行が存在しない場合、Eloquentは「about」のスラッグと「Like and subscribe」の内容を含む新しい行を作成します。

問題: 主キーまたは一意の制約がない

現在、古い WordPress サイトから新しい WordPress サイトにページ データを移動する移行スクリプトを作成しています。スクリプトは古いサイトのデータベースに接続し、新しいサイトのデータベースにインポートできる SQL ファイルを作成します。新しいサイトにはすでに手動で移動されたページがいくつかありますが、そのコンテンツは古くなっている可能性があります。新しいサイトにページがすでに存在する場合、それを再度作成するのではなく、すでに存在するページを更新したいと考えます。ページの URL スラッグに対応する WordPress データベースの post_name 列を使用して、ページがすでに存在するかどうかを判断できます。

post_name が主キーの場合、REPLACE ステートメントを使用して Eloquent の createOrUpdate() メソッドと同様のことを実行できますが、post_name は主キーではありません。

post_name に一意の制約がある場合、INSERT ... ON DUPLICATE KEY UPDATE ステートメントを使用して Eloquent の createOrUpdate() メソッドと同様のことを実現できますが、post_name には一意の制約がありません。

ああ、WordPress の楽しさ。

MySQL の IF ステートメントを調べましたが、IF ステートメントはストアド プロシージャ、トリガー、関数でのみ機能します。新しいサイトのデータベースにインポートする SQL ファイルにストアド プロシージャを作成したくなかったので、他のオプションを探す必要がありました。

解決策: 2 つのステートメント

純粋な SQL で Eloquent の updateOrInsert() 機能をエミュレートするために私が見つけた最も簡単な解決策は、問題を 2 つの部分に分割することでした:

  1. 一致するスラッグを使用して既存の行を更新します。
  2. 一致するスラッグを持つ行がない場合は、新しい行を作成します。

実際には次のようになります:

-- Update the post if it already exists.

UPDATE wp_posts
SET post_type = 'page',
    post_title = 'About',
    post_content = 'Like and subscribe'
WHERE post_name = 'about';

-- Create a new post if it does not exist.

INSERT INTO wp_posts (post_name, post_type, post_title, post_content)
SELECT 'about', 'page', 'About', 'Like and subscribe'
WHERE NOT EXISTS (
    SELECT 1
    FROM wp_posts
    WHERE post_name = 'about'
);

注: この例では、簡潔さと明確さのために WordPress に必要な wp_posts 列の多くを省略しています。

INSERT ... SELECT ステートメントについて学んだことは、私にとって「なるほど」と思った瞬間でした。別のテーブルからのクエリの結果を使用して、一度に多数の挿入を実行することを目的としています。ただし、独自の値を指定し、post_name が "about" の投稿が存在しない場合にのみ挿入を実行することで、SQL の機能を悪用することができます。

これは、この問題に対する最もエレガントで効率的な解決策ですか?おそらくそうではありません。ただし、WordPress サイトの 1 回限りの移行には十分であり、ストアド プロシージャやアプリケーション ロジックを必要とせずに行を更新または挿入できます。この投稿が、ORM を使用せずに強力なクエリを作成する際に役立つことを願っています。

リリースステートメント この記事は、https://dev.to/tylerlwsmith/upsert-a-low-in-a-db-that-doesnt-use-primary-keys-or-unique-constraints-2jnlに再現されています。
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3