PIVOT SQL Server帮助

时间:2011-02-25 10:34:37

标签: sql sql-server sql-server-2005 tsql pivot

给出以下表结构:

CrimeID | No_Of_Crimes  |   CrimeDate    | Violence | Robbery | ASB

1            1             22/02/2011         Y          Y      N

2            3             18/02/2011         Y          N      N

3            3             23/02/2011         N          N      Y

4            2             16/02/2011         N          N      Y

5            1             17/02/2011         N          N      Y

是否有可能使用T-SQL生成与此类似的结果集?

Category   |  This Week |  Last Week
Violence          1           3
Robbery           1           0
ASB               3           1

如果上周的数据低于'20 / 02/2011',本周应该大于或等于'20 / 02/2011'

我不是在寻找有人为我编写代码,虽然代码片段会很方便:),只是一些关于这是否可行的建议,以及我应该如何使用SQL Server。

有关信息,我目前正在使用Web服务器上的LINQ执行所有此聚合,但这需要在每次发出此请求时通过网络发送19MB。 (该表有很多类别,并且> 150,000行)。我想让数据库完成所有工作,只通过网络发送少量数据

非常感谢

3 个答案:

答案 0 :(得分:3)

为清晰起见,

编辑删除了错误的sql 编辑忘记上面的尝试以下

select * 
from (
select wk, crime, SUM(number) number
from (
    select case when datepart(week, crimedate) = datepart(week, GETDATE()) then 'This Week'
            when datepart(week, crimedate) = datepart(week, GETDATE())-1 then 'Last Week'
            else 'OLDER' end as wk, 
            crimedate, 
            case when violence ='Y' then no_of_crimes else 0 end as violence, 
            case when robbery ='Y' then no_of_crimes else 0 end as robbery, 
            case when asb ='Y' then no_of_crimes else 0 end as asb 
    from crimetable) as src
UNPIVOT
    (number for crime in 
    (violence, robbery, asb)) as pivtab
group by wk, crime
) z
PIVOT
( sum(number)
for wk in ([This Week], [Last Week])
) as pivtab

答案 1 :(得分:2)

晚会,但是具有最佳查询计划的解决方案:

示例数据

create table crimes(
    CrimeID int, No_Of_Crimes int, CrimeDate datetime,
    Violence char(1), Robbery char(1), ASB char(1));
insert crimes
select 1,1,'20110221','Y','Y','N' union all
select 2,3,'20110218','Y','N','N' union all
select 3,3,'20110223','N','N','Y' union all
select 4,2,'20110216','N','N','Y' union all
select 5,1,'20110217','N','N','Y';

制作更多数据 - 除了上面的5个之外,总共约10240行,每个5个在前一个5之前的2周。还创建一个有助于crimedate的索引。

insert crimes
select crimeId+number*5, no_of_Crimes, DATEADD(wk,-number*2,crimedate),
violence, robbery, asb
from crimes, master..spt_values
where type='P'

create index ix_crimedate on crimes(crimedate)

从这里开始,检查每个的输出以查看它的去向。还要检查执行计划。

Standard Unpivot打破类别。

select CrimeID, No_Of_Crimes, CrimeDate, Category, YesNo
from crimes
unpivot (YesNo for Category in (Violence,Robbery,ASB)) upv
where YesNo='Y'

注意:

  1. YesNo上的过滤器实际上是在取消隐藏后应用的。你可以发表评论看看。
  2. 再次展开,但这次只选择上周和本周的数据。

    select CrimeID, No_Of_Crimes, Category,
        Week = sign(datediff(d,CrimeDate,w.firstDayThisWeek)+0.1)
    from crimes
    unpivot (YesNo for Category in (Violence,Robbery,ASB)) upv
    cross join (select DATEADD(wk, DateDiff(wk, 0, getdate()), 0)) w(firstDayThisWeek)
    where YesNo='Y'
      and CrimeDate >= w.firstDayThisWeek -7
      and CrimeDate <  w.firstDayThisWeek +7
    

    注意:

    1. (select DATEADD(wk, DateDiff(wk, 0, getdate()), 0)) w(firstDayThisWeek)创建一个单列表,其中列包含此查询的关键日期,即当前周的第一天(使用DATEFIRST设置)
    2. 在解锁之前,CrimeDate上的过滤器实际应用于BASE TABLE。检查计划
    3. Sign()只是将数据分成3个桶(-1 / 0 / + 1)。添加+0.1可确保只有两个桶-1和+1。
    4. 最终查询,按此/上周转动

      select Category, isnull([1],0) ThisWeek, isnull([-1],0) LastWeek
      from
      (
          select Category, No_Of_Crimes,
              Week = sign(datediff(d,w.firstDayThisWeek,CrimeDate)+0.1)
          from crimes
          unpivot (YesNo for Category in (Violence,Robbery,ASB)) upv
          cross join (select DATEADD(wk, DateDiff(wk, 0, getdate()), -1)) w(firstDayThisWeek)
          where YesNo='Y'
            and CrimeDate >= w.firstDayThisWeek -7
            and CrimeDate <  w.firstDayThisWeek +7
      ) p
      pivot (sum(No_Of_Crimes) for Week in ([-1],[1])) pv
      order by Category Desc
      

      输出

      Category  ThisWeek    LastWeek
      --------- ----------- -----------
      Violence  1           3
      Robbery   1           0
      ASB       3           3
      

答案 2 :(得分:0)

我会试试这个:

declare @FirstDayOfThisWeek date = '20110220';
select cat.category, 
       ThisWeek = sum(case when cat.CrimeDate >= @FirstDayOfThisWeek
                     then crt.No_of_crimes else 0 end), 
       LastWeek = sum(case when cat.CrimeDate >= @FirstDayOfThisWeek
                     then 0 else crt.No_of_crimes end)
from crimetable crt
cross apply (values 
    ('Violence', crt.Violence),
    ('Robbery', crt.Robbery),
    ('ASB', crt.ASB))
    cat (category, incategory)
where cat.incategory = 'Y'
  and crt.CrimeDate >= @FirstDayOfThisWeek-7
group by cat.category;