web-dev-qa-db-ja.com

1つの列に2つ以上の値が含まれている必要があるテーブルからアイテムを選択するにはどうすればよいですか?

さまざまな単語とドキュメント内の場所を参照する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を理解していません。

http://my.safaribooksonline.com/book/web-development/9780596529321/4dot-searching-and-ranking/querying

6
user658182

これはリレーショナル除算の問題であり、SOで問題があり、このクエリを書く方法はたくさんあります。 、およびPostgreSQLのパフォーマンス分析:SQL結果を多対多の関係でフィルタリングする方法

CTE、EXCEPTINTERSECTなど、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 
      )
   );

それらをテストして楽しんでください:)

9
ypercubeᵀᴹ