オリジナルを基に構築
元のクエリは、問題のある行を除外するために正しい方向に進んでいました。 >
がありました =
の代わりに 。数えるためのトリッキーなステップがありませんでした。
SELECT count(*) AS ct
FROM (
SELECT 1
FROM compatibility c
WHERE rating_id = 1
AND NOT EXISTS (
SELECT 1
FROM compatibility c2
WHERE c2.rating_id > 1
AND (c2.attr1_id = c.attr1_id AND c2.attr2_id = c.attr2_id OR
c2.attr1_id = c.attr2_id AND c2.attr2_id = c.attr1_id))
GROUP BY least(attr1_id, attr2_id), greatest(attr1_id, attr2_id)
) sub;
短い
おそらくもっと速いでしょう。
SELECT count(*) AS ct
FROM (
SELECT 1 -- selecting more columns for count only would be a waste
FROM compatibility
GROUP BY least(attr1_id, attr2_id), greatest(attr1_id, attr2_id)
HAVING every(rating_id = 1)
) sub;
@Clodoaldoのクエリ
に似ています または、この以前の回答と詳細な説明
。every(rating_id = 1)
not bool_or(rating_id > 1)
よりも単純です 、ただし、rating < 1
も除外します -これはおそらくあなたのケースには問題ありません(またはそれ以上です)。
MySQL 現在、(標準SQL!)every()
を実装していません。 。 rating_id > 1
のみを削除したいので 、この単純な式は要件により厳密に適合し、両方のRDBMSで機能します:
HAVING max(rating_id) = 1
最短
count(*)
を使用 ウィンドウ集計関数として、サブクエリなし。
SELECT count(*) OVER () AS ct
FROM compatibility
GROUP BY least(attr1_id, attr2_id), greatest(attr1_id, attr2_id)
HAVING max(rating_id) = 1
LIMIT 1;
ウィンドウ関数は後に適用されます 集約ステップ。これに基づいて、2つを取得します。 単一のクエリレベルで実行される集計ステップ:
- 同等の
(atr1_id, atr2_id)
を折ります 、発散するrating_id
の行を除く 存在します。 - セット全体でウィンドウ関数を使用して残りの行をカウントします。
LIMIT 1
単一の行を取得します(すべての行は同一になります)。
MySQLにはウィンドウ関数がありません。 Postgres のみ。
最短、必ずしも最速とは限りません。
SQLフィドル。 (pg9.3は現在オフラインであるためpg9.2上)