質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

6回答

5720閲覧

PostgreSQL in句でAND条件にするには

doumeishi

総合スコア52

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2016/08/06 16:45

編集2016/08/06 18:17

menu_code | ingredient_code
-----------+-----------------
100 | abc
101 | efg
102 | hij
100 | xxx
100 | zzz

上記のようなテーブルがあったとします。
この時、 ingredient_code = 'abc' and ingredient_code ='xxx'
の場合はmenu_code == 100がヒットし、
ingredient_code = 'abc' and ingredient_code = 'xxx' and ingredient_code = 'yyy' の場合は、ヒットしないようなSQL文を書きたいのですが、exists演算子を使わないで
書きたいです(というか、副問い合わせはしようしないで(レスポンスが遅くなるので))が、
方法があるのかすらわかりません。
どなたか、教えていただけないでしょうか。

KotoriMaturiさんへ

返答ありがとうございます。
そうです。ingredient_codeの条件が一つでも外れている場合は
ヒットしない、という動作にしたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Panzer_vor

2016/08/06 17:12

今の例示だとどちらのケースも1レコードが取れないと(1レコード内1カラムに複数値を持つことがあり得ないため)、これはORに読み替えればいいのでしょうか? そのOR条件のいずれか1件でも条件を満たさなければレコードを取得しないの認識で合ってますでしょうか?(複数コード取れる時も駄目?)
guest

回答6

0

bool_orを使ってみました :-)

sql

1with t(menu_code,ingredient_code) as( 2values(100,'abc'), 3 (100,'xxx'), 4 (100,'zzz'), 5 (101,'efg'), 6 (102,'hij')) 7select menu_code 8 from t 9group by menu_code 10having bool_or(ingredient_code = 'abc') 11 and bool_or(ingredient_code = 'xxx'); 12 13| menu_code | 14|-----------| 15| 100 | 16

投稿2016/08/13 05:37

AketiJyuuzou

総合スコア1147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

以下のSQLはいかがでしょうか。
同じような記述が続くので好みは分かれると思いますが、できるだけ簡単で確実な方法を考えてみました。

SQL

1select menu_code from table001 where ingredient_code = 'abc' 2intersect 3select menu_code from table001 where ingredient_code = 'xxx' 4intersect 5select menu_code from table001 where ingredient_code = 'zzz' 6;

ちなみに、menu_code列以外も取得する場合は、以下で実現できます。

SQL

1select * from table001 2where menu_code in( 3 select menu_code from table001 where ingredient_code = 'abc' 4 intersect 5 select menu_code from table001 where ingredient_code = 'xxx' 6 intersect 7 select menu_code from table001 where ingredient_code = 'zzz' 8);

追記:
以下の通り、動作確認をしてみました。PostgreSQLのバージョンは9.5.3です。
(長くなってしまい申し訳ございません。)

SQL

1--テスト用テーブル・データ作成 2drop table if exists table001; 3create table table001( 4 menu_code varchar(3), 5 ingredient_code varchar(3), 6 other_key varchar(3), 7 note text, 8 --同一のmenu_code,ingredient_codeの組み合わせが複数行存在する場合も想定 9 primary key(menu_code,ingredient_code,other_key) 10); 11insert into table001 values('100','abc','A','OK'); 12insert into table001 values('100','xxx','B','OK'); 13insert into table001 values('100','zzz','C','OK'); 14insert into table001 values('101','efg','A','NG'); 15insert into table001 values('102','hij','A','NG'); 16insert into table001 values('103','abc','A','NG'); 17insert into table001 values('104','abc','A','NG'); 18insert into table001 values('104','xxx','B','NG'); 19insert into table001 values('105','abc','A','NG'); 20insert into table001 values('105','abc','B','NG'); 21insert into table001 values('105','zzz','C','NG'); 22insert into table001 values('106','abc','A','OK'); 23insert into table001 values('106','xxx','B','OK'); 24insert into table001 values('106','zzz','C','OK'); 25insert into table001 values('106','zzz','D','OK'); 26insert into table001 values('107','abc','A','OK'); 27insert into table001 values('107','xxx','B','OK'); 28insert into table001 values('107','zzz','C','OK'); 29insert into table001 values('107','efg','D','OK'); 30 31--テスト1(menu_codeが1行以上該当する場合) 32select * from table001 33where menu_code in( 34 select menu_code from table001 where ingredient_code = 'abc' 35 intersect 36 select menu_code from table001 where ingredient_code = 'xxx' 37 intersect 38 select menu_code from table001 where ingredient_code = 'zzz' 39); 40 41--結果 42-- menu_code | ingredient_code | other_key | note 43-------------+-----------------+-----------+------ 44-- 100 | abc | A | OK 45-- 100 | xxx | B | OK 46-- 100 | zzz | C | OK 47-- 106 | abc | A | OK 48-- 106 | xxx | B | OK 49-- 106 | zzz | C | OK 50-- 106 | zzz | D | OK 51-- 107 | abc | A | OK 52-- 107 | xxx | B | OK 53-- 107 | zzz | C | OK 54-- 107 | efg | D | OK 55--(11 行) 56 57--テスト2(menu_codeが1行も該当しない場合) 58select * from table001 59where menu_code in( 60 select menu_code from table001 where ingredient_code = 'abc' 61 intersect 62 select menu_code from table001 where ingredient_code = 'xxx' 63 intersect 64 select menu_code from table001 where ingredient_code = 'fff' 65); 66 67--結果 68-- menu_code | ingredient_code | other_key | note 69-------------+-----------------+-----------+------ 70--(0 行)

投稿2016/08/11 15:56

編集2016/08/12 03:09
minr

総合スコア37

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Postgreはよくわからないんですが、普通にSQLで書けば
項目2つ

SQL

1select menu_code 2from tbl where ingredient_code in ('abc','xxx') 3group by menu_code 4having count(distinct ingredient_code)=2;

項目3つ

SQL

1select menu_code 2from tbl where ingredient_code in ('abc','xxx','yyy') 3group by menu_code 4having count(distinct ingredient_code)=3;

としませんか?
項目数を自動で提案したい場合はなんらかの別テーブルを用意するといいでしょう

投稿2016/08/08 00:50

yambejp

総合スコア114769

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

JOINはサブクエリでは無いと言う事で。。

SQL

1select A.menu_code from table A 2join table B on A.menu_code=B.menu_code and A.ingredient_code='abc' and B.ingredient_code='xxx' 3left join table C on A.menu_code=C.menu_code and A.ingredient_code='abc' and C.ingredient_code='yyy' 4where C.ingredient_code is NULL;

投稿2016/08/07 06:57

A.Ichi

総合スコア4070

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

サブクエリが一概にパフォーマンスを悪化させるって訳でもないのですが、
サブクエリを使わないという制約を課すなら以下のような感じでどうでしょう?

もう少し考えてみますが、一応下記で大丈夫です。
レコードが取れない条件を入力された際の対応がどうしても思いつかない・・・

SQL

1SELECT 2 MAX(menu_code) AS menu_code 3FROM 4 TABLE 5WHERE 6 ingredient_code IN ('abc', 'xxx', 'yyy') 7HAVING 8 MAX(menu_code) = MIN(menu_code) 9AND COUNT(*) >= 3 -- 条件の数(※ただし「aaa」が2回など同一条件が複数指定されるとNG)

ただ集約関数使いまくるのとHAVING句を使うからむしろパフォーマンスが悪いかも・・・

・追記
禁を犯してFROM句でサブクエリを用いてみました。
すごく苦しいコード・・・orz

SQL

1SELECT 2 MAX(menu_code) AS menu_code 3FROM 4 ( 5 SELECT 6 'abc' AS cond 7 UNION ALL 8 SELECT 9 'xxx' 10 UNION ALL 11 SELECT 12 'yyy' 13 ) T1 14 LEFT JOIN TABLE T2 15 ON T2.ingredient_code = T1.cond 16HAVING 17 MAX(menu_code) = MIN(menu_code) -- 指摘を受け修正 18AND COUNT(*) = COUNT(menu_code)

###補足
ちなみにFROM句におけるサブクエリを結合する方法を用いると、
WHERE句でのサブクエリ(相関副問い合わせ)と比べ高速に動作する機会は多いと思われます。

投稿2016/08/06 18:30

編集2016/08/08 10:16
Panzer_vor

総合スコア1636

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

doumeishi

2016/08/07 00:51

Kotoriさん、hirohiroさん ありがとうございます! Kotoriさんの案の方がすっきりしているように見えるので Kotoriさんを、VAにさせていただきます。 Kotoriさんの最初の案を実行したところ、ちゃんと動きました 実際に解決したいコードは、ingredient_codeの指定は重複 しないので、この案でレスポンスを測ってみて、問題なければ 使います。 お二方とも、本当にありがとうございました。
kutsulog

2016/08/08 05:51

横槍な上に蛇足ですが 2番目のSQLのほうは こっちのHAVINGにも MAX(menu_code) = MIN(menu_code) をいれないとyyyがefgになったときにマッチしてしまいそう... SELECT~UNION ALL~の部分は PostgreSQLなら(SELECT UNNEST(ARRAY['abc', 'xyz', 'yyy']) AS cond) T1でいけるかと
Panzer_vor

2016/08/08 10:14

> kutsulogさん ご指摘ありがとうございます。完全に条件漏れですね、チョンボしてました…。コードは訂正させていただきます。 またARRAYとUNNESTなるものがあるのですね。 当方ベンダ拡張部分については知識不足なので、勉強になります。
guest

0

当初投稿したものが間違っていたため再考したのですが、ましなコードは浮かびませんでした。
ごり押し気味な回答になっています。すみません

サブクエリを使わないとなると、こんな感じでしょうか?
(動作確認してません)

SQL

1SELECT menu_code 2FROM table 3GROUP BY menu_code 4HAVING SUM( 5 CASE 6 WHEN ingredient_code = 'abc' OR ingredient_code ='xxx' 7 THEN 1 ELSE 0 8 END 9) >= 2 /* この2は比較条件の数 */

または

SQL

1SELECT menu_code 2FROM table 3GROUP BY menu_code 4HAVING SUM(CASE WHEN ingredient_code = 'abc' THEN 1 ELSE 0 END) = 1 5AND SUM(CASE WHEN ingredient_code = 'xxx' THEN 1 ELSE 0 END) = 1 6

テーブル設計やデータ件数とその偏りに大きく影響を受けると思うので、サブクエリ利用より常に早いか?と問われると怪しいです(むしろサブクエリ利用のほうが早いケースが多いかも)

投稿2016/08/06 18:18

編集2016/08/07 04:33
hirohiro

総合スコア2068

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

doumeishi

2016/08/06 18:21

返答ありがとうございます。 >ingredient_code = 'abc' OR ingredient_code ='xxx' この部分を、ANDにしたいのです・・・
hirohiro

2016/08/06 18:40 編集

もう一度よくコードを確認してほしいのですが、 menu_codeでグループ化し、それぞれのmenu_codeに対して、ingredient_code = 'abc'かingredient_code ='xxx' の行の数を数えます (これがsum。例示のデータなら合計値まで出すと次のようになっているはず) menu_code sum 100     2 101     0 102     0 そして合計が1以上のmenu_codeのみを選択しています。 結果的に以下の結果が得られていると思います ---- ingredient_code = 'abc' and ingredient_code ='xxx' の場合はmenu_code == 100がヒットし、 ingredient_code = 'abc' and ingredient_code = 'xxx' and ingredient_code = 'yyy' の場合は、ヒットしない
hirohiro

2016/08/06 18:43 編集

コメント書いていて気がつきました!ダメですね。再考します (sum()>=2 でよければ動きますね。2は条件の数)
hirohiro

2016/08/06 18:55

間違っていた上に、修正しようとしたものが(一応動作はすると思うのですが...)不恰好なものになってしまってすみません。失礼しました。難しいですね...
Panzer_vor

2016/08/06 20:06

> hirohiroさん 横から失礼いたします。 1つ目のサンプルコードのCASE式ですが、恐らく戻し値が逆になっています。 後、僕もコードを考えてみましたが結局は同じような形に収まりました^^; レコードが取れない際の扱いが難しいですよね・・・
hirohiro

2016/08/07 04:32

KotoriMaturi さん ありがとうございます あ、ほんとですね。修正しておきます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問