我有一个employee
表,其中包含列:
empid, empname
然后是一个projectplan
表,其中包含列:
planid, empid, task, start, end
如何创建如下所示的视图:
Date Emp1 Emp2 Emp3 Emp4 ..
------------------------------------------------------------
01-Jun task1 task2,task3 task2,task4 task1,task5
02-Jun task1 task2,task3 task6 task7
感谢任何帮助。
答案 0 :(得分:0)
您对任务的解释并不是那么清楚。但我知道您无法使用可变列数创建视图。您可以使用生成所需结果的动态SQL创建存储过程。在这里我的消化:
CREATE TABLE #employee (
empid int,
empname varchar(100),
CONSTRAINT PK_employee PRIMARY KEY (empid)
);
CREATE TABLE #projectplan (
planid int,
empid int,
task varchar(100),
start date,
[end] date,
CONSTRAINT PK_projectplan PRIMARY KEY (planid)
);
INSERT INTO #employee
VALUES
(1, 'John'),
(2, 'Mary')
INSERT INTO #projectplan
VALUES
(1, 1, 'Task 1', '20160110', '20160112'),
(2, 1, 'Task 2', '20160113', '20160228'),
(3, 1, 'Task 3', '20160315', '20160328'),
(4, 1, 'Task 4', '20160315', '20160328'),
(5, 2, 'Task 3', '20160315', '20160319'),
(6, 2, 'Task 4', '20160320', '20160520')
DECLARE @cols nvarchar(MAX) =
STUFF((
SELECT ',' + QUOTENAME(empname + LTRIM(STR(empid)))
FROM #employee
FOR XML PATH('')
), 1, 1, '')
EXEC ('
SELECT *
FROM (
SELECT
p.start AS [Date],
e.empname + LTRIM(STR(e.empid)) AS [Emp],
STUFF((
SELECT '','' + task
FROM #projectplan
WHERE empid = p.empid
AND start = p.start
FOR XML PATH('''')
), 1, 1, '''') AS TaskList
FROM (
SELECT DISTINCT
start,
empid
FROM #projectplan
) AS p
INNER JOIN #employee AS e ON e.empid = p.empid
) AS it
PIVOT (
MAX(TaskList) FOR Emp IN (' + @cols + ')
) AS pt')
答案 1 :(得分:0)
在视图中无法执行此操作,如果添加新员工,则需要重写它。这就是你需要动态SQL的原因。
首先我创建了带有虚拟数据的表:
SELECT * INTO #employee
FROM (VALUES
(1, 'John Smith'),
(2, 'Richard Morris'),
(3, 'Jason Campbell'),
(4, 'Anthony Watson'),
(5, 'Jeff Butler')
) as t(empid, empname)
SELECT * INTO #projectplan
FROM (VALUES
(1, 1, 'task1','2016-06-01','2016-06-07'),
(2, 2, 'task2','2016-06-01','2016-06-05'),
(3, 3, 'task3','2016-06-01','2016-06-05'),
(4, 4, 'task4','2016-06-01','2016-06-03'),
(5, 5, 'task5','2016-06-01','2016-06-04'),
(6, 2, 'task6','2016-06-02','2016-06-09'),
(7, 3, 'task7','2016-06-03','2016-06-17'),
(8, 5, 'task8','2016-06-02','2016-06-19')
) as t(planid, empid, task, [start], [end])
然后我使用CTE获取MIN([start])
和MAX([end])
之间的所有日期,以及所有员工的另一个CTE以及每个日期的任务:
;WITH cte AS (
SELECT CAST(MIN([start]) as datetime) as dateStart,
CAST(MAX([end]) as datetime) as dateEnd
FROM #projectplan
UNION ALL
SELECT DATEADD(day,1,dateStart),
dateEnd
FROM cte
WHERE dateStart < dateEnd
), res AS (
SELECT empname,
task,
c.dateStart as [date]
FROM cte c
INNER JOIN #projectplan p
ON c.dateStart between [start] and [end]
INNER JOIN #employee e
ON e.empid = p.empid
)
--And put them into `#final` temporary table
SELECT r.empname,
CAST(r.[date] as date) [date],
STUFF((SELECT ','+task
FROM res
WHERE empname = r.empname AND [date] = r.[date]
FOR XML PATH('')
),1,1,'') as tasks
INTO #final
FROM res r
所以在#final
表中我有:
empname date tasks
John Smith 2016-06-01 task1
Richard Morris 2016-06-01 task2
Jason Campbell 2016-06-01 task3
Anthony Watson 2016-06-01 task4
Jeff Butler 2016-06-01 task5
John Smith 2016-06-02 task1
Richard Morris 2016-06-02 task2,task6
Jason Campbell 2016-06-02 task3
Anthony Watson 2016-06-02 task4
Jeff Butler 2016-06-02 task5,task8
...etc
如您所见,所有跨越日期任务的员工都以逗号分隔。然后我们用动态SQL PIVOT:
DECLARE @columns nvarchar(max),
@query nvarchar(max)
SELECT @columns = STUFF(
(SELECT ',' + QUOTENAME(empname)
FROM #employee
FOR XML PATH('')),1,1,'')
SELECT @query = N'
SELECT *
FROM #final
PIVOT (
MAX(tasks) FOR empname IN ('+@columns+')
) AS pvt'
EXEC sp_executesql @query
输出:
date John Smith Richard Morris Jason Campbell Anthony Watson Jeff Butler
2016-06-01 task1 task2 task3 task4 task5
2016-06-02 task1 task2,task6 task3 task4 task5,task8
2016-06-03 task1 task2,task6 task3,task7 task4 task5,task8
2016-06-04 task1 task2,task6 task3,task7 NULL task5,task8
2016-06-05 task1 task2,task6 task3,task7 NULL task8
2016-06-06 task1 task6 task7 NULL task8
2016-06-07 task1 task6 task7 NULL task8
2016-06-08 NULL task6 task7 NULL task8
2016-06-09 NULL task6 task7 NULL task8
2016-06-10 NULL NULL task7 NULL task8
2016-06-11 NULL NULL task7 NULL task8
2016-06-12 NULL NULL task7 NULL task8
2016-06-13 NULL NULL task7 NULL task8
2016-06-14 NULL NULL task7 NULL task8
2016-06-15 NULL NULL task7 NULL task8
2016-06-16 NULL NULL task7 NULL task8
2016-06-17 NULL NULL task7 NULL task8
2016-06-18 NULL NULL NULL NULL task8
2016-06-19 NULL NULL NULL NULL task8
正如您所看到的,Richard Morris
得到了2个任务task2
,日期介于2016-06-01
和2016-06-05
以及task6
之间,时间间隔介于2016-06-02
之间2016-06-09
。因此,间隔正在交叉,task2,task6
和2016-06-02
之间显示2016-06-05
。
希望这会对你有帮助!