我想在用户不执行任何任务的表中显示缺少的日期。我的表包含一些数据
CREATE TABLE Tasks
([Name] varchar(50), [UserId] int, [TaskDate] datetime)
INSERT INTO Tasks
([Name], [UserId], [TaskDate])
VALUES
('mickel',1, '2012-08-06 00:00:00'),
('mickel',1, '2012-08-07 00:00:00'),
('mickel',1, '2012-08-011 00:00:00'),
('mickel',1, '2012-08-013 00:00:00'),
('Joseph',2, '2012-08-06 00:00:00'),
('Joseph',2, '2012-08-08 00:00:00'),
('Joseph',2, '2012-08-09 00:00:00'),
('Joseph',2, '2012-08-12 00:00:00'),
('Shan', 3, '2012-08-07 00:00:00'),
('Shan', 3, '2012-08-08 00:00:00'),
('Shan', 3, '2012-08-10 00:00:00'),
('Shan', 3, '2012-08-12 00:00:00')
想要显示输出,其中每一行显示每个用户的名称和逗号分隔的缺失日期列表。
答案 0 :(得分:1)
尝试运行此查询:
select
p1.userid,
( SELECT Convert(varchar(max),taskdate, 121 ) + ' and '
FROM tasks p2
WHERE p2.userid = p1.userid
ORDER BY NAME
FOR XML PATH('') ) AS NameValues from tasks p1 group by userid
答案 1 :(得分:1)
这个SQL Fiddle创建一个内联表值函数:
IF EXISTS ( SELECT 1
FROM sys.objects
WHERE name = 'ExplodeDates'
AND type = 'IF' )
BEGIN
DROP FUNCTION dbo.ExplodeDates;
END;
GO
CREATE FUNCTION dbo.ExplodeDates
(
@StartDate datetime,
@NoDays integer
) RETURNS TABLE AS
RETURN (
SELECT TOP ( @NoDays )
DateVal = DATEADD( DAY, ROW_NUMBER() OVER (
ORDER BY s1.object_id ), @StartDate )
FROM sys.all_objects s1
CROSS JOIN sys.all_objects s2
);
GO
然后使用CTE生成结果,并使用FOR XML PATH
填充最终列。
WITH cte AS (
SELECT u.Name, u.UserId, x.DateVal
FROM ( SELECT StartDate = MIN( t.TaskDate ),
NoDays = DATEDIFF( DAY, MIN( t.TaskDate ), MAX( t.TaskDate ) )
FROM dbo.Tasks t ) p
CROSS APPLY dbo.ExplodeDates( p.StartDate, p.NoDays ) x
CROSS JOIN (SELECT DISTINCT Name, UserId
FROM dbo.Tasks ) u
LEFT JOIN dbo.Tasks t
ON u.Name = t.Name
AND u.UserId = t.UserId
AND x.DateVal = t.TaskDate
WHERE t.Name IS NULL
AND t.UserId IS NULL )
SELECT f.Name, f.UserId, LEFT( f.MissingDates, LEN( f.MissingDates ) - 1 )
FROM ( SELECT c1.Name, c1.UserId, MissingDates = (
SELECT CONVERT( VARCHAR( MAX ), DateVal, 112 ) + ', '
FROM cte c2
WHERE c2.Name = c1.NAME
AND c2.UserId = c1.UserId
ORDER BY c2.Name
FOR XML PATH( '' ) )
FROM cte c1
GROUP BY c1.Name, c1.UserId ) f
ORDER BY f.UserId;