3

XnViews データベースに対して使用するために、「単純化された」SQL クエリを機能する SQLite クエリに変換しようとしています。

例は「(cat_10 and cat_12) and (cat_5 or cat_7)」です。

これは、フィールド "if" (fileID) および "ic" (categoryID) を持つテーブル "t3" に対して使用する必要があります。

エントリは次のようになります。

if, ic
7, 10
7, 12
7, 4
9, 10
9, 12
9, 5
10, 10
10, 12
10, 7

上記の単純化されたクエリは、ファイル 9 と 10 のみを選択する必要があります。これは、7 には必要なカテゴリ 10 と 12 がありますが、5 と 7 のどちらも含まれていないためです。

実際の問題は、2 つのカテゴリ間の AND を単純に機能させるのにすでに数時間かかったので、その地獄のようなクエリ ステートメントを作成することです。

SELECT if FROM t3 WHERE ic IN (10, 12) GROUP BY if HAVING count(if) = 2

これにより、カテゴリ 10 と 12 を含むすべてのファイル ID が得られますが、それを残りの "および (cat_5 または cat_7)" とどのように組み合わせる必要があるかわかりません。

これらの単純化された sql ステートメント (html と js で作成された click-it-together-builder によって作成された) を計画したとき、単純に "cat_5" を "t3.ic = 5" に置き換え、残りはそのままにすることを計画していました。

もちろん、 where がエントリ全体をチェックするように機能しないとは予想していませんでした。ic = 5 AND ic = 7 はあり得ません。

したがって、( x と y ) のペアに限定されない可能性があることを念頭に置いて、これらの単純なクエリを実際に機能するクエリに変換する方法を誰かが知っているかどうか疑問に思っています。

編集:私が与えた例を実行する方法を考え出しました。少なくとも:

SELECT if FROM t3 WHERE ic IN (10, 12) GROUP BY if HAVING count(if) = 2
INTERSECT 
SELECT if FROM t3 WHERE ic IN (5, 7) GROUP BY if

しかし、現在の主な問題は ( ) を正しい順序で解決することです。

編集 2: group_concat() を使用してカテゴリを 1 つのフィールドにグループ化しようとしていると思いますそしてそれはうまくいくはずです。「すべき」を強調する。

4

4 に答える 4

2

元のクエリは意図したことを実行しません。sが再び10と10になっているが、12がまったくないWHERE ic IN (10, 12) GROUP BY if HAVING count(if) = 2場合でも、正しい結果が得られます。icこれは、あなたが望むもののテキストによる説明に反します。これは、12と10の結果をフェッチするための内部クエリが必要な場所です。以下に投稿したフィドルリンクで、クエリが失敗するかどうかをテストできます。

少しトリッキーですが、これは私がそれを簡単に解釈する方法です。

SELECT DISTINCT ifc
FROM   t3
WHERE  ifc IN (
               SELECT   ifc
               FROM     t3 
               WHERE    ic = 10  
               GROUP BY ifc
               HAVING   COUNT(*) > 0             

               INTERSECT

               SELECT   ifc
               FROM     t3 
               WHERE    ic = 12
               GROUP BY ifc
               HAVING   COUNT(*) > 0
              )            
AND ic IN (5, 7)

フィドルを試してください

私は最適化を持ち込みませんでした、あなたはあなたのものを試すかもしれません。フィドルリンクはPostgresのものですが、これは機能するはずです(私のブラウザでSQLiteが機能しませんでした:()

編集: CL。HAVING本当の内部クエリに句を含める必要がないことについての興味深いことを指摘します。私は、最適化を考えずに物事を明確にすることを目的として、SQL用語でOPの要件を解釈していました。

見栄えの良いクエリは次のとおりです。

SELECT DISTINCT ifc
FROM   t3
WHERE  ifc IN (
               SELECT   ifc
               FROM     t3 
               WHERE    ic = 10            

               INTERSECT

               SELECT   ifc
               FROM     t3 
               WHERE    ic = 12
              )            
AND ic IN (5, 7)
于 2012-11-06T06:45:25.757 に答える
0

意外と当初の予定通りに動作しました。

SELECT Folders.Pathname || Images.Filename AS File FROM Images
JOIN Folders ON Images.FolderID = Folders.FolderID
LEFT JOIN (
    SELECT f, Cats, t4.if AS Tagged FROM t2
    JOIN (
        SELECT if, ' ' || group_concat(ic,' ') || ' ' AS Cats FROM t3 GROUP BY if
    ) st3 ON t2.i = st3.if
    LEFT JOIN t4 ON t2.i = t4.if
) st2 ON File = st2.f
$selectWhereImage $sqlqry
ORDER BY ModifiedDate $order LIMIT $offset, $limit

私はこれがクエリの1つの地獄であることを知っていますが、それは私が探しているすべてのもの(カテゴリID、タグ付きかどうか、評価、色)を日付で並べ替えることができ、結果として完全なファイルパスを組み合わせます。

それは恐らく恐ろしい方法ですが、ブラケットや演算子に必要な残りの部分をそのままにして、「cat_5」のようなプレースホルダーを単純に置き換えることができるより良い方法を誰かが見つけた場合、私はすべての耳です:D

ああ、$ selectWhereImageには、ファイルがimageformatで終わるように制限するより長いWHEREが含まれています。$ sqlqryは上からのrefittetであり、cat_5は、の左右にスペースが追加されているため、猫のようになります。猫「1」は「10」にないので、「10」に「1」が見つからなくても、任意の数に一致させることができます:D

于 2012-11-07T17:42:50.727 に答える
0

より単純でより速いと私が信じるハック的なアプローチは

SELECT DISTINCT ifc
FROM   t3
WHERE  ifc IN (
               SELECT   ifc
               FROM     t3 
               WHERE    ic = 10
              ) 
   AND ifc IN (
               SELECT   ifc
               FROM     t3 
               WHERE    ic = 12
              )               
AND ic IN (5, 7)
于 2012-11-08T20:15:07.607 に答える
0

交差を使用する必要がある場合は、上部のクエリを変更する必要がありますが、これは間違っています。everyifに 10 と 12 があることを確認する必要があるicため、そのための 2 つの個別のクエリなしでは逃げることはできません。何かのようなもの:

SELECT ifc
FROM   t3
WHERE  ifc IN (
               SELECT   ifc
               FROM     t3 
               WHERE    ic = 10
              ) 
   AND ifc IN (
               SELECT   ifc
               FROM     t3 
               WHERE    ic = 12
              )

INTERSECT

SELECT ifc FROM t3 WHERE ic IN (5, 7)

はここINTERSECTでグループを処理するので、明示的に追加する必要はありませんが、これは他のクエリほど効率的ではありません。サブクエリを回避する必要がある場合は、次を使用できますJOIN

SELECT DISTINCT t.ifc
FROM   t3 AS t
JOIN   t3 AS v ON v.ifc = t.ifc
JOIN   t3 AS p ON p.ifc = t.ifc
WHERE  v.ic = 10 AND p.ic = 12 AND t.ic IN (5, 7)

INTERSECT2 つ目は、 MySQL のように知らないデータベースでも機能するという利点があります。

于 2012-11-08T20:31:18.053 に答える