3

在某些应用程序中,我使用以下 sql 查询,

SELECT DATE, 
SUM( CASE WHEN project_id =  '6' THEN spent_time  ELSE 0 END ) project_1, 
SUM( CASE WHEN project_id =  '41' THEN spent_time  ELSE 0 END ) project_2, 
SUM( CASE WHEN project_id =  '14' THEN spent_time ELSE 0 END ) project_3
FROM tasks
WHERE user_id =80
GROUP BY DATE, project_id

它返回以下输出

在此处输入图像描述

但在上面的 SQL 查询中,我使用了预定义的列。我正在寻找一个解决方案,其中我有动态列说我事先不知道项目 ID。

我还想要一个额外的列,显示每一行的 project_1、project_2、project_3 的总和。

因此,结果结构将是 DATE、PROJECT_1、PROJECT_2、PROJECT_3、SUM_OF_PROJECTS

我还可以获取该行不存在的数据吗?例如2012-04-03在下面的例子中。最好不要使用日历表

任何指针将不胜感激。

其他细节:数据库-mysql、Rails(2.3.14)

4

3 回答 3

2

我不确定您使用的是什么数据库引擎,但下面的示例使用 Microsoft SQL Server。我相信它可以很容易地适应其他引擎。

首先,我使用以下查询创建了一些设置数据:

create table tasks(
[id] int not null identity(1,1),
[DATE] smalldatetime not null,
project_id int not null,
spent_time int not null,
primary key ([id])
)
go
insert into tasks([date],project_id,spent_time)
select '2012-04-02',1,10
union all select '2012-04-02',1,5
union all select '2012-04-02',2,5
union all select '2012-04-03',1,8
union all select '2012-04-03',2,1
go

正如上面评论中提到的,您需要动态生成 SQL 语句。我在变量@sql 中执行此操作,然后在最后执行它。这是我的解决方案:

declare @sql nvarchar(4000), @project_id nvarchar(10)
select @sql = 'select [date]'

declare c cursor for select distinct convert(nvarchar(10),project_id) as project_id from tasks order by project_id
open c
fetch c into @project_id
while @@FETCH_STATUS = 0
begin
    select @sql = @sql + ', sum(case when project_id = ' + @project_id + ' then spent_time else 0 end) as project_' + @project_id
    fetch c into @project_id
end
close c
deallocate c

select @sql = @sql + ', sum(spent_time) as sum_of_projects from tasks group by [date] order by [date]'
exec (@sql)

正如我的测试数据所预期的那样,它会生成输出:

date        project_1  project_2
----        ---------  ---------
2012-04-02  15         5
2012-04-03  8          1

希望这可以帮助!

更新

OP 已经表示希望避免使用游标,因此以下代码也可以在不使用游标的情况下工作(至少在 MS SQL Server 上)......

declare @sql nvarchar(4000), @project_id nvarchar(10)
select @sql = 'select [date]'

select @sql = @sql + ', sum(case when project_id = ' + project_id + ' then spent_time else 0 end) as project_' + project_id
from (select distinct CONVERT(nvarchar(10), project_id) as project_id from tasks) q

select @sql = @sql + ', sum(spent_time) as sum_of_projects from tasks group by [date] order by [date]'
exec (@sql)
于 2012-04-26T10:54:15.327 回答
1

您需要编写写入 SQL 的代码。没有办法让单个静态 SQL 查询返回动态列数。只有通过动态构建查询本身,您才能做到这一点。

您的示例代码很好。对于固定数量的项目。

您甚至可以将“6”、“41”和“14”作为参数,这意味着您的查询将始终返回三个项目,但每次它们可能是不同的项目。

但是要拥有第四个项目,您需要更改查询。

您可以编写代码以动态进行更改(动态 SQL),或者一次计算出您需要的最多列,然后忍受该限制。

于 2012-04-26T10:52:52.543 回答
0

您可以尝试使用枢轴。查看http://blogs.msdn.com/b/spike/archive/2009/03/03/pivot-tables-in-sql-server-a-simple-sample.aspx以获取示例

于 2012-04-26T10:45:22.457 回答