SQL将表连接到自身以获取上一年的数据
SQL。如何将表连接到自身以获得所需的结果,如下表所示。逻辑是,我想为相同的产品和上一年的相应月份提供单位 源表上的简单左连接在键a.[year]=b.[year]+1上,当然,月到月和产品到产品会导致数据丢失,我们在上一年有值,现在没有值SQL将表连接到自身以获取上一年的数据,sql,sql-server,tsql,join,self-join,Sql,Sql Server,Tsql,Join,Self Join,SQL。如何将表连接到自身以获得所需的结果,如下表所示。逻辑是,我想为相同的产品和上一年的相应月份提供单位 源表上的简单左连接在键a.[year]=b.[year]+1上,当然,月到月和产品到产品会导致数据丢失,我们在上一年有值,现在没有值 完全联接就足够了 select distinct coalesce(a.year, b.year+1) as year , coalesce(a.month, b.month) as month , coalesce(a.prod
完全联接就足够了
select distinct
coalesce(a.year, b.year+1) as year
, coalesce(a.month, b.month) as month
, coalesce(a.product, b.product) as product
, a.units as units
, b.units as units_prev
from yourtable a
full join yourtable b on a.[year] = b.[year]+1 and a.[month] = b.[month] and a.product = b.product
但您的预期结果与2018年第2个月产品2的描述略有出入,之前的值为2933
DB小提琴:
结果:
year month product units units_prev
2017 1 1 1721
2017 2 1 4915
2017 4 2 2933
2017 5 1 5230
2018 1 1 1721
2018 1 2 7672
2018 2 1 5216 4915
2018 3 1 8911
2018 4 2 2933
2018 5 1 5230
2019 1 2 7672
2019 2 1 5216
2019 3 1 8911
如果您需要像这样过滤期货,那么您可以添加一个额外的where谓词,类似于:
where coalesce(a.year, b.year+1) <= year(getdate())
我会带着滞后,和一个
对您的设计进行一点猜测,它假设您有一个产品表。如果您想要2017年和2018年没有销售的行,以及2017年3月的预期结果,您需要生成月份、年份并加入产品以获得空值 这个查询会对月份和年份进行查询,如果需要,希望您也能够添加产品
DECLARE @startMonth INT=1
DECLARE @endMonth INT=12
DECLARE @startYear INT=2017
DECLARE @endYear INT=2018
;
WITH months AS (
SELECT @startMonth AS m
UNION ALL
SELECT m+1 FROM months WHERE m+1<=@endMonth
),
years AS (
SELECT @startYear AS y
UNION ALL
SELECT y+1 FROM years WHERE y+1<=@endYear
),
monthYears AS (
SELECT m, y
FROM months, years
)
SELECT thisYear.[Year], thisYear.[Month], thisYear.[Product], thisYear.[Units], prevYear.[Units] as units_prev
FROM
(SELECT [Product], my.y as [Year], my.m as [Month], [Units]
FROM monthYears my
LEFT JOIN sales on my.m = [Month] and my.y = [Year]) as thisYear
LEFT OUTER JOIN
(SELECT [Product], my.y as [Year], my.m as [Month], my.y + 1 as NextYear, [Units]
FROM monthYears my
LEFT JOIN sales on my.m = [Month] and my.y = [Year]) as prevYear
on thisYear.Product = prevYear.Product
and (thisYEAR.[Year]) = prevYear.[NextYear]
and thisYEAR.[Month] = prevYear.[Month]
ORDER BY thisYear.[Year], thisYear.[Month], thisYear.[Product]
option (maxrecursion 12);
年-月
使用交叉连接生成行,使用左连接引入数据,然后使用lag获取上一个值:
select y.year, m.month, p.product, t.units,
lag(t.units) over (partition by p.product, m.month order by y.year) as prev_units
from (select distinct year from t) y cross join
(select distinct month from t) m cross join
(select distinct product from t) p left join
t
on t.year = y.year and t.month = m.month and t.product = p.producct;
您可以使用交叉联接在数据中生成年、月和产品的所有可能组合。如果存在特定组合的数据,简单的左连接将为您提供值或NULL
DECLARE @t TABLE (year int, month int, product int, unit int);
INSERT INTO @t VALUES
(2017, 1, 1, 1721),
(2017, 2, 1, 4915),
(2017, 5, 1, 5230),
(2018, 2, 1, 5216),
(2018, 3, 1, 8911),
(2017, 4, 2, 2933),
(2018, 1, 2, 7672);
SELECT ally.year, allm.month, allp.product, curr.units, prev.units AS units_prev
FROM (SELECT DISTINCT year FROM @t) AS ally
CROSS JOIN (SELECT DISTINCT product FROM @t) AS allp
CROSS JOIN (SELECT DISTINCT month FROM @t) AS allm
LEFT JOIN @t AS curr ON curr.year = ally.year AND curr.product = allp.product AND curr.month = allm.month
LEFT JOIN @t AS prev ON prev.year = ally.year - 1 AND prev.product = allp.product AND prev.month = allm.month
结果:
| year | month | product | units | units_prev |
|------|-------|---------|-------|------------|
| 2017 | 1 | 1 | 1721 | NULL |
| 2017 | 2 | 1 | 4915 | NULL |
| 2017 | 3 | 1 | NULL | NULL |
| 2017 | 4 | 1 | NULL | NULL |
| 2017 | 5 | 1 | 5230 | NULL |
| 2017 | 1 | 2 | NULL | NULL |
| 2017 | 2 | 2 | NULL | NULL |
| 2017 | 3 | 2 | NULL | NULL |
| 2017 | 4 | 2 | 2933 | NULL |
| 2017 | 5 | 2 | NULL | NULL |
| 2018 | 1 | 1 | NULL | 1721 |
| 2018 | 2 | 1 | 5216 | 4915 |
| 2018 | 3 | 1 | 8911 | NULL |
| 2018 | 4 | 1 | NULL | NULL |
| 2018 | 5 | 1 | NULL | 5230 |
| 2018 | 1 | 2 | 7672 | NULL |
| 2018 | 2 | 2 | NULL | NULL |
| 2018 | 3 | 2 | NULL | NULL |
| 2018 | 4 | 2 | NULL | 2933 |
| 2018 | 5 | 2 | NULL | NULL |
令人惊讶的您不在[月]日加入?是这样还是你忘了?好吧,让我吃惊的是今年的合并,应该是b年+1年-技术上说,2019年,产品1的第3个月有8911个单位-但是你没有给出你的预期结果我没有[Day]。@PrzemyslawRemin C.[Day]=1不是YST.[Day]但是如果,你的意思是你的日历表没有日期栏,@PrzemyslawRemin我的问题是为什么?这是日历表中一个非常重要的列,我建议您对它进行更改以包含它。我没有[日期]列。只是因为我处理月度数据。我的[Units]列聚合为完整的月份。那么,@PrzemyslawRemin,在您的日历表中,是否只存储每月的第一天?如果是这样,那么只需从ON子句中删除和C.[Day]=1。如果没有,那么如果您的日历表中有一个月的每一天,为什么不在日历表中呢。然而,基于您的上述陈述,为什么您的日历表中没有每个日历日?这就是为什么它被称为日历表。为什么2017年4月1日有2933页?@SalmanA更正。Thx.您真的需要2017年的行吗?您可以简单地拥有5行输出,如product、month、2018\u units、2017_units@SalmanA是的,我确实需要该结构中每年的数据——比2018年和2017年还要多。我喜欢它的简单性,但它应该改进。它在我的数据的product列中生成三个null。在我的预期结果中,2017年和2018年都没有销售的产品2月份应该没有行。我想你的笛卡尔会为此产生行。请在代码的第二行加上别名好吗?@PrzemyslawRemin。是的,我知道您也希望产品交叉连接。这个查询是固定的。从显示的预期结果来看,我推测他们更喜欢从t y交叉连接选择不同的年份,从t mp选择不同的月份。@GordonLinoff差不多完成了。如果coalesceunits、prev_units不为null,那么“附加”是使查询获得所需结果的最佳方法吗?我不想要今年和上一年没有销售额的行。有些产品仅在一年中的特定月份销售。因为源表有几百万行,所以如果可能的话,我不希望同时删除这些杂草。@PrzemyslawRemin。是的,我想可以了。嗨,萨尔曼,1你的最终成绩中没有[年份]栏。2我不理解year=2018或year=2018-1表示选择*的条款。3[年份]列值在源表中是示例性的。2016年、2015年……为[年度]。。。。请不要参考数值。你能解释一下你的笛卡尔积是如何只产生10行而不是20行的吗。戈登·林诺夫的回答?对不起,我以为我们只谈了两年。它可以很容易地在n年内工作,但是滞后比两个左连接好。为什么你认为滞后比两个左连接好?性能似乎有利于自连接:这取决于。但我还是修改了我的答案。它现在与另一行完全相同,只是它使用左连接查找上一行。这个计划看起来稍微好一点。
| year | month | product | units | units_prev |
|------|-------|---------|-------|------------|
| 2017 | 1 | 1 | 1721 | NULL |
| 2017 | 2 | 1 | 4915 | NULL |
| 2017 | 3 | 1 | NULL | NULL |
| 2017 | 4 | 1 | NULL | NULL |
| 2017 | 5 | 1 | 5230 | NULL |
| 2017 | 1 | 2 | NULL | NULL |
| 2017 | 2 | 2 | NULL | NULL |
| 2017 | 3 | 2 | NULL | NULL |
| 2017 | 4 | 2 | 2933 | NULL |
| 2017 | 5 | 2 | NULL | NULL |
| 2018 | 1 | 1 | NULL | 1721 |
| 2018 | 2 | 1 | 5216 | 4915 |
| 2018 | 3 | 1 | 8911 | NULL |
| 2018 | 4 | 1 | NULL | NULL |
| 2018 | 5 | 1 | NULL | 5230 |
| 2018 | 1 | 2 | 7672 | NULL |
| 2018 | 2 | 2 | NULL | NULL |
| 2018 | 3 | 2 | NULL | NULL |
| 2018 | 4 | 2 | NULL | 2933 |
| 2018 | 5 | 2 | NULL | NULL |