SQL的默认行

时间:2017-08-14 08:34:32

标签: sql oracle

DB - Oracle

create table customer_exercise(
customer_id number,
exercise_id number,
cnt number,
exercise_date date)

数据

1000    10  3   14-AUG-17
1001    20  6   14-AUG-17
1000    20  2   14-AUG-17 

当in子句中的条件不存在记录时,是否可以获得默认行?

select customer_id, exercise_id, sum(cnt)
from customer_exercise 
where customer_id in (1000, 1001, 1003)
  and exercise_id in (10, 20)
group by customer_id, exercise_id
order by sum(cnt)

以上查询的结果 -

1000    20  2
1000    10  3
1001    20  6

由于in子句中的customer-id可能没有某些exercise-id的记录,是否可以使用SQL获得如下所示的结果,其中sum为0?对于例如1001没有exercise-id = 10的记录,因此sum将为0。

1001    10  0
1003    10  0
1003    20  0
1000    20  2
1000    10  3
1001    20  6

2 个答案:

答案 0 :(得分:2)

您可以使用:

WITH cte AS (
  SELECT *
  FROM (SELECT 1000 AS customer_id FROM DUAL UNION 
        SELECT 1001 FROM DUAL UNION 
        SELECT 1003 FROM DUAL) s
  CROSS JOIN (SELECT 10 AS exercise_id FROM DUAL UNION 
              SELECT 20 FROM DUAL) s2
)
SELECT c.customer_id , c.exercise_id, COALESCE(sum(ce.cnt),0) AS s
FROM cte c
LEFT JOIN customer_exercise ce
  ON c.customer_id = ce.customer_id
 AND c.exercise_id = ce.exercise_id
GROUP BY c.customer_id, c.exercise_id
ORDER BY s;

<强> DB Fiddle Demo

当然,您有多种方法可以在cte:

中生成CROSS JOIN
  • 硬编码值
  • 临时表
  • 子查询

答案 1 :(得分:1)

您可以将in子句条件转换为集合(例如built-in collection type, handy for this sort of thing),将它们扩展为CTE中的关系数据,然后将它们交叉连接;并且左连接到真实表以查看匹配的内容:

with customer_cte (customer_id) as (
  select * from table(sys.odcinumberlist(1000, 1001, 1003))
),
exercise_cte (exercise_id) as (
  select * from table(sys.odcinumberlist(10, 20))
)
select c.customer_id, e.exercise_id, coalesce(sum(ce.cnt), 0) as total_cnt
from customer_cte c
cross join exercise_cte e
left join customer_exercise ce
on ce.customer_id = c.customer_id
and ce.exercise_id = e.exercise_id
group by c.customer_id, e.exercise_id
order by coalesce(sum(cnt), 0), customer_id, exercise_id
/

CUSTOMER_ID EXERCISE_ID  TOTAL_CNT
----------- ----------- ----------
       1001          10          0
       1003          10          0
       1003          20          0
       1000          20          2
       1000          10          3
       1001          20          6

6 rows selected. 

如果您已经拥有单独的customerexercise表,并且它们至少包含您要查找的所有ID,那么您可以直接使用这些表,并过滤它们而不是您的映射表:

select c.customer_id, e.exercise_id, coalesce(sum(ce.cnt), 0) as total_cnt
from customer c
cross join exercise e
left join customer_exercise ce
on ce.customer_id = c.customer_id
and ce.exercise_id = e.exercise_id
where c.customer_id in (1000, 1001, 1003)
and e.exercise_id in (10, 20)
group by c.customer_id, e.exercise_id
order by coalesce(sum(cnt), 0), customer_id, exercise_id

您不会以这种方式获取customerexercise表中不存在的任何ID的默认行,但这可能不是问题。