需要帮助来编写查询

Need help to write a query

我需要编写一个查询来获取分配给特定项目的任期。

我有一个 table 的日常活动,它以以下格式存储公司中每个人的数据以及他们对项目的分配。

这里显示员工E123每天在各种项目上的分配情况。

查询应return未分配员工的开始日期和结束日期。 例如。在上述情况下,它应该 return

按项目分组 return 只有一条记录的开始日期为 2019 年 6 月 21 日,结束日期为 2019 年 6 月 27 日,任期为 7 天,这是错误的。

试过这个:

select EmpCode, ProjectId, min(Date), max(Date), count(EmpCode)
where Date between cast('2019-04-01 00:00:00.000' as datetime) and getdate() --and s.ProjectId = 0
        and EmpId = 'E123'
group by EmpCode, ProjectId, Date

认为这就是您要找的:

DECLARE @Data TABLE
    (
    EmpId nVARCHAR(8),
    ProjectId nVARCHAR(3),
    Date DATE
    )

INSERT INTO @Data
(EmpId, ProjectId, Date)
VALUES
('EMP123', 'P1', '2019-06-18'),
('EMP123', 'P1', '2019-06-19'),
('EMP123', 'P1', '2019-06-20'),
('EMP123', NULL, '2019-06-21'),
('EMP123', NULL, '2019-06-22'),
('EMP123', NULL, '2019-06-23'),
('EMP123', 'P2', '2019-06-24'),
('EMP123', 'P2', '2019-06-25'),
('EMP123', NULL, '2019-06-26'),
('EMP123', NULL, '2019-06-27')

SELECT 
    MIN(d.Date) As StartDate,
    ISNULL(EndDate, MAX(Date)) As EndDate,
    DATEDIFF(d, MIN(d.Date), ISNULL(EndDate, MAX(Date))) + 1 As Tenure
FROM @Data d 
OUTER APPLY (SELECT TOP 1 DATEADD(d, -1, Date) As EndDate FROM @Data a WHERE a.EmpId = d.EmpId AND a.ProjectId IS NOT NULL AND a.Date > d.Date ORDER BY a.Date ASC) EndDate
WHERE
    d.ProjectId IS NULL
GROUP BY d.EmpId, d.ProjectId, EndDate

一种不同的(也是更常见的)方法是使用 ROW_NUMBER 和 CTE 创建孤岛(组)。这避免了对您的数据进行第二次扫描 table。然后,您可以对员工和组进行分组以获得最小值和最大值:

DECLARE @Data table (EmpId char(6),
                     ProjectId char(2),
                     [Date] date);

INSERT INTO @Data (EmpId,
                   ProjectId,
                   Date)
VALUES ('EMP123', 'P1', '2019-06-18'),
       ('EMP123', 'P1', '2019-06-19'),
       ('EMP123', 'P1', '2019-06-20'),
       ('EMP123', NULL, '2019-06-21'),
       ('EMP123', NULL, '2019-06-22'),
       ('EMP123', NULL, '2019-06-23'),
       ('EMP123', 'P2', '2019-06-24'),
       ('EMP123', 'P2', '2019-06-25'),
       ('EMP123', NULL, '2019-06-26'),
       ('EMP123', NULL, '2019-06-27');

WITH Grps AS (
    SELECT D.EmpId,
           D.ProjectId,
           D.[Date],
           ROW_NUMBER() OVER (PARTITION BY D.EmpId ORDER BY D.Date) -
           ROW_NUMBER() OVER (PARTITION BY D.EmpId, D.ProjectId ORDER BY D.Date) AS Grp
    FROM @Data D)
SELECT G.EmpId,
       MIN(G.[Date]) AS StartDate,
       MAX(G.[Date]) AS EndDate,
       DATEDIFF(DAY,MIN(G.[Date]),MAX(G.[Date]))+1 AS Tenure
FROM Grps G
WHERE G.ProjectId IS NULL
GROUP BY G.EmpId,
         G.Grp;

(感谢 Koen Vissers,提供可消耗的样本数据。)

对我来说,这看起来像是一个相对简单的聚合查询。唯一的挑战是识别组。

不过,那也简单。它只是非 NULL projectid 值的累积数量:

select empid, min(date), max(date), count(*) as tenure
from (select d.*,
             count(projectid) over (partition by empid order by date) as grp
      from @data d
     ) d
where projectid is null
group by empid, grp
order by empid, min(date);

Here 是一个 db<>fiddle.

试试这个 >>

    SELECT EMP_PRO.EmpCode,
       EMP_PRO.ProjectId,
       Date_M.min_D StartDate,
       Date_M.max_D EndDate,
       Date_M.tenure
  FROM EMP_PRO
       LEFT OUTER JOIN
       (SELECT min (date) min_D, max (Date) max_D, count (Grp) tenure , ProjectId
          FROM (SELECT id,
                       ProjectId,
                       date,
                         DENSE_RANK () OVER (ORDER BY id)
                       - DENSE_RANK ()
                            OVER (PARTITION BY ProjectId ORDER BY id)
                          AS Grp
                  FROM EMP_PRO) T
        GROUP BY T.Grp ,ProjectId) Date_M
          ON EMP_PRO.date = Date_M.min_D
 WHERE Date_M.min_D IS NOT NULL AND EMP_PRO.ProjectId IS NULL