0

私は次の表を持っています

id  rid     eId     vs  isN
24  3   22  2   1
25  3   21  2   1
26  60  21  2   1
27  60  21  2   1
28  60  21  2   1
29  60  21  2   1
30  60  21  2   1
31  60  21  2   1
32  81  21  2   1
35  60  22  2   1
36  81  22  2   1
37  0   22  2   1
38  60  22  2   1
39  81  22  2   1
40  0   22  2   1
41  60  22  2   1
42  81  22  2   1
43  3   22  2   1

私は8eIdつの異なる数字を持っていますが、この8つの異なる eid を数えたいと思っています.8つの値を含む配列を取得したいのですが、キーは8つの異なる名前でなければなりません。"vs" は、カウントするたびに 3 つの異なる数字です。"rid" = %d および "vs" = %d (特定のrid と特定の vs)

SELECT count(*) as count FROM notification 
WHERE rid = 60 AND vs = 2 AND isN = 1 GROUP BY eId 

rid=>60,21=>6,22=>3,vs=>2,isN=>1  

(これは私が上記で得たものです)

rid=>60,21=>6,22=>3,23=>0,33=>0,34=>0,35=>0,36=>0,41=>0,42=>0,vs=>2,isN=>1

(これは私が欲しいものです。もちろん、この数字はeIdに存在しなかったので、ゼロとして返したいです)

4

3 に答える 3

1

指定された結果セットを取得する 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 ENDSUM

次のいずれかの形式を使用して、同等の結果を得ることができます。

     , 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 句で行おうとすると、テーブルを複数回通過する必要が生じる可能性があります。

于 2013-02-11T17:05:18.377 に答える
1

必要なのは、出力するすべての値を含むドライバー テーブルです。次に、これを実際のデータに左外部結合できます。

SELECT count(notification.eid) as count
FROM (select distinct eid
      from notification
     ) drivers left outer join
     (select *
      from notification
      WHERE rid = %d AND vs = %d AND isN = 1
     ) n
     on driver.eid = notification.eid
GROUP BY driver.eId

eid出力の最終的な順序に依存している場合を除き、句にthe も含める必要selectがあります (MySQL は、他のデータベースとは異なり、 a の後の結果の順序を保証しgroup byます)。

于 2013-02-11T16:31:14.893 に答える