SQL - 根据值过滤掉结果集

时间:2017-08-26 06:03:03

标签: sql oracle

DB - Oracle

省略所有约束。

 create table customer (cid number(10), cname varchar(50));

 create table exercise (eid number(10), ecode varchar(2));

 -- mapping table
 create table customer_exercise (cid number(10), eid number(10), cnt number(10))  

数据

Customer table

100    e1
200    e2
300    e3
400    e4

Exercise table

1      c1
2      c2
3      c3
4      c4

Customer_Exercise

cid  eid count
100   1  20
200   2  50
100   2  30
300   4  10 

SQL:

SELECT   c.cid
        ,e.eid
        ,COALESCE(SUM(ce.cnt), 0) AS total_cnt
    FROM customer c
         CROSS JOIN exercise e
         LEFT JOIN customer_exercise ce
            ON     ce.cid = c.cid
               AND ce.eid = e.eid
   WHERE     c.cid IN (100, 200, 300)
         AND e.eid IN (1, 2)
GROUP BY c.cid, e.eid

结果:

cid   eid  total_cnt

100    1       20
100    2       30
200    1       0
200    2       50
300    1       0
300    2       0

有没有办法过滤掉in子句中没有任何运动ID条目的客户?

例如客户300没有运动ID 1或2的任何行。该客户不应该在结果中。客户200没有练习1的行,但有练习2的数据,所以他应该在练习1中显示为0。

如何获得如下的结果集?

预期结果:

cid   eid    total_cnt

100    1         20
100    2         30
200    1         0
200    2         50

2 个答案:

答案 0 :(得分:0)

您可以使用inner join代替外部联接,但删除eid上的联接条件,将其移动到CASE WHEN子句中的select表达式中。这样你就不得不重复in (1, 2)条件:

SELECT     c.cid
         , e.eid
         , COALESCE(SUM(CASE e.eid WHEN ce.eid THEN ce.cnt ELSE 0 END), 0) AS total_cnt
FROM       (
                SELECT DISTINCT eid
                FROM   exercise 
                WHERE  eid IN (1, 2)) e
CROSS JOIN customer c
INNER JOIN customer_exercise ce
        ON ce.cid = c.cid
       AND ce.eid IN (1, 2)
WHERE      c.cid IN (100, 200, 300)
GROUP BY   c.cid
         , e.eid
ORDER BY   1, 2

rextester.com上看到它。

输出:

cid | eid  | total_cnt
----+------+----------
100 |  1   |     20
100 |  2   |     30
200 |  1   |      0
200 |  2   |     50

替代:

SELECT     c.cid
         , e.eid
         , COALESCE(SUM(CASE e.eid WHEN ce.eid THEN ce.cnt ELSE 0 END), 0) AS total_cnt
FROM       exercise e
CROSS JOIN customer c
INNER JOIN customer_exercise ce
        ON ce.cid = c.cid
       AND ce.eid IN (1, 2)
WHERE      c.cid IN (100, 200, 300)
       AND e.eid IN (1, 2)
GROUP BY   c.cid
         , e.eid
ORDER BY   1, 2

答案 1 :(得分:0)

正确的方法:

with t as (
  SELECT   c.cid
          ,e.eid
          ,COALESCE(SUM(ce.cnt), 0) AS total_cnt
                ,count(max(ce.cnt))over(partition by c.cid) ce_cnt
      FROM customer c
           CROSS JOIN exercise e
           LEFT JOIN customer_exercise ce
              ON     ce.cid = c.cid
                 AND ce.eid = e.eid
     WHERE     c.cid IN (100, 200, 300)
           AND e.eid IN (1, 2)
  GROUP BY c.cid, e.eid
  )
select t.cid,t.eid,t.total_cnt from t where t.ce_cnt >0

对不起,我有一点点错误,(没有max()代码给ORA-00979:不是GROUP BY表达式)