如何从每个用户的表组中查找缺少的日期?

时间:2014-02-11 18:10:00

标签: c# asp.net sql-server tsql

我想在用户不执行任何任务的表中显示缺少的日期。我的表包含一些数据

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')

想要显示输出,其中每一行显示每个用户的名称和逗号分隔的缺失日期列表。

2 个答案:

答案 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;