1

次に説明する 2 つのデータベース テーブルがあります。アスタリスクは主キーを強調しています。

+----------------+    +----------------+
| posts          |    | url_references |
+----------------+    +----------------+
| id*            |    | url*           |
| post_content   |    | post_id        |
+----------------+    +----------------+

テーブルurl_references内の対応するエントリの存在に基づいて投稿を挿入または更新したいと考えています。これに到達するための SQL コマンドの最適な組み合わせは何ですか? PHP挿入または更新に関する決定を処理することは避けたいと思います。 次のシナリオでは、PHP コマンドを使用した別の段階的な動作について説明します。

SELECT * FROM url_references WHERE url = $url;

シナリオ 1: 新しいエントリを挿入します。

// mysql_num_rows() returns 0
INSERT INTO post (post_content) VALUES ($postContent);
$postId = mysql_insert_id();
INSERT INTO url_references (url, post_id) VALUES ($url, $postId);

シナリオ 2: 既存のエントリを更新します。

// mysql_num_rows() returns 1
$row = mysql_fetch_array($rows);
$postId = $row['post_id'];
UPDATE posts SET post_content = $postContent WHERE id = post_id;

編集 1:投稿のIDを直接確認できないことに注意してください。主キーとしてのURLに基づいて投稿を管理 (挿入/更新) したい。

4

2 に答える 2

1

上記を古典的な方法で行いたい場合は、次のようにします。

まず、それurlが自然な主キーであることに同意するかもしれません。とにかく、検索を高速化するには、この列にインデックスが必要です。

CREATE UNIQUE INDEX url_references_idx ON url_references(url);

その後、実行すると:

INSERT INTO url_references (url) VALUES ($url);

最終的には、次の 2 つのシナリオになります。

• はINSERT成功します。これは、あなた$urlが新しく、次に進むことができることを意味します。

INSERT INTO posts (id, post_content) values (NULL, $postContent);
SELECT LAST_INSERT_ID(); // This will return $post_id
UPDATE url_references SET post_id = $post_id WHERE url = $url;
COMMIT;

このシナリオでは、新しく挿入された行のロックによりurl_references、最初のトランザクションが正常にコミットされた場合 (または失敗した場合は最初のシナリオ)、別のスレッドが 2 番目のシナリオに進むことが保証されます。

• はINSERT失敗します。つまり、あなた$urlはすでに知られており、次の手順に進むことができます。

SELECT post_id FROM url_references WHERE url = $url;
UPDATE posts SET post_content = $postContent WHERE id = $post_id;
COMMIT;

注: 最初のINSERTステートメントurl_referencesは、正しいトランザクション分離レベルとautocommit=off.

注:SELECT ... FOR UPDATEこの場合、既存の行のみをロックするため、使用は機能しません (そして、挿入しようとしている存在しない行をロックする必要があります)。混乱させて申し訳ありませんが、質問の下にある私のコメントは無視してください。

于 2011-08-22T15:25:11.023 に答える
0

テーブルでのREPLACE INTO決定を回避するために使用できます。次に、影響を受ける行の数に基づいて、url_references に INSERT する必要があるかどうかを決定します。このようなもの:INSERT/UPDATEpostsREPLACE

$sql = "REPLACE INTO posts (post_id, post_content) VALUES ($postId, $postContent)";
$result = mysql_query($sql);
$numRows = mysql_num_rows($result);

if ($numRows == 1) {
    // was INSERT not DELETE/INSERT (UPDATE) - need to insert into url_references

    $postId = mysql_insert_id();
    $sql = "INSERT INTO url_references (url, post_id) VALUES ($url, $postId)";

    ... do SQL INSERT etc
}

MySQL のREPLACEドキュメントから:

REPLACE ステートメントは、影響を受ける行の数を示すカウントを返します。これは、削除および挿入された行の合計です。単一行の REPLACE のカウントが 1 の場合、行が挿入され、行は削除されませんでした。カウントが 1 より大きい場合、新しい行が挿入される前に 1 つ以上の古い行が削除されました。

上記の疑似コードはテストしていないので、微調整が必​​要になる場合があることに注意してください。

http://dev.mysql.com/doc/refman/5.0/en/replace.htmlを参照してください。

于 2011-08-21T11:30:17.917 に答える