我有以下在我的Oracle数据库中运行的查询,并且我想拥有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
我不介意查询是否显示当前周的开始和结束日期,或者它是否在上一周开始。
答案 0 :(得分: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
答案 1 :(得分: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
此前:
使用SET DATEFIRST命令将星期的第一天设置为星期日:
SET DATEFIRST 7
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
表示您想要生成的周数。
答案 2 :(得分: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;
但是我会提醒您,如果您的数据是日期时间,并且您要将这些边界用于查询范围,则应使用开放式范围,例如: &gt; = 03/07和&lt; 03/14。这样你就不会错过23:59:59到午夜之间发生的任何行;虽然它们可能很罕见,但它们可能很重要。
答案 3 :(得分:0)
这就是我想出的。它略显笨拙,因为它依赖于我的表中至少有一个行&gt; =我想要选择的周数。我可以稍微调整它以包括当前周。
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
...
答案 4 :(得分: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