在SQL Server中按周细分

在SQL Server中按周细分,sql,sql-server-2005,sql-server-2008,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)

鉴于此查询:

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
问题:

SQL中有没有一种方法可以像下面这样编写输出?我需要整合数据。我可以复制和粘贴它们,但这是52周的数据。这不是一个有效的方法,请帮忙。我使用SQLServer2005和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进行了注释,您可以使用带有union子句的动态查询,但我要做的是创建一个临时表并将结果插入其中。然后您可以从那里选择数据并删除临时表


您的另一个选择是创建一个表,该表保留您的周的从到日期,并加入该表。这实际上是一种更好的方法,但您需要使该表与您需要的所有日期保持最新。

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


您的另一个选择是创建一个表,该表保留您的周的从到日期,并加入该表。这实际上是一种更好的方法,但您需要使该表与您需要的所有日期保持最新。

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

SELECT 
  DATEPART(WEEK, DATE_DT)
  Country AS CITZ,
  COUNT(Subject_Key) AS PEOPLE
FROM dbo.MyTable
GROUP BY 
   Country, DATEPART(WEEK, DATE_DT)
这将为您提供数字周数,但尚未提供起始日期和截止日期

或者,您可以不使用基本查询,而是将结果存储到临时表中:

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

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

SELECT 
  DATEPART(WEEK, DATE_DT)
  Country AS CITZ,
  COUNT(Subject_Key) AS PEOPLE
FROM dbo.MyTable
GROUP BY 
   Country, DATEPART(WEEK, DATE_DT)
这将为您提供数字周数,但尚未提供起始日期和截止日期

或者,您可以不使用基本查询,而是将结果存储到临时表中:

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

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

Week    StartDate   EndDate
1       10/01/2009  10/07/2009
2       10/08/2009  10/14/2009
3       10/15/2009  10/21/2009
...
…然后加入其中。您可以提前填写一次Weeks表-如果您愿意,您可以将其填写到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 

当您需要对一系列日期进行数据分析,并且可以预先构建类似的日或月表时,这通常会简化复杂的查询。如果已经对表进行了适当的索引,那么它也可以更快。这些表是星型架构数据仓库术语中的时间维度。

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

Week    StartDate   EndDate
1       10/01/2009  10/07/2009
2       10/08/2009  10/14/2009
3       10/15/2009  10/21/2009
...
…然后加入其中。您可以提前填写一次Weeks表-如果您愿意,您可以将其填写到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 
当您需要对一系列日期进行数据分析,并且可以预先构建类似的日或月表时,这通常会简化复杂的查询。如果已经对表进行了适当的索引,那么它也可以更快。这些表是星型架构数据仓库术语中的时间维度。

请尝试:

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
尝试:


救命啊!不再需要临时表,因为您可以动态生成集合,并且可以在任何日期而不是周一开始工作周

危险:写在记事本上。可能存在小错误/打字错误。不过这主意不错

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

救命啊!不再需要临时表,因为您可以动态生成集合,并且可以在任何日期而不是周一开始工作周

危险:写在记事本上。可能存在小错误/打字错误。不过这主意不错

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