3

私は SQL をあまり使いません。ほとんどの場合、CRUD 操作を行っています。ときどき、もう少し複雑なことがわかります。したがって、この質問は初心者の質問かもしれませんが、準備はできています。私はこれを何時間も理解しようとしてきましたが、役に立ちませんでした。

したがって、次のテーブル構造を想像してください。

> | ID | Col1 | Col2 | Col3 | .. | Col8 |

IDと計算列を選択したい。計算列の範囲は 0 ~ 8 で、クエリに一致した数が含まれています。また、特定の数の一致がある行のみが含まれるように結果セットを制限したいと考えています。

したがって、このサンプルデータから:

> | 1 | 'a' | 'b' | 1 | 2 |  
> | 2 | 'b' | 'c' | 1 | 2 |  
> | 3 | 'b' | 'c' | 4 | 5 |  
> | 4 | 'x' | 'x' | 9 | 9 |  

Col1 = 'a' OR Col2 = 'c' OR Col3 = 1 OR Col4 = 5 に対してクエリを実行し、計算結果が 1 を超える場合、結果セットは次のようになります。

> | ID | Cal |
> | 1  |  2  |
> | 2  |  2  |
> | 3  |  2  |

問題があれば、T-SQL と SQL Server 2005 を使用していますが、DB スキーマを変更できません。

また、ストアド プロシージャや一時テーブルを作成する必要がなく、1 つの自己完結型クエリとして保持することもお勧めします。

4

3 に答える 3

4

この回答は SQL 2005 で機能し、CTE を使用して派生テーブルを少しクリーンアップします。

WITH Matches AS
(
    SELECT ID, CASE WHEN Col1 = 'a' THEN 1 ELSE 0 END + 
                CASE WHEN Col2 = 'c' THEN 1 ELSE 0 END +
                CASE WHEN Col3 = 1  THEN 1 ELSE 0 END +
                CASE WHEN Col4 = 5  THEN 1 ELSE 0 END AS Result
    FROM Table1
    WHERE Col1 = 'a' OR Col2 = 'c' OR Col3 = 1 OR Col4 = 5 
)
SELECT ID, Result
FROM Matches
WHERE Result > 1 
于 2009-08-17T22:06:09.300 に答える
2

ブール比較が整数 1 または 0 を返すという事実を利用したソリューションを次に示します。

SELECT * FROM (
  SELECT ID, (Col1='a') + (Col2='c') + (Col3=1) + (Col4=5) AS calculated
  FROM MyTable
) q
WHERE calculated > 1; 

+よりも優先順位が高いため、ブール比較を括弧で囲む必要があることに注意してください=WHEREまた、通常、同じクエリの句で列エイリアスを使用できないため、すべてをサブクエリに入れる必要があります。

サブクエリで句を使用してその行を制限する必要があるように見えるかもしれませんがWHERE、とにかく完全なテーブル スキャンで終わる可能性が高いため、おそらく大きな勝利ではありません。一方、そのような制限によってサブクエリの結果の行数が大幅に減ると予想される場合は、それを行う価値があります。


Quassnoi のコメントに関して、ブール式を整数値として扱うことができない場合は、ブール条件を整数にマップする方法が必要です。例えば:

SELECT * FROM (
  SELECT ID, 
      CASE WHEN Col1='a' THEN 1 ELSE 0 END
    + CASE WHEN Col2='c' THEN 1 ELSE 0 END 
    + CASE WHEN Col3=1   THEN 1 ELSE 0 END
    + CASE WHEN Col4=5   THEN 1 ELSE 0 END AS calculated
  FROM MyTable
) q
WHERE calculated > 1;
于 2009-08-17T21:57:59.800 に答える
1

このクエリは、よりインデックスに適しています。

SELECT  id, SUM(match)
FROM    (
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col1 = 'a'
        UNION ALL
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col2 = 'c'
        UNION ALL
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col3 = 1
        UNION ALL
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col4 = 5
        ) q
GROUP BY
        id
HAVING  SUM(match) > 1

これは、検索しているすべての列が最初にインデックス付けされ、次にカーディナリティが高い (多くの異なる値)場合にのみ効率的です。

パフォーマンスの詳細については、私のブログのこの記事を参照してください。

于 2009-08-17T21:58:37.443 に答える