【问题标题】:How to create a view from existing table records, but also adding new records that do not exist如何从现有表记录创建视图,同时添加不存在的新记录
【发布时间】:2019-06-09 23:44:06
【问题描述】:

我正在尝试从现有视图数据创建视图,但如果每个部件/日期组合中不存在某些行,则创建这些行。我有以下查询,显示了我目前对特定 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 个部分/日期组合。

【问题讨论】:

  • 提取唯一的 issue_group 和 s_level 组合并 LEFT JOIN 将其添加到您的查询中。
  • @PM77-1 但我目前只有一张桌子,那它是如何工作的?还是我必须首先使用每个 issue_group 和 s_level 组合创建该表/视图,然后再进行连接?
  • 编写一个查询以产生唯一的组合并将其结果用于JOIN
  • 您好@PM77-1,请用您正在使用的 RDBMS 标记您的问题:oracle、mysql、sql-server...?
  • @GMB 对不起,我以为我在标签中添加了 RDBMS ......但它是 Oracle。

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


【解决方案1】:

一种解决方案可能是使用(固定)值列表之间的笛卡尔积生成所有预期行的笛卡尔积,然后将LEFT JOINcurrent_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)

注意:您没有标记您的 RDBMS。这应该适用于其中的大多数,除了 Oracle,您需要将 FROM DUAL 添加到列出允许值的查询中的每个选择中,例如:

(SELECT '201802' AS s_date FROM DUAL UNION SELECT '201803' FROM DUAL) AS sd

【讨论】:

    【解决方案2】:

    这个想法是使用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)
    

    【讨论】:

    • 谢谢!!我删除了最初 with 语句中的 where 子句,它仍然适用于视图中的所有部分/日期。交叉连接和复杂性有点超出我的想象,所以现在我还有更多的学习要做。我真的很感激。
    猜你喜欢
    • 2013-09-25
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    • 2023-01-12
    • 1970-01-01
    • 2017-05-23
    • 2012-07-25
    相关资源
    最近更新 更多