指定された結果セットを取得する 1 つの方法を次に示します。
SELECT d.rid AS `rid`
, SUM(n.eid<=>21) AS `21`
, SUM(n.eid<=>22) AS `22`
, SUM(n.eid<=>23) AS `23`
, SUM(n.eid<=>33) AS `33`
, SUM(n.eid<=>34) AS `34`
, SUM(n.eid<=>35) AS `35`
, SUM(n.eid<=>36) AS `36`
, SUM(n.eid<=>41) AS `41`
, SUM(n.eid<=>42) AS `42`
, d.vs AS `vs`
, d.isN AS `isN`
FROM ( SELECT %d AS rid, %d AS vs, 1 AS isN ) d
LEFT
JOIN notification n
ON n.rid = d.rid
AND n.vs = d.vs
AND n.isN = d.isN
GROUP
BY d.rid
, d.vs
, d.isN
注: 式は、またはより ANSI 標準の の(n.eid<=>21)
省略形です。これにより、0 または 1 が得られ、関数で集計できます。IF(n.eid=21,1,0)
CASE WHEN n.eid = 21 THEN 1 ELSE 0 END
SUM
次のいずれかの形式を使用して、同等の結果を得ることができます。
, SUM(n.eid<=>21) AS `21`
, COUNT(IF(n.eid=22,1,NULL)) AS `22`
, SUM(IF(n.eid=23,1,0)) AS `23`
, COUNT(CASE WHEN n.eid = 33 THEN 1 END) AS `33`
, SUM(CASE WHEN n.eid = 34 THEN 1 ELSE 0 END) AS `34`
ここで使用している「トリック」は、エイリアス化されたインライン ビューd
が 1 行を返すことが保証されていることです。次に、LEFT JOIN 演算子を使用して、「一致する」すべての行をnotification
テーブルから取得します。は、これらGROUP BY
すべての行を強制的に折りたたんで (集約して) 単一の行に戻します。そして、各行で条件付きテストを使用して、特定のカウントに含まれるかどうかを確認しています。「トリック」は、各行に対して 0 または 1 を返し、すべての 0 と1 でカウントを取得します。
注:COUNT(expr)
集計を使用するexpr
場合、行がカウントに含まれる場合は非 NULL を返し、行がカウントに含まれない場合は NULL を返します。
を使用する場合、行がカウントに含まれる場合は 1 を返し、そうでない場合は 0 を返しますSUM(expr)
。expr
(NULL ではなく 0 が必要なので、含まれる行がない場合に が「ゼロ カウント」(つまり、NULL ではなく 0) を返すことが保証さSUM(expr)
れます。(もちろん、IFNULL
関数を使用することもできます) NULL を 0 に置き換える方法ですが、この場合、その必要性を避けるのに十分簡単です。)
この「カウント」へのアプローチの利点の 1 つは、簡単に拡張して「組み合わせた」カウントを取得したり、行を複数の異なるカウントに含めたりできることです。例えば
, SUM(IF(n.eid IN (41,42),1,0)) AS `total_41_and_42`
eid=41 行と eid=42 行の合計数が得られます。(これはあまり良い例ではありません。クライアント側で 2 つのカウントを加算することで簡単に計算できるからです。しかし、より精巧なカウントを行っていて、単一の行を複数の行でカウントしたい場合、これは本当に利点になります。列 ...
, SUM(IF(n.eid=42,1,0)) AS eid_42
, SUM(IF(n.eid=42 AND foo=1,1,0) AS eid_42_foo_1
, SUM(IF(n.eid=42 AND foo=2,1,0)) AS eid_42_foo_2
テーブルを「1回通過」するだけで、これらすべての個別のカウントを取得できnotification
ます。これらのチェックを WHERE 句で行おうとすると、テーブルを複数回通過する必要が生じる可能性があります。