2010-03-08 35 views
3

我有我的Oracle数据库运行下面的查询,我想有一个SQL Server 2008数据库相当于:帮忙翻译从Oracle的PL/SQL本周查询到SQL Server 2008

SELECT TRUNC(/* Midnight Sunday */ 
     NEXT_DAY(SYSDATE, 'SUN') - (7*LEVEL) 
     ) AS week_start, 
     TRUNC(/* 23:59:59 Saturday */ 
     NEXT_DAY(NEXT_DAY(SYSDATE, 'SUN') - (7*LEVEL), 'SAT') + 1 
     ) - (1/(60*24)) + (59/(60*60*24)) AS week_end 
FROM DUAL 
CONNECT BY LEVEL <= 4 /* Get the past 4 weeks */ 

什么查询所做的是获得本周的开始和最后4周的本周结束。周数是任意的,应该在我想要的SQL Server查询中轻松修改。它产生的数据如下所示:

WEEK_START   WEEK_END 
2010-03-07 00:00:00 2010-03-13 23:59:59 
2010-02-28 00:00:00 2010-03-06 23:59:59 
... 

我目前停留在翻译的部分是CONNECT BY LEVEL因为它似乎SQL Server 2008不具有等同的。我宁愿简单地调整一条线,如CONNECT BY LEVEL <= 4,并让查询生成更多或更少的周(即,我不想调整多个UNION ALL声明)。

编辑:这里是我迄今为止获取当前一周的开始和结束:

SELECT week_start, 
      DATEADD(SECOND, -1, DATEADD(DAY, 7, week_start)) AS week_end 
    FROM (
      SELECT CAST(
        CONVERT(
        VARCHAR(10), 
        DATEADD(DAY, 1-DATEPART(DW, GETDATE()), GETDATE()), 
        111 
        ) AS DATETIME 
       ) AS week_start 
     ) AS week_start_view 

我不介意,如果查询显示当前周的开始和结束日期,或者如果它在前一周开始。

回答

3

我修改了OMG Ponies'的答案,因为它看起来像个好主意,它每周只有错误的week_end值,并且还显示未来几周而不是过去几周。我想出了以下情况:

WITH dates AS (
    SELECT DATEADD(
      DD, 
      1 - DATEPART(DW, CONVERT(VARCHAR(10), starting_date, 111)), 
      CONVERT(VARCHAR(10), starting_date, 111) 
     ) AS midnight 
    FROM (
     SELECT DATEADD(WEEK, -3, GETDATE()) AS starting_date 
     ) AS starting_date_view 

    UNION ALL 

    SELECT DATEADD(DD, 7, midnight) 
    FROM dates 
    WHERE DATEADD(DD, 7, midnight) < GETDATE() 
) SELECT midnight AS week_start, 
     DATEADD(SS, -1, DATEADD(DAY, 7, midnight)) AS week_end 
    FROM dates 

它产生过去4周内:

week_start     week_end 
2010-02-14 00:00:00.000 2010-02-20 23:59:59.000 
2010-02-21 00:00:00.000 2010-02-27 23:59:59.000 
2010-02-28 00:00:00.000 2010-03-06 23:59:59.000 
2010-03-07 00:00:00.000 2010-03-13 23:59:59.000 

这比我previous answer,我觉得更好,因为它不依赖于具有特定数量的另一个表的行。生成的周数可通过更改仅一个数字来更改:SELECT DATEADD(WEEK, -3, GETDATE()) AS starting_date中的3。本周包括在内,这个数字表示本周之前还有多少周应该显示。

遍历过去几周到现在为止,不包括当前周

更新:和这里的排除在本周一版本:

WITH dates AS (
    SELECT DATEADD(
      DD, 
      1 - DATEPART(DW, CONVERT(VARCHAR(10), starting_date, 111)), 
      CONVERT(VARCHAR(10), starting_date, 111) 
     ) AS midnight_sunday 
    FROM (
     SELECT DATEADD(WEEK, -4, GETDATE()) AS starting_date 
     ) AS starting_date_view 

    UNION ALL 

    SELECT DATEADD(DD, 7, midnight_sunday) 
    FROM dates 
    WHERE DATEADD(DD, 7, midnight_sunday) < 
     DATEADD(
      DD, 
      1 - DATEPART(DW, CONVERT(VARCHAR(10), GETDATE(), 111)), 
      CONVERT(VARCHAR(10), GETDATE(), 111) 
     ) 
) SELECT midnight_sunday AS week_start, 
     DATEADD(SS, -1, DATEADD(DAY, 7, midnight_sunday)) AS week_end 
    FROM dates 

其结果:

week_start     week_end 
2010-02-07 00:00:00.000 2010-02-13 23:59:59.000 
2010-02-14 00:00:00.000 2010-02-20 23:59:59.000 
2010-02-21 00:00:00.000 2010-02-27 23:59:59.000 
2010-02-28 00:00:00.000 2010-03-06 23:59:59.000 

迭代过去几个月直到现在

我后来发现需要此查询的每月版本。下面是修改:

WITH dates AS (
    SELECT CAST(
     FLOOR(CAST(starting_date AS DECIMAL(12, 5))) - 
     (DAY(starting_date) - 1) AS DATETIME 
    ) AS month_start 
    FROM (
     SELECT DATEADD(MONTH, -3, GETDATE()) AS starting_date 
     ) AS starting_date_view 

    UNION ALL 

    SELECT DATEADD(MONTH, 1, month_start) 
    FROM dates 
    WHERE DATEADD(MONTH, 1, month_start) < GETDATE() 
) SELECT month_start, 
     DATEADD(SS, -1, DATEADD(MONTH, 1, month_start)) AS month_end 
    FROM dates 
    ORDER BY month_start DESC 
+0

+1:荣誉!我会更新我的,所以我没有错。 – 2010-03-10 20:55:12

1

所有你需要的是一组:

;WITH cte(n) AS 
(
    SELECT 0 
    UNION ALL SELECT 1 
    UNION ALL SELECT 2 
    UNION ALL SELECT 3 
) 
    SELECT week_start, 
      DATEADD(SECOND, -1, DATEADD(DAY, 7, week_start)) AS week_end 
    FROM (
      SELECT CAST(
        CONVERT(
        VARCHAR(10), 
        DATEADD(WEEK, -n, DATEADD(DAY, 1-DATEPART(DW, GETDATE()), GETDATE())), 
        111 
        ) AS DATETIME 
       ) AS week_start 
          FROM cte 
     ) AS week_start_view; 

不过,我会提醒你,如果你的数据是datetime和你要使用这些边界的查询范围,你应该使用一个开放式的范围内,例如> = 03/07和< 03/14。这样你就不会错过23:59:59和午夜之间发生的任何行;尽可能罕见,但它们可能很重要。

+0

此外,如果你已经有一个数字表,你可以简单地更换CTE和从“FROM dbo.Numbers其中编号为1至4” – 2010-03-08 20:28:54

+0

我喜欢这个。我敢打赌'WITH'可以更改为更像我的'level_view'(请参阅http://stackoverflow.com/questions/2404084/help-translate-this-week-query-from-oracle-pl-sql-to -sql-server-2008/2404501#2404501),然后我可以指定一个数字,而不是执行多个工会。 – 2010-03-08 20:30:26

+0

当行数很少时,UNION非常简单,并且一个Numbers表比从现有表派生行号更简单,并且依赖于总是有足够的行来满足您的查询的事实。很多人反对辅助桌(不知道为什么);我个人认为它们非常有用。因人而异。 – 2010-03-08 20:34:31

0

这是我想出来的。它有点笨拙,因为它至少依赖于我的表中有一个行> =我想选择的周数。我可以稍微调整一下,以包括本周。

SELECT week_start, 
      DATEADD(SECOND, -1, DATEADD(DAY, 7, week_start)) AS week_end 
    FROM (
      SELECT CAST(
        CONVERT(
        VARCHAR(10), 
        DATEADD(
         DAY, 
         1-DATEPART(DW, GETDATE()), 
         DATEADD(DAY, -7*level, GETDATE()) 
        ), 
        111 
        ) AS DATETIME 
       ) AS week_start 
      FROM (
       SELECT level 
       FROM (
         SELECT ROW_NUMBER() OVER(ORDER BY RAND()) AS level 
         FROM my_table_with_at_least_21_rows 
        ) AS all_rows_view 
       WHERE level <= 21 
       ) AS level_view 
     ) AS week_start_view 

从上周开始,这是过去的21周。这里的样本数据:

week_start     week_end 
2010-02-28 00:00:00.000  2010-03-06 23:59:59.000 
2010-02-21 00:00:00.000  2010-02-27 23:59:59.000 
2010-02-14 00:00:00.000  2010-02-20 23:59:59.000 
2010-02-07 00:00:00.000  2010-02-13 23:59:59.000 
... 
+0

1)“4”在等级比较中成为“21”? 2)看看master..spt_values表 – devio 2010-03-09 06:16:20

+0

我后来澄清我的问题,说我想能够调整生成的周数。对不起,我也应该说我的问题是说生成的星期数是任意的,应该很容易修改。 – 2010-03-09 20:50:40

0

根据您的代码:

SELECT DATEADD(day, weeks.week * -7, week_start) AS week_start, 
     DATEADD(SECOND, -1, DATEADD(DAY, (weeks.week-1) * -7, week_start)) AS week_end 
FROM (
     SELECT CAST(
       CONVERT(
       VARCHAR(10), 
       DATEADD(DAY, 1-DATEPART(DW, GETDATE()), GETDATE()), 
       111 
       ) AS DATETIME 
      ) AS week_start 
    ) AS week_start_view, 
    (SELECT 0 AS week UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) AS weeks 
2

使用(但不要忘了vote for Sarah):

WITH dates AS (
    SELECT DATEADD(DD, 
        1 - DATEPART(DW, CONVERT(VARCHAR(10), starting_date, 111)), 
        CONVERT(VARCHAR(10), starting_date, 111) 
        ) AS midnight 
     FROM (SELECT DATEADD(WEEK, -3, GETDATE()) AS starting_date) AS starting_date_view 
    UNION ALL 
    SELECT DATEADD(DD, 7, midnight) 
     FROM dates 
    WHERE DATEADD(DD, 7, midnight) < GETDATE()) 
SELECT midnight AS week_start, 
     DATEADD(SS, -1, DATEADD(DAY, 7, midnight)) AS week_end 
    FROM dates 

以前:

  1. 设置一周的第一天是星期天与SET DATEFIRST命令:

    SET DATEFIRST 7 
    
  2. 在SQL Server 2005+相当于Oracle的CONNECT BY LEVEL是递归的CTE(ANSI标准的BTW)。用途:

    WITH dates AS (
        SELECT DATEADD(DD, 
            1 - DATEPART(DW, CONVERT(VARCHAR(10), GETDATE(), 111)), 
            CONVERT(VARCHAR(10), GETDATE(), 111)) AS date 
        UNION ALL 
        SELECT DATEADD(dd, 7, d.date) 
        FROM dates d 
        WHERE DATEADD(dd, 7, d.date) <= DATEADD(dd, 4*7, GETDATE())) 
    SELECT t.date AS week_start, 
         DATEADD(ss, -1, DATEADD(DAY, 7, t.date)) AS week_end 
        FROM dates t 
    

this link for explaining how to get the first day of the week。要更改星期数,请更改DATEADD(dd, 4*7, GETDATE()),其中4表示要生成的星期数。

+0

我喜欢你的解决方案比我的解决方案简单,并且它仍然有一个单一的点,我可以改变生成几周。不过,我不知道我是否可以修改本周的第一天。 – 2010-03-09 20:49:23

+0

此外,我不知道CTE是什么,但一个快速的谷歌搜索发现这个:Common Table Expressions http://msdn.microsoft.com/en-us/library/ms186243.aspx – 2010-03-09 20:55:38

+0

等等,只是注意到:什么是查询中的'日期'表?它是否内置于SQL Server 2008中,有点像Oracle的'DUAL'表? – 2010-03-09 20:56:43