相関関係に依存する計算列を含む SELECT
-
18-09-2019 - |
質問
私は 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 つの自己完結型クエリとして保持したいと考えています。
解決
この答えは少し派生テーブルをクリーンアップするCTEを使用して、SQL 2005で動作します。
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
他のヒント
ここでは、ブール比較は、整数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;
このクエリはインデックスに適しています。
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
これは次の場合にのみ効果的です。 全て 検索している列は、第一にインデックスが付けられており、第二に、高いカーディナリティ (多数の個別の値) を持っています。
パフォーマンスの詳細については、私のブログのこの記事を参照してください。