在SQL Server中按周分解

时间:2010-11-16 16:23:12

标签: sql sql-server-2005 sql-server-2008

鉴于此查询:

DECLARE 
@FROM_DT DATETIME, 
@TO_DT     DATETIME

BEGIN
SET @FROM_DT = '10/01/2009' 
SET @TO_DT   = DATEADD(DAY,7,@FROM_DT)
--WHILE (@FROM_DT <= '10/01/2010')
WHILE (@TO_DT < '10/01/2010')


BEGIN
SELECT 
CONVERT(CHAR(10),@FROM_DT,101)               AS FROM_DT, 
CONVERT(CHAR(10),DATEADD(DAY,-1,@TO_DT),101) AS TO_DT,
COUNTRY                                      AS CITZ,
COUNT(SUBJECT_KEY)                           AS PEOPLE
FROM MYTALE
WHERE DATE_DT >=@FROM_DT
AND DATE_DT   <@TO_DT
GROUP BY COUNTRY

SET @FROM_DT = DATEADD(DAY,7,@FROM_DT)
SET @TO_DT     = DATEADD(DAY, 7,@TO_DT)
END
END

以下是我的结果:

FROM_DT TO_DT       COUNTRY PEOPLE
10/01/2009  10/07/2009  A       2
10/01/2009  10/07/2009  B       1

FROM_DT TO_DT       COUNTRY PEOPLE
10/08/2009  10/14/2009  A       1
10/08/2009  10/14/2009  C       2

 ---to
FROM_DT TO_DT       COUNTRY PEOPLE
09/23/2010  09/29/2010  A       1
09/23/2010  09/29/2010  B       3

FROM_DT TO_DT       COUNTRY PEOPLE
09/30/2010  10/06/2010  C       13
09/30/2010  10/06/2010  D       1

问题:

在SQL中有没有办法可以像下面那样编写输出? (我需要整合数据。我可以复制并粘贴它们,但这是52周的数据。不是一种有效的方法)请帮忙。我使用SQL Server 2005&amp; 2008版。

FROM_DT TO_DT       COUNTRY PEOPLE
10/01/2009  10/07/2009  A       2
10/01/2009  10/07/2009  B       1
10/08/2009  10/14/2009  A       1
10/08/2009  10/14/2009  C       2
09/23/2010  09/29/2010  A       1
09/23/2010  09/29/2010  B       3
09/30/2010  10/06/2010  C       13
----

从上面的查询中,我评论了WHILE(@FROM_DT&lt; = '10 / 01/2010')并将其替换为WHILE(@TO_DT&lt; '10 / 01/2010'),因为我想获取FY10的数据,日期从2009年10月1日开始到2010年9月30日。但是,结果仅截至2010年9月29日,不包括2010年9月30日的数据。我的查询有问题吗?请帮忙!

5 个答案:

答案 0 :(得分:2)

好吧,SQL Server有一个名为DATEPART的函数,它还可以为您提供日期的WEEK部分 - 例如:

SELECT 
  DATEPART(WEEK, DATE_DT)
  Country AS CITZ,
  COUNT(Subject_Key) AS PEOPLE
FROM dbo.MyTable
GROUP BY 
   Country, DATEPART(WEEK, DATE_DT)

这将为您提供数字周数(但尚未包含from_date和to_date)。

或者您可以单独保留基本查询,但将结果存储到临时表中:

CREATE TABLE dbo.tmp_Results(FromDT CHAR(10), ToDT CHAR(10), 
                             Country VARCHAR(100), Count INT)

然后只需将结果插入到每个运行的表中:

INSERT INTO dbo.tmp_Results(FromDT, ToDT, Country, Count)
  SELECT 
     CONVERT(CHAR(10),@FROM_DT,101)               AS FROM_DT, 
     CONVERT(CHAR(10),DATEADD(DAY,-1,@TO_DT),101) AS TO_DT,
     COUNTRY                                      AS CITZ,
     COUNT(SUBJECT_KEY)                           AS PEOPLE
  FROM MYTALE
  WHERE DATE_DT >=@FROM_DT
  AND DATE_DT   <@TO_DT
  GROUP BY COUNTRY

然后从最后的临时表中选择:

SELECT * FROM dbo.tmp_Results

答案 1 :(得分:2)

递归CTE救援!不再需要临时表,因为你可以动态生成你的设置,并且可以在任何日期而不是在星期一开始几周。

(危险:写在记事本中。可能存在轻微的错误/错别字。但是正确的想法)

WITH weeks (start, end) AS (
  select
    @from_dt as start
    dateadd(day, 7, @from_dt) as end
  UNION
  select
    dateadd(day, start, 7)
    dateadd(day, end, 7)
  from
    weeks
  where
    start < @last_dt
)
select
  w.start,
  w.end,
  c.country,
  count(c.subject_key)
from
  my_table c
  join weeks on c.date_dt >= start and c.date_dt < end
group by
  start, end, country

答案 2 :(得分:1)

您可以使用带有union子句的动态查询,但我要做的是创建一个临时表并将结果插入其中。然后你可以从那里选择数据并删除临时表。

您的另一个选择是创建一个表,该表一直保持几周的起始日期,然后加入该表。这实际上是一种首选方式,但您需要使该表与所需的所有日期保持同步。

答案 3 :(得分:0)

数据仓库的一种方法是创建一个“周”表,其中包含所有可能的周数,以及它们的开始和结束日期:

Week    StartDate   EndDate
1       10/01/2009  10/07/2009
2       10/08/2009  10/14/2009
3       10/15/2009  10/21/2009
...

...然后加入那个。您可以提前填写“周”表 - 如果需要,可以将其填写到3000年 - 然后在您的数据库中可以进行如下查询:

SELECT 
  StartDate, EndDate, COUNTRY, COUNT(SUBJECT_KEY) AS People
FROM 
  MYTALE INNER JOIN Weeks ON DATE_DT BETWEEN StartDate AND EndDate
GROUP BY 
  StartDate, EndDate, Country 

当您需要在一系列日期中进行数据分析时,这通常可以简化复杂的查询(并且您可以预先构建类似的“天”或“月”表。)假设您已编入索引,它也可以更快适当的表格。这些表是星型模式数据仓库用语中的“时间维度”。

答案 4 :(得分:0)

尝试:

DECLARE 
@FROM_DT DATETIME, 
@TO_DT     DATETIME

BEGIN
SET @FROM_DT = '10/01/2009' 
SET @TO_DT   = DATEADD(DAY,7*53,@FROM_DT)

SELECT 
CONVERT(CHAR(10),DATEADD(DAY,7*(WEEKNO),@FROM_DT),101)   AS FROM_DT, 
CONVERT(CHAR(10),DATEADD(DAY,7*(WEEKNO)+6,@FROM_DT),101) AS TO_DT,
COUNTRY                                                  AS CITZ,
COUNT(SUBJECT_KEY)                                       AS PEOPLE
(SELECT M.*, TRUNC(DATEDIFF(DAY,@FROM_DT,DATE_DT)/7) WEEKNO
 FROM MYTALE M
 WHERE DATE_DT >=@FROM_DT
 AND DATE_DT   <@TO_DT) SQ
GROUP BY COUNTRY, WEEKNO

END