代码之家  ›  专栏  ›  技术社区  ›  Przemyslaw Remin

SQL将表连接到自身以获取上一年的数据

  •  2
  • Przemyslaw Remin  · 技术社区  · 7 年前

    SQL。如何将表连接到自身以获得所需的结果,如下表所示。逻辑是,我想为相同的产品和上一年的相应月份提供单位。

    源表上的简单左连接到键上的自身 a.[year]=b.[year]+1

    enter image description here

    5 回复  |  直到 7 年前
        1
  •  3
  •   Andrew    7 年前

    完全联接就足够了

      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。

    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())
    
        2
  •  2
  •   Gordon Linoff    7 年前

    年-月

    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;
    
        3
  •  1
  •   Thom A    7 年前

    我会和你一起去 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];
    

    这是对您的设计的一点猜测(假设您有一个产品表)。

        4
  •  1
  •   Salman Arshad    7 年前

    您可以使用以下工具在数据中生成年、月和产品的所有可能组合: 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       |
    
        5
  •  0
  •   PhilS    7 年前

    如果您希望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);
    
    推荐文章