可变列输出

时间:2012-06-12 18:35:03

标签: sql-server-2008 tsql loops while-loop case

我可以使用循环根据计算创建可变数量的列吗?

表A:列id,名称,日期,项目。它显示谁在哪一天买了一件商品。在购买商品时,名称会多次出现。 id是唯一的。

表B:有名字,请求。它显示名称何时开始工作。

(我知道如何将name与begindate联系起来,所以它不是真的在下面的伪代码中。)

表C是我想要的结果:

name   itemsday1 itemsday2 itemsday3... itemsdayn

第二栏与今天购买的物品相对应,这是在名称之前购买的物品的最后一个物品。列数需要根据最早开始的人而有所不同。我希望我的查询循环并为每天创建一个列,从begindate到今天,它计算当天名称购买的项目数。

Psuedo代码:

declare mostd INT
select datediff(dd, begindate, getdate()) as spans  into #span from B
set mostd = select max(spans) from #span

select
    name
    ,while mostd !=0
        begin
            case when???
                count(items)
            end as column.mostd
            mostd=mostd-1
        end
    end
from A (join B blah blah)
group by name

Results
NAME    column4    column3    column2    column1    column0
James   9          8          7          6          NULL
Wade    5          4          3          NULL       NULL
Bosh    2          1          NULL       NULL       NULL
Durant  0          9          8          NULL       NULL

TSQL可以这样做吗?你能帮我把它固化成真正的代码吗?感谢。

3 个答案:

答案 0 :(得分:0)

使用PIVOT运算符http://msdn.microsoft.com/en-us/library/ms177410(v=sql.105).aspx

可以实现

更新:一个例子。它受到这篇伟大文章的启发:http://dotnetgalactics.wordpress.com/2009/10/23/using-sql-server-20052008-pivot-on-unknown-number-of-columns-dynamic-pivot/

-- create table #items (id int, name varchar(40), date datetime, userid int)
-- create table #users (id int, name varchar(40), begindate datetime)

declare @dates varchar(4000)
declare @query varchar(4000)

SELECT  @dates = STUFF(( SELECT DISTINCT
                        '],[' + cast(date as varchar(30))
                        FROM    #items
                        ORDER BY '],[' + cast(date as varchar(30))
                        FOR XML PATH('')
                        ), 1, 2, '') + ']'

set @query = 'SELECT * FROM (SELECT #users.name, date FROM #items
        INNER JOIN #users ON #items.userid = #users.id) items 
        PIVOT (COUNT(date) FOR date IN (' + @dates + ')) pvt'

EXECUTE(@query)

结果:

name  2012-10-01 2012-10-02 2012-10-03 2012-10-04 2012-10-05 2012-10-06 2012-10-07

user1     0          0           1          0          0          1         0
user2     1          6           0          0          0          1         1
user3     1          1           7          0          0          3         0
user4     0          0           0          1          1          1         1

答案 1 :(得分:0)

您需要使用动态SQL来执行此操作。从

开始
DECLARE @SelectSQL varchar(max) = "SELECT name";

然后执行你的while循环,跟踪字段名称的整数计数器(如果你真的想以相反的顺序执行此操作,则需要使用DATEDIFF(day,getdate(),begindate)并向后计数)。对于要表示列的每一天,输出以下内容:

SELECT @SelectSQL = @SelectSQL + ', (SELECT COUNT(id) FROM TableA where name = TableB.name AND [date] = ''' + CONVERT(varchar, @mostd) + ''') AS column' + str(@ColumnCounter)

然后,在循环之外,您将后续查询的其余部分:

@SelectSQL = @SelectSQL + ' FROM TableB';

注意,没有连接到TableA,因为在子查询中都会处理这一点。此外,出于同样的原因,您不需要GROUP BY.

修改:哎呀,忘记了最后一部分。

要执行此操作,只需运行:

EXEC (@SelectSQL);

答案 2 :(得分:0)

SO上有一些关于动态转动数据的答案 - 这是我提供的一个,这是一个有用的东西。

sql server 2008 dynamic pivot based on ordinal value

通过使用XML PATH运算符,您还可以在结果集中获得不错的列名。