SQL。如下表所示,如何将表连接到自身以获得所需的结果。逻辑是我要为同一产品和上一年的相应月份设置单位。
在源表上对键a.[year]=b.[year]+1
本身进行简单的左联接(当然还有逐月以及从产品到产品)会导致丢失我们上一年有值且没有值的数据现在。
答案 0 :(得分:3)
完全加入就足够了
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 Fiddle:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=d01dc5bd626854b083be0864f2d5b0e4
结果:
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 coalesce(a.year, b.year+1) <= year(getdate())
答案 1 :(得分:2)
年份月份
使用cross join
生成行,使用left join
引入数据,然后使用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;
答案 2 :(得分:1)
我会选择LAG
和一个calendar table。
SELECT C.[Year],
C.[Month],
YPT.product,
YST.units,
YST.LAG(YST.units) OVER (PARTITION BY YTP.[product],C.[month] ORDER BY C.[year]) AS UnitsPrev
FROM CalendarTable C
CROSS JOIN YourProductTable YPT
LEFT JOIN YourSourceTable YST ON C.[Year] YST.[Year]
AND C.[Month] = YST.[Month]
AND YPT.Product = YST.Product
WHERE C.[day] = 1
AND C.[date] BETWEEN {SomeStartDate} AND {SomeEndDate];
这对您的设计有一些猜测(假设您有一个产品表)。
答案 3 :(得分:1)
您可以使用CROSS JOIN
在数据中生成年份,月份和产品的所有可能组合。如果存在特定组合的数据,简单的LEFT JOIN
将为您提供值或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 |
答案 4 :(得分:0)
如果您希望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);