70

SQL テーブルにデータを挿入する一連のクエリを実行したいのですが、特定の条件を満たすレコードがある場合に限ります。テーブルには 4 つのフィールドがあります: ( idprimary) fund_id、、、dateprice

fund_idクエリには、dateおよびの 3 つのフィールドがありますprice

したがって、私のクエリは次のようになります。

INSERT INTO funds (fund_id, date, price)
    VALUES (23, '2013-02-12', 22.43)
    WHERE NOT EXISTS (
       SELECT * 
       FROM funds 
       WHERE fund_id = 23
         AND date = '2013-02-12'
    );

fund_idそのため、 and に一致するレコードdateがまだ存在しない場合にのみ、データを挿入したいと考えています。上記が正しい場合、追加の select ステートメントを毎回実行する必要があるため、これを達成するための非常に非効率的な方法だと思います。

上記を達成するためのより良い方法はありますか?

編集:明確にするために、一意のフィールドでfund_idもありません。date同じ Fund_id または日付を共有するレコードは存在しますが、別のレコードと同じ Fund_id と日付の両方を持つレコードはありません。

4

3 に答える 3

59

これは、これを達成するための簡単な解決策かもしれません:

INSERT INTO funds (ID, date, price)
SELECT 23, DATE('2013-02-12'), 22.5
  FROM dual
 WHERE NOT EXISTS (SELECT 1 
                     FROM funds 
                    WHERE ID = 23
                      AND date = DATE('2013-02-12'));

psまたは (ID主キーの場合):

 INSERT INTO funds (ID, date, price)
    VALUES (23, DATE('2013-02-12'), 22.5)
        ON DUPLICATE KEY UPDATE ID = 23; -- or whatever you need

この Fiddleを参照してください。

于 2013-05-09T11:18:56.050 に答える
45

私が最初に選択したものとしてマークした答えは正しく、私が尋ねたことを達成しますが、これを行うより良い方法があります(他の人は認めましたが、入りませんでした)。とで構成されるテーブルに複合ユニーク インデックスを作成する必要がfund_idありdateます。

ALTER TABLE funds ADD UNIQUE KEY `fund_date` (`fund_id`, `date`);

次に、レコードを挿入するときに、競合が発生したときの条件を追加します。

INSERT INTO funds (`fund_id`, `date`, `price`)
    VALUES (23, DATE('2013-02-12'), 22.5)
        ON DUPLICATE KEY UPDATE `price` = `price`; --this keeps the price what it was (no change to the table) or:

INSERT INTO funds (`fund_id`, `date`, `price`)
    VALUES (23, DATE('2013-02-12'), 22.5)
        ON DUPLICATE KEY UPDATE `price` = 22.5; --this updates the price to the new value

これにより、サブクエリのパフォーマンスが大幅に向上し、テーブルの構造が優れています。MySQL では値として扱われるため、一意のキー列に NULL 値を含めることはできません。

于 2013-11-13T11:06:28.023 に答える
6

DDL を変更できない (一意の制約を作成する) ことができない、または DML の書き込みのみに制限されていると仮定して、テーブル全体に対して値のフィルター処理された結果で null をチェックします。

フィドル

insert into funds (ID, date, price) 
select 
    T.* 
from 
    (select 23 ID,  '2013-02-12' date,  22.43 price) T  
        left join 
    funds on funds.ID = T.ID and funds.date = T.date
where 
    funds.ID is null
于 2013-05-09T11:21:54.397 に答える