使用MS SQL查询,我想折叠连续行中的冗余数据,以使报表更易于阅读。假设我有以下数据:
ID | Department | Name | Task
-------------------------------------------------
1 Sales Mike Call customer
2 Sales Mike Create quote
3 Sales Sarah Create order
4 Engineering Sam Design prototype
5 Engineering Sam Calculate loads
6 Production Team1 Build parts
7 Production Team2 Build parts
8 Production Team1 Assemble parts
9 Accounting Amy Invoice job
10 Sales Mike Call customer
11 Sales Mike Follow up after 30 days
如何从查询中获取以下汇总行:
Sales: Mike (Call customer, Create quote) Sarah (Create order)
Engineering: Sam (Design prototype, Calculate loads)
Production: Team1 (Build parts) Team2 (Build parts) Team1 (Assemble parts)
Accounting: Amy (Invoice job)
Sales: Mike (Call customer, Follow up after 30 days)
基本上,如果前一个部门和名称相同,请将任务添加到逗号分隔的子列表中。如果只有部门相同,则启动一个新的命名子列表,如果部门是新的,则开始一个新行。请注意,第10行和第11行不应包含在第一行中,以便任务顺序不会丢失。
在C#中,这个任务很容易使用循环和/或Linq,但是,我现在需要从SQL查询生成相同的结果。
答案 0 :(得分:1)
使用递归公用表表达式(working SQLFiddle example)
;with RecursivePersonTask( Id, Department, Name, Tasks )
as
(
select
a.Id
, a.Department
, a.Name
, a.Task
from
dbo.Task a
left outer join dbo.Task b
on a.Department = b.Department
and a.Name = b.Name
and a.Id = b.Id + 1
where
b.Id is null
union all
select
t.Id
, t.Department
, t.Name
, rpt.Tasks + ', ' + t.Task
from
RecursivePersonTask rpt
inner join dbo.Task t
on rpt.Department = t.Department
and rpt.Name = t.Name
and rpt.Id = t.Id - 1
)
, CombinedPersonTasks( Id, Department, Name, Tasks )
as
(
select
ROW_NUMBER() over ( order by a.Id )
, a.Department
, a.Name
, '(' + a.Tasks + ')'
from
RecursivePersonTask a
left outer join RecursivePersonTask b
on a.Department = b.Department
and a.Name = b.Name
and a.Id = b.Id - 1
where
b.Id is null
)
, RecursiveDepartmentTasks( Id, Department, Tasks )
as
(
select
a.Id
, a.Department
, a.Name + ' ' + a.Tasks
from
CombinedPersonTasks a
left outer join CombinedPersonTasks b
on a.Department = b.Department
and a.Id = b.Id + 1
where
b.Id is null
union all
select
cpt.Id
, cpt.Department
, rdt.Tasks + ' ' + cpt.Name + ' ' + cpt.Tasks
from
RecursiveDepartmentTasks rdt
inner join CombinedPersonTasks cpt
on rdt.Department = cpt.Department
and rdt.Id = cpt.Id - 1
)
, CombinedDepartmentTasks( Id, Department, Tasks )
as
(
select
ROW_NUMBER() over ( order by a.Id )
, a.Department
, a.Tasks
from
RecursiveDepartmentTasks a
left outer join RecursiveDepartmentTasks b
on a.Department = b.Department
and a.Id = b.Id - 1
where
b.Id is null
)
select
*
from
CombinedDepartmentTasks
order by
Id
答案 1 :(得分:1)
如果您有SQL Server 2012,则可以使用窗口函数的ROWS参数:
with tasks as (
select 1 as id, 'Sales' as dept ,'Mike' as name, 'Call customer' as task union
select 2, 'Sales' ,'Mike', 'Create quote' union
select 3, 'Sales' ,'Sarah', ' Create order' union
select 4, 'Engineering' ,'Sam', ' Design prototype' union
select 5, 'Engineering' ,'Sam', ' Calculate loads' union
select 6, 'Production' ,'Team1', ' Build parts' union
select 7, 'Production' ,'Team2', ' Build parts' union
select 8, 'Production' ,'Team1', ' Assemble parts' union
select 9, 'Accounting' ,'Amy', ' Invoice job' union
select 10, 'Sales' ,'Mike', ' Call customer' union
select 11, 'Sales' ,'Mike', ' Follow up after 30 days'
)
select max(NewDepartmentRollover) over (order by id rows unbounded preceding) as ColumnToGroupOn , * from (
select
case when max(dept) over (order by id rows between 1 preceding and 1 preceding) = dept then NULL else id end as NewDepartmentRollover,
* from tasks
) GroupOn
如果您只有SQL Server 2005或2008,则会执行以下操作:
with tasks as (
select 1 as id, 'Sales' as dept ,'Mike' as name, 'Call customer' as task union
select 2, 'Sales' ,'Mike', 'Create quote' union
select 3, 'Sales' ,'Sarah', ' Create order' union
select 4, 'Engineering' ,'Sam', ' Design prototype' union
select 5, 'Engineering' ,'Sam', ' Calculate loads' union
select 6, 'Production' ,'Team1', ' Build parts' union
select 7, 'Production' ,'Team2', ' Build parts' union
select 8, 'Production' ,'Team1', ' Assemble parts' union
select 9, 'Accounting' ,'Amy', ' Invoice job' union
select 10, 'Sales' ,'Mike', ' Call customer' union
select 11, 'Sales' ,'Mike', ' Follow up after 30 days'
)
, b as (
select
row_number() over (order by tasks.id) as rn,
tasks.id as lefty
from tasks
left join tasks t3
on t3.id = tasks.id - 1
where tasks.dept <> isnull(t3.dept,'')
)
select tasks.*, lefty as columnToGroupOn from tasks left join (
select b.lefty, isnull(b2.lefty,999)-1 as righty from b
left join
b b2 on b.rn = b2.rn - 1
) c
on tasks.id between lefty and righty