さまざまな単語とドキュメント内の場所を参照するMySQLデータベーステーブルがあります。すべての単語を含むドキュメントのIDを返したいのですが。
以下はテーブルの例です。
docid wordid
1 4
2 4
1 2
1 5
では、WORDIDが4、2、5の単語を誰かがデータベースに問い合わせたとしましょう。
私の誤ったSQL SELECTステートメントは次のようになります。
Select docid from table where wordid = 4 and wordid = 2 and wordid = 5
これは私に0の結果を与えています。
私 見たことがある 他の場所でwhere in
句が提案されています:
私が正しく理解していれば、これはOR句を記述する別の方法です。私はこれを試しました:
select docid from table where wordid in (4,2,5)
しかし、これは私にすべての結果を与えています。 docid 2は他の単語を含まないため、除外する必要があります。私はdocid 1を取得することを期待しています。
ただし、where in
句が正しくないのは、dbの経験がほとんどないためです。
すべての単語を含むdocidを返すにはどうすればよいですか?
同様に、私のwhere句はFORループで動的に生成されます。クエリは、1語または2語のように単純な場合もあれば、10語または12語の場合もあります。速度を考慮したクエリ構造を探しています。詳しい情報が必要な場合はお知らせください。
参考までに、私はこのコードをPHP/MYSQLに変換しようとしていますが、ここでのsqlステートメントまたは同等のMYSQLを理解していません。
これはリレーショナル除算の問題であり、SOで問題があり、このクエリを書く方法はたくさんあります。 、およびPostgreSQLのパフォーマンス分析:SQL結果を多対多の関係でフィルタリングする方法
CTE、EXCEPT
、INTERSECT
など、MySQLに欠けている機能を持つ回答のコードをそこに恥知らずにコピーしてコードを削除/変更する方法は次のとおりです。
仮定:
factors
と呼ばれます(wordid, docid)
にはUNIQUE
制約がありますdocuments
テーブルとwords
テーブルがあります。書きやすく、中程度の効率:
-- Query 1 -- by Martin
SELECT d.docid, d.docname
FROM document d
JOIN factors f USING (docid)
WHERE f.wordid IN (2, 4, 5)
GROUP BY d.docid
HAVING COUNT(*) = 3 ; -- number of words
書きやすく、中程度の効率:
-- Query 2 -- by Erwin
SELECT d.docid, d.docname
FROM documents d
JOIN (
SELECT docid
FROM factors
WHERE wordid IN (2, 4, 5)
GROUP BY docid
HAVING COUNT(*) = 3
) f USING (docid) ;
書くのがより複雑で、Postgresの効率は非常に良い-おそらくMySQLではお粗末だ:
-- Query 4 -- by Derek
SELECT d.docid, d.docname
FROM documents d
WHERE d.docid IN (SELECT docid FROM factors WHERE wordid = 2)
AND d.docid IN (SELECT docid FROM factors WHERE wordid = 4);
AND d.docid IN (SELECT docid FROM factors WHERE wordid = 5);
書くのがより複雑で、Postgresでは非常に優れた効率-そしておそらくMySQLでも同じです:
-- Query 5 -- by Erwin
SELECT d.docid, d.docname
FROM documents d
WHERE EXISTS (SELECT * FROM factors
WHERE docid = d.docid AND wordid = 2)
AND EXISTS (SELECT * FROM factors
WHERE docid = d.docid AND wordid = 4)
AND EXISTS (SELECT * FROM factors
WHERE docid = d.docid AND wordid = 5) ;
書くのがより複雑で、Postgresでは非常に優れた効率-そしておそらくMySQLでも同じです:
-- Query 6 -- by Sean
SELECT d.docid, d.docname
FROM documents d
JOIN factors x ON d.docid = x.docid
JOIN factors y ON d.docid = y.docid
JOIN factors z ON d.docid = z.docid
WHERE x.wordid = 2
AND y.wordid = 4
AND z.wordid = 5 ;
書きやすく、words
の任意のセットに拡張できますが、JOIN
およびEXISTS
ソリューションほど効率的ではありません。
-- Query 7 -- by ypercube
SELECT d.docid, d.docname
FROM documents d
WHERE NOT EXISTS (
SELECT *
FROM words AS w
WHERE w.wordid IN (2, 4, 5)
AND NOT EXISTS (
SELECT *
FROM factors AS f
WHERE f.docid = d.docid
AND f.wordid = w.wordid
)
);
書きやすく、効率が悪い:
-- Query 8 -- by ypercube
SELECT d.docid, d.docname
FROM documents d
WHERE NOT EXISTS (
SELECT *
FROM (
SELECT 2 AS wordid UNION ALL
SELECT 4 UNION ALL
SELECT 5
) AS w
WHERE NOT EXISTS (
SELECT *
FROM factors AS f
WHERE f.docid = d.docid
AND f.wordid = w.wordid
)
);
それらをテストして楽しんでください:)