【问题标题】:Select Past 24(N) Months First Date选择过去 24(N) 个月的第一个日期
【发布时间】:2013-02-21 04:34:43
【问题描述】:

这是一个显示过去 24 个月的第一个日期的脚本。

我需要在单个 T-SQL 查询中使用以下功能,而不是迭代。

Declare @intCount as int

SET @intCount = 24

Declare @Date as varchar(25)  

While (@intCount >0)

Begin
SET @Date = CONVERT(VARCHAR(25),DATEADD(m,-(@intCount-1),
                                DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101)
select @Date

SET @intCount = @intCount-1

End

以上查询返回 24 个结果集(选择)。但我想要一个结果集

编辑:

主要要求是在子查询中使用这个单一结果

【问题讨论】:

  • 在迭代时将它们插入到维度式表中,然后只查询该表怎么样?
  • @Scotch,我没听懂你。你是说临时表?我不擅长 SQL :( 你能否添加你的答案,这样我就可以理解 :)
  • 你试过什么?在此处阅读有关递归 CTE 的信息:msdn.microsoft.com/en-us/library/ms186243%28v=sql.105%29.aspx
  • @cha,这个递归 CTE 如何适合这里。抱歉,我不是那个 SQL 专家 :(
  • 用递归 CTE 查看我的答案

标签: sql sql-server tsql


【解决方案1】:

您可以使用递归 CTE

;with cte(intCount,myDate)
 as
 (
   Select 1, CONVERT(VARCHAR(25),DATEADD(m,  1,
                            DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101)
   union all
    Select intCount+1 ,CONVERT(VARCHAR(25),DATEADD(m,-(intCount-1),
                            DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101) from cte
                            where intCount<=24
 )
Select myDate from  cte

更新:

如果需要,可以将其存储在表变量或临时表中

 Declare @Date table
 (myDate varchar(25))

 Declare @count int
 set @count=24
 ;with cte(intCount,myDate)
 as
 (
   Select @count-1, CONVERT(VARCHAR(25),DATEADD(m,-(@count-1),
                            DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101)
   union all
   Select intCount-1 ,CONVERT(VARCHAR(25),DATEADD(m,-(intCount-1),
                            DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101) from cte
                            where intCount>0
 )
 Insert into @Date(myDate) 
 Select myDate from cte

或者你可以创建一个函数

 go
 alter FUNCTION FnGetDate(@intCount int)
 RETURNS  @rtnTable TABLE 
 (
  myDate varchar(25)NOT NULL
 )
 AS
 BEGIN

 ;with cte(level,myDate)
  as
 (
   Select @intCount-1, CONVERT(VARCHAR(25),DATEADD(m,-(@intCount-1),
                        DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101)
   union all
   Select level-1 ,CONVERT(VARCHAR(25),DATEADD(m,-(level-1),
                        DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101) from cte
                        where level>0
 ) 
 Insert into @rtnTable(myDate)
 select myDate from cte
 return
 END

现在你可以像

 Select * from dbo.FnGetDate(24)

【讨论】:

  • 为什么我得到 03/01/2013、03/01/2013 然后 02/01/2013。似乎第一条记录是两次:)
  • @praveen:答案仍然给出了一个额外的日期,包括未来一个月。解决这个问题,它可能会回答这个问题。
  • 只是没有正确检查问题中的条件。更新了我的答案
  • @praveen,2013 年 3 月 1 日是未来日期 :(
  • Update下方查看我的第二个答案。它不会返回03/01/2013
【解决方案2】:

这就是我的建议,我对存储过程生疏了,但我将我的建议加粗到你原来的过程中

Declare @intCount as int
  CREATE TABLE days (day varchar(25));
 SET @intCount = 24

 Declare @Date as varchar(25)  

 While (@intCount >0)

Begin
 SET @Date = CONVERT(VARCHAR(25),DATEADD(m,-(@intCount-1),
                            DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101)
 INSERT Into days(day) VALUES (@Date)
 SET @intCount = @intCount-1

 End
 SELECT * FROM days;

【讨论】:

  • 看起来不错。有没有办法在没有迭代的情况下做到这一点?
  • 好吧,在这个例子中你没有用你的选择进行迭代——所以你只得到一个结果集,我想安德烈的例子在技术上并不是迭代,因为它只是逐行合并每个转换.
【解决方案3】:

使用临时表:

Declare @intCount as int
SET @intCount = 24    
Declare @Date as varchar(25)  
create table #temp1 (myDate date)
While (@intCount >0)
Begin
SET @Date = CONVERT(VARCHAR(25),DATEADD(m,-(@intCount-1),DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101)
insert into #temp1
select @Date
SET @intCount = @intCount-1
End

select * from #temp1

【讨论】:

  • 是否可以在没有迭代的情况下使用?
  • 我认为 praveen 的方法正是你所需要的。
  • 是的,格里沙。这就是我现在正在研究的。不确定查询费用。哪个会更好? :)
  • 我认为 whilecte 的成本会非常相似,尤其是当您只有 24 次迭代时...
【解决方案4】:

如果@intCount 是常量,您可以通过简单的UNION ALL 做到这一点:

select CONVERT(VARCHAR(25),DATEADD(m,-24, DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101) as date
union all
select CONVERT(VARCHAR(25),DATEADD(m,-23, DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101) as date
union all
.....
select CONVERT(VARCHAR(25),DATEADD(m,0, DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101) as date

或者使用临时表:

Declare @intCount as int

SET @intCount = 24

Declare @Date as varchar(25)  

CREATE TABLE #temptable 
    (datefield date)

While (@intCount >0)

Begin
SET @Date = CONVERT(VARCHAR(25),DATEADD(m,-(@intCount-1),
                                DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101)
insert into #temptable                              
select @Date

SET @intCount = @intCount-1

End
select * from #temptable
drop table #temptable

【讨论】:

  • 这又像是一次迭代。我将发送 N 作为月数。在这种情况下,我需要在循环中准备尽可能多的选择联合:(
【解决方案5】:

这是一个如何使用 CTE 的示例:

;WITH DateCTE AS
    (
        SELECT dateadd(dd, - datepart(day, getdate()) + 1, Convert(date, getdate())) AS DateValue
        UNION ALL
        SELECT DATEADD(month, -1, DateValue)
        FROM DateCTE
        WHERE DATEADD(month, 23, DateValue) >  GetDate()
    )
select DateValue from DateCTE;

【讨论】:

  • 这看起来很棒。我可以在子查询中使用它吗?
  • 当然,只需将表添加到此查询的末尾,例如(在from dateCTE 之后): INNER JOIN Mytable on dateCTE.dateValue = Mytable.productiondate
【解决方案6】:
DECLARE @intCount AS INT

SET @intCount = 24

DECLARE @Date AS VARCHAR(25)  

WHILE (@intCount > 0)
BEGIN
    SET @Date = ISNULL(@Date, '') + CONVERT(VARCHAR(25),DATEADD(m,-(@intCount-1),
                                DATEADD(dd,-(DAY(GETDATE())-1),GETDATE())),101) + ' '
    --SELECT @Date   Don't have it here
    SET @intCount = @intCount -1
END

SELECT @Date

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-26
    • 2015-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多