【问题标题】:Return All Months & Years Between Date Range - SQL返回日期范围之间的所有月份和年份 - SQL
【发布时间】:2013-11-01 16:18:12
【问题描述】:

我有点难过我该怎么做。

我有一个非常基本的查询,目前按年和月返回每种产品的销售额。 它按年/月分组,并汇总数量。 这将为有销售的每个产品/年/月组合返回一行。

如果一个月没有销售,则没有数据。

我希望我的查询为我的日期范围内的每个年/月的每个产品返回一行数据,无论是否实际有订单。

如果没有订单,那么我可以为该产品/年/月返回 0。

以下是我的示例查询。

Declare @DateFrom datetime, @DateTo Datetime
Set @DateFrom = '2012-01-01'
set @DateTo = '2013-12-31'

select 
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As YearMonth,
variant_detail.vad_variant_code,
sum(order_line_item.oli_qty_required) as 'TotalQty'

From 
variant_Detail
join order_line_item on order_line_item.oli_vad_id = variant_detail.vad_id
join order_header on order_header.oh_id = order_line_item.oli_oh_id

Where 
(order_header.oh_datetime between @DateFrom and @DateTo)

Group By 
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110),
variant_detail.vad_variant_code

【问题讨论】:

  • 我认为你需要一个 12 个月的表,简单的 int 列,然后你加入你的查询。
  • 问题是我不能改变数据库来添加一个表来做到这一点。
  • 按照米海的建议做,但不要创建一个真实的表,而是使用一个表变量:declare @mytable table (id int, name varchar(20)) 然后将名称插入到表变量中并将其加入到您的查询中。
  • 你可以使用 CTE 来制作这个。您在网络上有示例
  • 确保这个临时表有年月组合,而不仅仅是月。永远不知道输入参数是什么。

标签: sql sql-server date


【解决方案1】:

您可以使用 CTE 生成它。 您将找到有关本文的信息: http://blog.lysender.com/2010/11/sql-server-generating-date-range-with-cte/

尤其是这段代码:

WITH CTE AS
(
    SELECT @start_date AS cte_start_date
    UNION ALL
    SELECT DATEADD(MONTH, 1, cte_start_date)
    FROM CTE
    WHERE DATEADD(MONTH, 1, cte_start_date) <= @end_date   
)
SELECT * 
FROM CTE

【讨论】:

    【解决方案2】:

    感谢您的建议。

    我设法使用另一种方法使其工作。

    Declare @DateFrom datetime, @DateTo Datetime
    Set @DateFrom = '2012-01-01'
    set @DateTo = '2013-12-31'
    
    select 
    YearMonthTbl.YearMonth,
    orders.vad_variant_code,
    orders.qty
    
    From 
    (SELECT  Convert(CHAR(4),DATEADD(MONTH, x.number, @DateFrom),120) + '/' + Convert(CHAR(2),DATEADD(MONTH, x.number, @DateFrom),110) As YearMonth
    FROM    master.dbo.spt_values x
    WHERE   x.type = 'P'        
    AND     x.number <= DATEDIFF(MONTH, @DateFrom, @DateTo)) YearMonthTbl
    
    
    left join 
        (select variant_Detail.vad_variant_code, 
        sum(order_line_item.oli_qty_required) as 'Qty', 
        Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As 'YearMonth'
        FROM order_line_item 
        join variant_detail on variant_detail.vad_id = order_line_item.oli_vad_id
        join order_header on order_header.oh_id = order_line_item.oli_oh_id
        Where 
        (order_header.oh_datetime between @DateFrom and @DateTo)
        GROUP BY variant_Detail.vad_variant_code,
        Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110)
        ) as Orders on Orders.YearMonth = YearMonthTbl.YearMonth
    

    【讨论】:

    【解决方案3】:

    这是我整理的。它肯定需要一些调试,但我认为这将引导您朝着正确的方向前进。我将查询分成不同的部分,以尝试使其更易于阅读。希望这会有所帮助。

    DECLARE @dateFrom DATETIME, @dateTo DATETIME
    
    SELECT @dateFrom = MIN(oh_datetime) FROM order_header
    SELECT @dateTo = MAX(oh_datetime) FROM order_header
    
    ;WITH
    y AS
    (
        SELECT YEAR(@dateFrom) AS [Year]
        UNION ALL
        SELECT [Year] + 1
        FROM y
        WHERE
              [Year] < YEAR (GETDATE())
    ),
    m AS
    (
        SELECT 1 AS [Month]
        UNION ALL
        SELECT [Month] + 1
        FROM m
        WHERE
              [Month] < 12
    ),
    dates AS
    (
    SELECT
        CAST(y.[Year] AS nvarchar(4)) + N'/' + RIGHT(N'00' + CAST(m.[Month] AS nvarchar(2)), 2) AS YearMonth
    FROM
        y CROSS JOIN m
    ),
    qty AS
    (
    SELECT
        YEAR(oh.oh_datetime) + N'/' + MONTH(oh.oh_datetime) AS YearMonth,
        v.vad_variant_code,
        oli.oli_qty_required AS Qty
    FROM
        variant_Detail AS v
            INNER JOIN order_line_item AS oli ON oil.oli_vad_id = v.vad_id
            INNER JOIN order_header AS oh ON oh.oh_id = oli.oli_oh_id
    )
    SELECT
        d.YearMonth,
        qty.vad_variant_code,
        SUM(qty.Qty) AS TotalQty
    FROM
        dates AS d LEFT OUTER JOIN qty
            ON d.YearMonth = qty.YearMonth
    GROUP BY
        d.YearMonth,
        qty.vad_variant_code
    

    【讨论】:

      【解决方案4】:

      如果你找到一年中的所有月份,这里是另一个转折

      ;WITH DateYear AS (
          SELECT 0 AS num
          UNION ALL
          SELECT num + 1 FROM DateYear
          WHERE num < 11
      )
      Select FirstDateOfTheMonth, DATENAME(mm,FirstDateOfTheMonth), num from 
      (SELECT CONVERT(DATE,DATEADD(MONTH,num,'2017'))  AS FirstDateOfTheMonth, num from DateYear)
      cte
      

      结果是

      另一个转折:

      Declare @dateFrom datetime ='2019-03-21', @dateTo datetime ='2019-12-31'
      ;WITH CTE AS
      (
          SELECT @dateFrom AS cte_start_date
          UNION ALL
          SELECT DATEADD(MONTH, 1, cte_start_date)
              FROM CTE
              WHERE ( DATEADD(MONTH, 1, cte_start_date) <=  EOMONTH( @dateTo)   ) 
              --or ( DATENAME(MONTH, cte_start_date) =DATENAME(MONTH, @dateTo) and DATENAME(year, cte_start_date) =DATENAME(year, @dateTo) ) )
      )
      SELECT * 
      FROM CTE
      

      以下内容适用于 sqlserver 2012 及更高版本,以获取该月的最后一天:- Select EOMONTH('2020-02-15')

      【讨论】:

        猜你喜欢
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-22
        • 2020-12-07
        • 1970-01-01
        • 1970-01-01
        • 2016-11-20
        相关资源
        最近更新 更多