如何从现有表记录创建视图,还如何添加不存在的新记录

时间:2019-01-15 22:22:34

标签: sql oracle create-table insert-into create-view

我正在尝试根据现有的视图数据创建视图,但是如果每个零件/日期组合中不存在某些行,则要创建这些行。我有下面的查询,该查询显示了当前针对特定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)

哪个产生以下内容:

enter image description here

我知道如何用这些数据创建视图,这很容易。但是我需要的是每个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。所以我试图让它看起来像这样:

enter image description here

我只显示了一部分,有几个日期,只是为了阐明要点。该表中有超过10k的零件,对于6个issue_group / s_level组合,每个零件/日期组合都不会超过1个。

2 个答案:

答案 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)