• ベストアンサー

IF NOT EXISTを使用するINSERT文

格納するデータの性質上、主キーや一意キーを設定できないテーブル(testtable)に、ある条件を満たすデータが既にあればデータを登録しない、というINSERT文(下記)を実行したいと考えています。 --------------------------- IF NOT EXISTS ( SELECT * FROM testtable WHERE Entity1='entity1' AND Entity2='entity2' AND localId='myid' AND subsysId='subsysid' AND deactivationDate is NULL ) INSERT INTO shibpid (Entity1, Entity2, localId, subsysId) VALUES ('entity1', 'entity2', 'myid', 'subsysid) ELSE PRINT 'already exist.'; --------------------------- しかし、このSQL文を以下のように実行するとエラーがでてしまいます。 --------------------------- >mysql -u root -p testdb Enter password: ******(パスワードを入力) mysql> IF NOT EXISTS ( -> SELECT * FROM testtable -> WHERE Entity1='entity1' -> AND Entity2='entity2' -> AND localId='myid' -> AND subsysId='subsysid' -> AND deactivationDate is NULL -> ) -> INSERT INTO shibpid (Entity1, Entity2, localId, subsysId) -> VALUES ('entity1', 'entity2', 'myid', 'subsysid) -> ELSE PRINT '111'; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF NOT EXISTS (SELECT * FROM testtable WHERE Entity1='entity1' at line 1 mysql> --------------------------- 文法エラー、といわれても、どこが違うのか全くわからず、非常に困っています。 もしや、IF NOT EXISTS は使えない、あるいはこのような使い方はできないのでしょうか?

  • SSMSE
  • お礼率25% (17/67)
  • MySQL
  • 回答数7
  • ありがとう数6

質問者が選んだベストアンサー

  • ベストアンサー
  • masa6272
  • ベストアンサー率66% (93/140)
回答No.4

IF EXISTS などという文は、SQLにはありません。 これは、条件に書くものです。 SQL文は集合演算的な言語ですので、こういった手続き型の記述はストアードプロシージャなどで行います。 ただ。こういった手はあります。 まず、1行だけのテーブルを作ります。これはOracleで言えばdualのようなものです。FROM句にダミーで使います。 CREATE TABLE onerow(x int); INSERT INTO onerow values(0); そして次のようなSQL文を発行します。 INSERT INTO shibpid (Entity1, Entity2, localId, subsysId) (SELECT 'entity1', 'entity2', 'myid', 'subsysid' FROM onerow WHERE NOT EXISTS ( SELECT * FROM testtable WHERE Entity1='entity1' AND Entity2='entity2' AND localId='myid' AND subsysId='subsysid' AND deactivationDate is NULL))

SSMSE
質問者

補足

これを試してみたところ、期待する動作を得ることができました! ダミーのテーブルに問い合わせる分、資源消費や処理速度が心配ですが・・・それにしても、こんな方法もあったとは。 勉強になりました。

その他の回答 (6)

  • masa6272
  • ベストアンサー率66% (93/140)
回答No.7

まだ開いているようですので・・・ 効率は問題ないですよ。 条件式のNOT EXISTSの方がほとんどの時間を食うでしょう。 それに比べれば、無視できるコストだと思います。

SSMSE
質問者

お礼

たびたびの補足説明、有難うございます。 > 条件式のNOT EXISTSの方がほとんどの時間を食うでしょう。 意外にもダミーテーブルを使った問い合わせの方が早いのですね。 また1つ、勉強になりました。 最後までお付き合いくださり、本当にありがとうございました。

  • masa6272
  • ベストアンサー率66% (93/140)
回答No.6

#4です。 補足です。 MySQLでは、FROM句のないSELECT文が書けます。 SELECT 1,2,3; を実行すると、1,2,3からなる1行が返されます。 しかし、WHERE句を書く時にはFROM句がないとシンタックスエラーと怒られます・・・ で、このような無害なテーブルを使ってます。 この解は、ほとんどのRDBMSで動きます。Oracleの場合は、onerowと同じ役割を果たすdualというテーブルが最初からありますので、そちらを使えます。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.5

この場合、適当なフィールドにUNIQUE属性をつけておいて INSERT IGNORE INTOでインサートしてやるのが現実的かと

SSMSE
質問者

補足

最初、一意のデータを表現できる、最低限の複数のフィールドでUNIQUEキーを設定することを考えました。 (データの性質上、単独のフィールドで一意にならないのです。) しかし、その最低限の複数のフィールドのなかにNULLが入るものがあり、NULLが入ると一意性の判定をしてくれないらしく、そのフィールドの値がNULLであれば同じデータが幾らでも登録できてしまいました。 このような事情から、キー制約以外の方法を探していました。

回答No.3

記憶によると IF NOT EXIST は、CREATE TABLE などにしか使えなかったと思います。 英文ですが、代替手段はあるようです。 http://bogdan.org.ua/2007/10/18/mysql-insert-if-not-exists-syntax.html フロー制御を駆使すれば出来るような気もするのですが。 http://dev.mysql.com/doc/refman/5.1/ja/control-flow-functions.html (過去にやったことがあると思ったので自分のソースを見てみたところ アプリケーション側で処理してました) 5.0だとストアドも使えるようです。

SSMSE
質問者

補足

> 英文ですが、代替手段はあるようです。 ここに挙げられた方法の動作は私の希望とちょっと違うようです。 (私のテーブルには主キーなどが無いので、ここで紹介されている方法のどちらでも、どんどん登録データが増えてしまうのです。) ただ、文中にあげられている、ダミー操作(多分、#4の方が述べているのと同じ感じだと思います)は検討の価値がありそうです。 > フロー制御を駆使すれば出来るような気もするのですが。 こちらは、現状、「そんな気がするけど、いまいち使い方がわからないなぁ」状態です。 もう少し自分で調べてみて、必要なら改めて質問したいと思います。 > 5.0だとストアドも使えるようです。 ストアドプロシージャの使用は検討したのですが、できるだけDBの種類に依存しない方法を採りたい、との思いから、これは最終手段ということにしています。

回答No.2

>IF NOT EXISTS これは、SQL ServerのT-SQLの構文では?

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.1

>IF NOT EXISTS の構文は具体的になにを参考になさっているのでしょうか? また、ご利用になっているMySQLのバージョンはいくつでしょうか?

SSMSE
質問者

補足

以前に使用したことがある、SQL SERVERでこのようなことができた気がするのだけど・・・というのと、MySQLでもDROP DATABASE文などでIF EXISTS句を使用しているので使えるのでは?という、2つから質問のようなクエリを記述しました。 使用しているMySQLは5.0です。

関連するQ&A

  • 見たことのないINSERT文

    お世話になります。 他人の書いたSQLを解析して以下のようなコードを見つけました。 CREATE TABLE OYA ( ID NUMBER NOT NULL, NAME VARCHAR2(10) ) / CREATE TABLE KO ( ID NUMBER NOT NULL, OYA_ID NUMBER NOT NULL, NAME VARCHAR2(10) ) / INSERT INTO ( SELECT ID ,OYA_ID ,NAME FROM KO WHERE EXISTS ( SELECT ID FROM OYA WHERE NAME LIKE '%1' ) ) VALUES ( 1 ,1 ,'KODOMO-1' ); INSERT文でテーブル名を指定するかわりにSELECT文を指定しています。 SELECT INSERT文は知っていますが、このような表記は初めてです。 (文法エラーにならないのに驚きました) おそらく意図するところは、ある条件に一致したOYAが存在する場合に、KOをインサートするのだと思いました。 実際は、OYAがなくてもINSERTは実行されてしまいますが。。。 このような表記のINSERT文の説明が書いてあるサイトをご存知の方がいらっしゃいましたら、よろしくお願いします。

  • データ登録時、重複エラーを避けたい

    MYSQLのデータベースの、IDという項目が主キーのTESTというテーブルに、データをに登録する際、 既に主キーが同じデータがない場合に、という条件をつけたいのですが、 下のように書くと、エラーになってしまいます。 INSERT INTO TEST (ID, NAME) VALUES ('a', 'abc') WHERE NOT EXISTS (SELECT * FROM TEST WHERE ID = 'a'); どうしたらよいか教えてください。

    • ベストアンサー
    • MySQL
  • PHP/MySQL INSERT文について。

    PHP/MySQL INSERT文について。 こんばんは。 PHP・MySQLでデータベースへデータの書き込みを試行錯誤しております。 そこで一つどうしても解決出来ない問題(謎)があるので質問させて頂きます。 簡易的な質問内容としては 全てのカラムに対する値の挿入は可能なのに カラムを指定して値を挿入しようとしたらエラーが出ます。 データベースの設定はテーブル名【TESTtable】 フィールド 種別 NULL 属性/その他 AAA int(6) No UNSIGNED ZEROFILL / auto_increment BBB int(4) Yes CCC int(4) Yes DDD int(4) Yes PHPでのSQL実行文をしてはの記述としては(値は全て可変で数値を代入します。) INSERT INTO TESTtable VALUES (last_insert_id(),50,600,50) とした場合は問題無くテーブルに書き込みされますが カラムを指定して INSERT INTO TESTtable (AAA,BBB,CCC,DDD) VALUES (last_insert_id(),50,600,50) とした場合、書き込みが行われません。 INSERT INTO TESTtable ('AAA','BBB','CCC','DDD') VALUES (last_insert_id(),50,600,50) INSERT INTO TESTtable (AAA,'BBB','CCC','DDD') VALUES (last_insert_id(),50,600,50) INSERT INTO TESTtable ('AAA','BBB','CCC','DDD') VALUES (last_insert_id(),'50','600','50') 等、色々試してみましたが不可能でした。 カラムAAAはauto_incrementにりますので毎回書き込みされますが BBB、CCC、DDDは書き込みが不要の場合もあるので カラム指定の書き込みは必須となるのですが・・・行き詰ってしまいました・・・。 ご教授頂ければ幸いです。 どうぞ、宜しくお願い致します。

    • ベストアンサー
    • MySQL
  • 副問い合わせのinsert文

    いつもお世話になっています。 insert文の副問い合わせのことでお聞きしたいのですが、 ■通常のinsert文 insert into AAA values(aaa,bbb,ccc); 上記のsqlを副問い合わせにした場合(aaaに別テーブルからの検索結果を入れたい場合)どういうSQL文になるでしょうか。 参考書等を参照すると、副問い合わせの場合はvaluesを省略する(使えない?)と記述がありました。 insert into AAA values ( aaa IN (SELECT bbb from BBB where ccc = ddd),bbb,ccc); とはできないみたいですので… どうかご教授宜しくお願いします。

  • INSERT文の書式

    oracleに触るの初めてなのにストアドなんて書くことに・・ 助けを頂けたらと思います。 ストアドの中でですが・・・・ INSERT文の中ではテーブルの項目が2つ以上あるとき、 変数にその2つ以上分の値を文字列として入れておいて 、その値をINSERT文に流すことってできないのでしょう か? test_str := (' ''テスト1'' , ''テスト2'' '); insert into TestTable (test1 , test2 ) values (test_str); 上記のように書くと PL/SQL: ORA-00947: 値の個数が不足しています。 とのエラーが帰ってきます。 上記のように変数を使って下記のように解釈させたいのですが無理なのでしょうか? insert into TestTable (test1 , test2 ) values ('テスト1','テスト2'); それではお願いします。 失礼いたします。

  • 測定結果が決められた範囲内か判定するSQL文

    決められた範囲内に測定結果が入っているかを判定するSQL文(またはストアドプロシージャ)を PostgreSQL 14.0を使って作ろうとしていますが、正しい結果が得られません。 具体的には、ケーブル・テーブルとスペック・テーブルで一致するテスト項目同士(例えば、'Test_1'同士)だけを比較したいのですが、他のテスト項目も引っ掛けてしまいます。 あと、下記のwhere test_item = 'Test_1', 'Test_2', 'Test_3'の部分を select test_item from cable; から一つ一つ取り出してループで回して代入し、最終的には id | test_item | test ----+-----------+------ 1 | Test_1 | 1.5 2 | Test_1 | 1.8 2 | Test_2 | 2.5 という、まとまった出力を得たいのですが、その方法を教えていただけないでしょうか? 自作のテーブルとSQL文は以下になります: create table cable( id integer default 0 not null ,test_item varchar(30) not null ,test numeric(3, 1) ,primary key (id, test_item) ); insert into cable values(1, 'Test_1', 1.5); insert into cable values(1, 'Test_2', 4.5); insert into cable values(1, 'Test_3', 2.5); insert into cable values(2, 'Test_1', 1.8); insert into cable values(2, 'Test_2', 2.5); insert into cable values(3, 'Test_3', 2.5); create table spec( test_item varchar(30) not null , lower_spec numeric(3, 1) , upper_spec numeric(3, 1) , primary key(test_item) ); insert into spec values('Test_1', 1.0, 2.0); insert into spec values('Test_2', 2.0, 3.0); insert into spec values('Test_3', 3.0, 4.0); postgres=# select * from cable c WHERE c.test_item = test_item and test < (select upper_spec from spec where test_item = 'Test_1') and test > (select lower_spec from spec where test_item = 'Test_1'); id | test_item | test ----+-----------+------ 1 | Test_1 | 1.5 2 | Test_1 | 1.8 (2 行) postgres=# select * from cable c WHERE c.test_item = test_item and test < (select upper_spec from spec where test_item = 'Test_2') and test > (select lower_spec from spec where test_item = 'Test_2'); id | test_item | test ----+-----------+------ 1 | Test_3 | 2.5 ←'Test_3'なので引っ掛けたくない 2 | Test_2 | 2.5 3 | Test_3 | 2.5 ←'Test_3'なので引っ掛けたくない (3 行) postgres=# select * from cable c WHERE c.test_item = test_item and test < (select upper_spec from spec where test_item = 'Test_3') and test > (select lower_spec from spec where test_item = 'Test_3'); id | test_item | test ----+-----------+------ (0 行) 必要であれば補足します。 では、よろしくお願いします。

  • array値を別のテーブルへインサートしたい。

    phpとmysqlを見よう見まねでやっている 初心者です。 atableのチェックボックスよりPOSTした $sample_array(atable.indexの値が複数です。) をbtableへ移動したいと思い、以下の式を自分なりに 考えてみましたが上手くbtableへinsert されません。 atableの複数のindexは選ばれているようですが それをどうしたらbtableへ複数insertできるのか良くわかりません。 何が間違っているのか、atableからbtableへ複数insertできる式を 具体的に書いて頂くと大変助かります。 どうかご教授の程よろしくお願い致します。 $sample_array = $_POST['sample_array']; $where=""; if (isset($sample_array) and is_array($sample_array)) { $where .=" AND atable.index in ("; foreach ($sample_array as $key=>$val) { if($key>0) $where .=","; $where .="'" .mysql_real_escape_string($val) . "'"; } $where .=")"; } $sql= "select * from atable"; $sql .= " where 1"; $sql .= $where; $result = mysql_query( $sql ); while ( $row = mysql_fetch_array( $result ) ) { $sql = "insert into btable (a_no,b_no,c_no) values ('" . $row['no_a'] . "', '" . $row['no_b'] . "','" . $row['no_c'] . "')"; }

    • ベストアンサー
    • PHP
  • INSERT文とUPDATE文の使い分け

    いつもお世話になっております。 MYSQLで x_table ID SUBID  1  aaa 2 aaa 3 bbb 4 ccc というテーブルがあったとして、「IDが 1 かつ、SUB_IDが aaa」の項目が存在する場合はUPDATE、存在しない場合はINSERT、という形でSQLを使い分けたいと考えています。 現在は SELECT * FROM x_table WHERE ID=1 AND SUBID='aaa' というSQLでレコードの存在確認をし、その結果によりif文でUPDATE文とINSERT文を使い分けているのですが、レコードの存在確認とINSERTやUPDATEのSQLを一つにまとめる事が出来るようなやり方って無いでしょうか? 無さそうな場合は「無い」とだけでも答えていただけるとうれしいです。

    • ベストアンサー
    • PHP
  • 入力値と外部キーをINSERTするには

    追加したいカラムが3つあるとしまして、そのうち2つはフォームからの入力値で、残り1つは別テーブルのIDをWHEREで引っ張ってきてINSERTしたい場合、INSERT...VALUES()とINSERT...SELECT構文を組み合わせないとダメかと思うのですが、組み合わせるとうまくいきません。2つの文に分けるしかないのでしょうか? やりたいことは下の感じのSQLです。が、解釈してくれません。 INSERT INTO room(A, B, C) VALUES (1, 2, SELECT other_table.id FROM other_table WHERE other_table.id = 1");

    • ベストアンサー
    • MySQL
  • MySQLへのINSERT

    JAVA Connection とPreparedStatement でMysqlへINSERT分を実行したいのですが、エラー が出力されます。 SELECT分だと正常に実行されるのですが。。。。どうしてでしょうか? ps = conn.prepareStatement(\" INSERT INTO test00 (data1) values (1)\")

    • ベストアンサー
    • Java