web-dev-qa-db-ja.com

レコードが存在しない場合にのみSQLをテーブルに挿入

特定の条件を満たすレコードが満たされた場合にのみ、いくつかのデータをSQLテーブルに挿入するクエリセットを実行します。テーブルには4つのフィールドがあります:id(プライマリ)、fund_iddateprice

クエリには3つのフィールドがあります:fund_iddateprice

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

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_iddateに一致するレコードがまだ存在しない場合にのみ、データを挿入します。上記が正しい場合、毎回追加の選択ステートメントを実行する必要があるため、これを達成するための非常に非効率的な方法であると思います。

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

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

62
harryg

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

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値を含めることはできないという警告があります。

40
harryg

これは、これを達成するための簡単なソリューションかもしれません。

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'));

p.s。あるいは(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

this Fiddle を参照してください。

57
Trinimon

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

FIDDLE

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
6
gillyspy