且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在SQL Server中将多行员工合并为单行

更新时间:2023-02-06 07:57:52

示例数据:

CREATE TABLE #Test
(
    EmpNo INT
    , Name VARCHAR(255)
    , Benefit VARCHAR(255)
    , StartDate DATETIME2
    , Status VARCHAR(255)
);
INSERT INTO #Test
    (EmpNo, Name, Benefit, StartDate, Status)
VALUES
    (0001, 'ABC', 'Medical', '01/01/2014', 'Active')
    , (0001, 'ABC', 'Dental', '02/02/2013', 'Inactive')
    , (0001, 'ABC', 'Vision', '03/03/2012', 'Active')
    , (0002, 'XYZ', 'Medical', '01/01/2014', 'Active')
    , (0002, 'XYZ', 'Dental', '02/02/2008', 'Inactive')

还有一个简单的group子句:

And a simple group clause:

实际查询(如果有历史记录),使用ROW_NUMBER将使您找到每个用户及其利益的最新记录:

SELECT T.EmpNo
    , T.Name
    , MAX(CASE WHEN T.Benefit = 'Medical ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS MedStart
    , MAX(CASE WHEN T.Benefit = 'Medical' THEN T.Status END) AS MedStatus
    , MAX(CASE WHEN T.Benefit = 'Dental ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS DenStart
    , MAX(CASE WHEN T.Benefit = 'Dental' THEN T.Status END) AS DenStatus
    , MAX(CASE WHEN T.Benefit = 'Vision ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS VisStart
    , MAX(CASE WHEN T.Benefit = 'Vision' THEN T.Status END) AS VisStatus
FROM (
    SELECT ROW_NUMBER() OVER (PARTITION BY EmpNo, Name, Benefit ORDER BY StartDate DESC) AS RowNo
        , EmpNo
        , Benefit
        , Name
        , StartDate
        , Status
    FROM #Test
) AS T
WHERE T.RowNo = 1
GROUP BY T.EmpNo
    , T.Name

使用动态SQL查询是否有未知数量的权益.可能效率不高:

DECLARE @SQL NVARCHAR(MAX) = 'SELECT T.EmpNo, T.Name'
    , @Benefit VARCHAR(MAX);

SELECT @SQL += ', MAX(CASE WHEN T.Benefit = ''' + Benefit + ''' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS ' + LEFT(Benefit, 3) + 'Star
                , MAX(CASE WHEN T.Benefit = ''' + Benefit + ''' THEN T.Status END) AS ' + LEFT(Benefit, 3) + 'Status'
FROM (SELECT DISTINCT Benefit FROM #Test) AS T

SET @SQL += '
FROM (
    SELECT ROW_NUMBER() OVER (PARTITION BY EmpNo, Name, Benefit ORDER BY StartDate DESC) AS RowNo, EmpNo, Benefit, NAME, StartDate, STATUS
    FROM #Test
    ) AS T
WHERE T.RowNo = 1
GROUP BY T.EmpNo, T.Name'

EXEC sp_executesql @SQL

查询(如果没有历史记录):

SELECT T.EmpNo
    , T.Name
    , MAX(CASE WHEN T.Benefit = 'Medical ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS MedStart
    , MAX(CASE WHEN T.Benefit = 'Medical' THEN T.Status END) AS MedStatus
    , MAX(CASE WHEN T.Benefit = 'Dental ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS DenStart
    , MAX(CASE WHEN T.Benefit = 'Dental' THEN T.Status END) AS DenStatus
    , MAX(CASE WHEN T.Benefit = 'Vision ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS VisStart
    , MAX(CASE WHEN T.Benefit = 'Vision' THEN T.Status END) AS VisStatus
FROM #Test AS T
GROUP BY T.EmpNo
    , T.Name

输出:

EmpNo   Name    MedStart    MedStatus   DenStart    DenStatus   VisStart    VisStatus
-------------------------------------------------------------------------------------
1       ABC     01/01/2014  Active      02/02/2013  Inactive    03/03/2012  Active
2       XYZ     01/01/2014  Active      02/02/2008  Inactive    NULL        NULL