【问题标题】:A string of quarterly dates between a start and end date开始日期和结束日期之间的一串季度日期
【发布时间】:2017-07-17 14:34:06
【问题描述】:

我有一个递归 cte 用于生成 @startDate 和 @endDate 之间的日期列表,按季度递增。

declare @startDate datetime
declare @endDate datetime

set @startDate= '01-jan-2014'
set @endDate= '01-jul-2017'

;With cte
As
( Select @startDate date1
Union All
Select DateAdd(Month,3,date1)   From cte where date1 < @endDate 
) select cast(cast( Year(date1)*10000 + MONTH(date1)*100 + 1 as 
varchar(255)) as date) quarterlyDates From cte

这会产生:

quarterlyDates
--------------
2014-01-01
2014-04-01
2014-07-01
2014-10-01 ...

我想将 cte 的输出连接成一个字符串,如下所示:

"'01-jan-2014', '01-apr-2014, '01-jul-2014'..." 

等等。我对这最后一步感到困惑 - 任何帮助将不胜感激!

【问题讨论】:

  • 是什么消耗了这个输出?逗号分隔的数据不是在 SQL Server 中表示多个值的自然方式(例如,与表或 XML 中的行不同)。如果使用这些数据的内容也不能自然地将数据表示为逗号分隔,也许我们可以避免不必要的转换?
  • 它将一些动态 sql 作为字符串,你可能是对的,这不是它需要的,但 SQL 不是我的天然家园,所以我正在慢慢构建...
  • 可以避免使用动态 SQL,或者您可以使用此数据填充临时表 - 外部范围的临时表可在动态 SQL 内部访问,这样可以更自然地表示数据。
  • 好的 - 谢谢。我已将另一个响应标记为已接受,但我也会检查临时表范围 - 这很有用。
  • 这并没有真正解决您的串联问题,但我会再次推荐我最喜欢的答案,即使用日期维度/日历表来帮助预先计算您需要的日期。每个数据库都应该有一个。它既能让你的查询更快,也能让你的生活更轻松。

标签: sql sql-server-2008-r2 common-table-expression


【解决方案1】:

不知道你为什么要...但只是包装底部的 cte 并使用东西。

declare @table table(quarterlyDates date)
insert into @table
values
('2014-01-01'),
('2014-04-01'),
('2014-07-01'),
('2014-10-01')

SELECT stuff((
    SELECT ', ' + cast(quarterlyDates as varchar(max))
    FROM @table
    FOR XML PATH('')
    ), 1, 2, '')

在您的代码中...虽然第二个 CTE 不是必需的,但为了清楚起见,我将其保留。

declare @startDate datetime
declare @endDate datetime

set @startDate= '01-jan-2014'
set @endDate= '01-jul-2017'

;With cte
As
( Select @startDate date1
Union All
Select DateAdd(Month,3,date1)   From cte where date1 < @endDate 
), 

cte2 as(
select cast(cast( Year(date1)*10000 + MONTH(date1)*100 + 1 as 
varchar(255)) as date) quarterlyDates From cte)

SELECT stuff((
    SELECT ', ' + cast(quarterlyDates as varchar(max))
    FROM cte2
    FOR XML PATH('')
    ), 1, 2, '');

【讨论】:

    【解决方案2】:

    使用FOR XML Pathtype 指令来避免在结果中编码非法字符

    ;WITH cte 
         AS (SELECT @startDate date1 
             UNION ALL 
             SELECT Dateadd(month, 3, date1) 
             FROM   cte 
             WHERE  date1 < @endDate) 
    SELECT Stuff((SELECT ',' + CONVERT(VARCHAR(15), date1, 106) quarterlyDates 
                  FROM   cte 
                  FOR xml path, type).value('.[1]', 'nvarchar(max)'), 1, 1, ''); 
    

    注意:我已经更改了最终 select 中不需要的操作。在Convert函数中使用样式106来获取所需的输出格式

    【讨论】:

      【解决方案3】:

      迟到的答案,只是为了好玩。

      示例

      declare @startDate datetime = '01-jan-2014'
      declare @endDate datetime   = '01-jul-2017'
      
      ;With cte
      As
      ( Select date1 = @startDate
              ,dates = ''''+convert(varchar(max),convert(varchar(11),@startDate,113))+''''
        Union All
        Select DateAdd(Month,3,date1)   
              ,cte.dates+','''+convert(varchar(11),DateAdd(Month,3,date1)   ,106)+''''
         From cte where date1 < @endDate 
      ) 
      Select Top 1 with ties 
             Dates=lower(replace(Dates,' ','-') )
       From cte
       Order By Date1 Desc
      

      退货

      '01-jan-2014','01-apr-2014','01-jul-2014','01-oct-2014','01-jan-2015','01-apr-2015','01-jul-2015','01-oct-2015','01-jan-2016','01-apr-2016','01-jul-2016','01-oct-2016','01-jan-2017','01-apr-2017','01-jul-2017'
      

      【讨论】:

        猜你喜欢
        • 2021-07-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-05
        • 1970-01-01
        • 1970-01-01
        • 2017-01-05
        • 1970-01-01
        相关资源
        最近更新 更多