用个人查询替换 CTE

问题描述 投票:0回答:1

我正在使用 Netezza SQL。

我有下表:

CREATE TABLE sample_table 
(
    name VARCHAR(50),
    year INTEGER,
    color VARCHAR(50)
);

INSERT INTO sample_table (name, year, color)
VALUES ('aaa', 2010, 'Red');

INSERT INTO sample_table (name, year, color)
VALUES ('aaa', 2012, 'Red');

INSERT INTO sample_table (name, year, color)
VALUES ('bbb', 2014, 'Blue');

INSERT INTO sample_table (name, year, color)
VALUES ('bbb', 2016, 'Blue');

桌子看起来像这样:

+------+--------+-------+
| name |  year  | color |
+------+--------+-------+
| aaa  |  2010  |  Red  |
| aaa  |  2012  |  Red  |
| bbb  |  2014  | Blue  |
| bbb  |  2016  | Blue  |
+------+--------+-------+

如我们所见:

  • “aaa”在 2010 年和 2012 年之间(即 2011 年)缺少一行
  • “bbb”在 2014 年和 2016 年(即 2015 年)之间缺少一行

我的问题: 我想编写一个 SQL 查询,为这两个名称添加这些缺失的行(假设每个“名称”的“颜色”保持不变)。最终输出应该是这个样子:

+------+--------+-------+
| name |  year  | color |
+------+--------+-------+
| aaa  |  2010  |  Red  |
| aaa  |  2011  |  Red  |
| aaa  |  2012  |  Red  |
| bbb  |  2014  | Blue  |
| bbb  |  2015  | Blue  |
| bbb  |  2016  | Blue  |
+------+--------+-------+

在上一个问题中,我学习了如何使用递归 CTE 解决类似问题(Adding Missing Rows in SQL using JOINS)。有人可以告诉我如何通过创建中间表来尝试解决这个问题吗? (例如 temp_tab1, temp_tab2, ... drop temp_tab1)

我仍在学习 SQL,发现更容易理解更小的代码块

谢谢!

sql recursive-query gaps-and-islands
1个回答
1
投票

为了避免递归,你可以有一个表列出所有可能的年份,你会用它来生成每个产品的“缺失”行,比如

years_table(years)

我们通常会在子查询中生成每个名称的开始和结束年份,然后从年份表中提取所有年份,最后检查我们是否在原始数据中有匹配项,使用

left join
;

select n.name, y.year, t.color
from (
    select name, min(year) min_year, max(year) max_year
    from sample_table
    group by name
) n
inner join years_table y on y.year between n.min_year and n.max_year
left join sample_table t on t.name = n.name and t.year = y.year
    

这有效,但不会为查询逻辑“添加”的行提供颜色。为此,我们需要做更多的工作(这是一个差距和孤岛问题)。这是一种方法:

select name, year, max(color) over(partition by name, grp order by year) color
from ( 
    select n.name, y.year, t.color, 
        sum(case when t.name is null then 0 else 1 end) over(partition by n.name order by y.year) grp
    from (
        select name, min(year) min_year, max(year) max_year
        from sample_table
        group by name
    ) n
    inner join years_table y on y.year between n.min_year and n.max_year
    left join sample_table t on t.name = n.name and t.year = y.year
) t

这也是我在这里提倡递归查询的另一个原因。这个想法是识别日期系列中的间隙,并使用递归仅生成缺失的行。由于递归查询从锚点开始,因此很容易跟踪“当前”颜色。

with recursive
    data as (
        select t.*, lead(year) over(partition by name order by year) lead_year
        from sample_table t
    ),
    rec as (
        select name, year,     color, lead_year from data where lead_year > year + 1
        union all
        select name, year + 1, color, lead_year from rec  where lead_year > year + 1
    )
select name, year, color from data where lead_year is null or lead_year = year + 1
union all
select name, year, color from rec
order by name, year

这里:

  • data
    查找“下一个”可用年份,这可以识别差距
  • rec
    从每个空隙开始,生成新的行,直到到达下一个岛,跟踪原始颜色
  • 外部查询
    union
    将原始岛屿和我们填补的空白结合在一起

这是 DB Fiddle 上的demo,其中有几行添加到您的数据中,并且两种解决方案都在工作。

输入:

姓名 颜色
aaa 2010 红色
aaa 2012 红色
aaa 2013 蓝色
aaa 2016 蓝色
bb 2014 蓝色
bb 2016 蓝色

输出:

姓名 颜色
aaa 2010 红色
aaa 2011 红色
aaa 2012 红色
aaa 2013 蓝色
aaa 2014 蓝色
aaa 2015 蓝色
aaa 2016 蓝色
bb 2014 蓝色
bb 2015 蓝色
bb 2016 蓝色
© www.soinside.com 2019 - 2024. All rights reserved.