我正在尝试根据现有的视图数据创建视图,但是如果每个零件/日期组合中不存在某些行,则要创建这些行。我有下面的查询,该查询显示了当前针对特定s_date/part_no
组合的所有内容:
SELECT
s_date,
part_no,
issue_group,
s_level,
qty_filled
FROM
current_view
WHERE
part_no = 'xxxxx'
AND s_date IN (
'201802',
'201803'
)
ORDER BY
s_date,
part_no,
issue_group,
DECODE(s_level, '80', 1, '100', 2, 'Late', 3)
哪个产生以下内容:
我知道如何用这些数据创建视图,这很容易。但是我需要的是每个issue_group and s_level
组合的一行,如果是已创建的行,则将0用作qty_filled
。
每个part_no / s_date
组合都应该有6行
- issue_group = '1' / s_level = '80'
- issue_group = '1' / s_level = '100'
- issue_group = '1' / s_level = 'Late'
- issue_group = '2/3 ' / s_level = '80'
- issue_group = '2/3 ' / s_level = '100'
- issue_group = '2/3 ' / s_level = 'Late'
因此,如果当前s_date/part_no
已存在上述组合之一,则显然会从当前视图中获取qty_filled
信息。如果不是,则创建一个新行,并qty_filled = 0
。所以我试图让它看起来像这样:
我只显示了一部分,有几个日期,只是为了阐明要点。该表中有超过10k的零件,对于6个issue_group / s_level组合,每个零件/日期组合都不会超过1个。
答案 0 :(得分:0)
一种解决方案可能是使用(固定)值列表之间的笛卡尔积生成所有预期行的笛卡尔积,然后用LEFT JOIN
current_view
对其进行笛卡尔积。
以下查询保证您将获得每个给定s_date/part_no/issue_group/s_level
元组的记录。如果current_view
中没有记录匹配,查询将显示0
数量。
SELECT
sd.s_date,
pn.part_no,
ig.issue_group,
sl.s_level,
COALESCE(cv.qty_filled, 0) qty_filled
FROM
(SELECT '201802' AS s_date UNION SELECT '201803') AS sd
CROSS JOIN (SELECT 'xxxxx' AS part_no) AS pn
CROSS JOIN (SELECT '1' AS issue_group UNION SELECT '2') AS ig
CROSS JOIN (SELECT '80' AS s_level UNION SELECT '100' UNION SELECT 'Late') AS sl
LEFT JOIN current_view cv
ON cv.s_date = sd.s_date
AND cv.part_no = pn.part_no
AND cv.issue_group = ig.issue_group
AND cv.s_level = ig.s_level
ORDER BY
sd.s_date,
pn.part_no,
ig.issue_group,
DECODE(sl.s_level, '80', 1, '100', 2, 'Late', 3)
NB:您没有标记RDBMS。这应该适用于大多数情况,Oracle除外,在Oracle中,您需要向列出允许值的查询中的每个选择中添加FROM DUAL
,例如:
(SELECT '201802' AS s_date FROM DUAL UNION SELECT '201803' FROM DUAL) AS sd
答案 1 :(得分:0)
想法是使用CROSS JOIN
生成行,然后使用LEFT JOIN
引入额外的信息。在Oracle语法中,这看起来像:
WITH v as (
SELECT v.*
FROM current_view v
WHERE part_no = 'xxxxx' AND
s_date IN ('201802', '201803')
)
SELECT d.s_date, ig.part_no, ig.issue_group, l.s_level,
COALESCE(v.qty_filled, 0) as qty_filled
FROM (SELECT DISTINCT s_date FROM v) d CROSS JOIN
(SELECT DISTINCT part_no, ISSUE_GROUP FROM v) ig CROSS JOIN
(SELECT '80' as s_level FROM DUAL UNION ALL
SELECT '100' FROM DUAL UNION ALL
SELECT 'LATE' FROM DUAL
) l LEFT JOIN
v
ON v.s_date = d.s_date AND v.part_no = ig.part_no AND
v.issue_group = ig.issue_group AND v.s_level = l.s_level
ORDER BY s_date, part_no, issue_group,
(CASE s_level WHEN '80' THEN 1 WHEN '100' THEN 2 WHEN 'Late' THEN 3 END)