将不重叠数据的多行合并为一行 SQL 服务器

Merge multiple rows without overlapping data into one row SQL Server

我有一个数据 table,数据如下:

ID Task time
Jim sleep 5:50
Jim wakeup 7:15
Bob sleep 6:00
Bob brushteeth 8:00
Bob eat 9:00

我是运行一个生成以下内容的查询

SELECT 
    dbo.Person.ID, 
    CAST(CASE WHEN dbo.DailyActivities.Activity = 'sleep' THEN 1 ELSE 0 END AS bit) AS slept, 
    CAST(CASE WHEN dbo.DailyActivities.Activity = 'wakeup' THEN 1 ELSE 0 END AS bit) AS wokeup, 
    CAST(CASE WHEN dbo.DailyActivities.Activity = 'brushteeth' THEN 1 ELSE 0 END AS bit) AS brushedteeth, 
    CAST(CASE WHEN dbo.DailyActivities.Activity = 'eat' THEN 1 ELSE 0 END AS bit) AS ate
FROM 
    dbo.Person 
LEFT OUTER JOIN
    dbo.DailyActivities ON dbo.Person.ID = dbo.DailyActivities.ID
ID slept wokeup brushedteeth ate
Jim TRUE FALSE FALSE FALSE
Jim FALSE TRUE FALSE FALSE
Bob TRUE FALSE FALSE FALSE
Bob FALSE FALSE TRUE FALSE
Bob FALSE FALSE FALSE TRUE

我们如何获得如下所示每行 1 个 ID 的结果

ID slept wokeup brushedteeth ate
Jim TRUE TRUE FALSE FALSE
Bob TRUE FALSE TRUE TRUE

最简单的方法是使用 DISTINCT + 子查询 + CASE。我稍微简化了您的查询,所以没有加入等,所以我必须少输入一些。但我希望它背后的概念是清楚的。

SELECT DISTINCT
    p.[ID]
  , CASE
      WHEN (SELECT COUNT(*) FROM [dbo].[Person] sub WHERE sub.[ID] = p.[ID] AND sub.[Task] = 'slept') > 0 THEN CAST(1 as bit)
      ELSE CAST(0 as bit)
    END AS [slept]
  , CASE
      WHEN (SELECT COUNT(*) FROM [dbo].[Person] sub WHERE sub.[ID] = p.[ID] AND sub.[Task] = 'wakeup') > 0 THEN CAST(1 as bit)
      ELSE CAST(0 as bit)
    END AS [wokeup]
  , CASE
      WHEN (SELECT COUNT(*) FROM [dbo].[Person] sub WHERE sub.[ID] = p.[ID] AND sub.[Task] = 'brushteeth') > 0 THEN CAST(1 as bit)
      ELSE CAST(0 as bit)
    END AS [brushteeth]
  , CASE
      WHEN (SELECT COUNT(*) FROM [dbo].[Person] sub WHERE sub.[ID] = p.[ID] AND sub.[Task] = 'eat') > 0 THEN CAST(1 as bit)
      ELSE CAST(0 as bit)
    END AS [ate]
FROM [dbo].[Person] p

正如我在评论中提到的,在 CASE 表达式周围使用 MAX;这称为条件聚合:

SELECT P.ID, 
       CAST(MAX(CASE WHEN DA.Activity = 'sleep' THEN 1 ELSE 0 END) AS bit) AS slept, 
       CAST(MAX(CASE WHEN DA.Activity = 'wakeup' THEN 1 ELSE 0 END) AS bit) AS wokeup, 
       CAST(MAX(CASE WHEN DA.Activity = 'brushteeth' THEN 1 ELSE 0 END) AS bit) AS brushedteeth, 
       CAST(MAX(CASE WHEN DA.Activity = 'eat' THEN 1 ELSE 0 END) AS bit) AS ate
FROM dbo.Person P
     LEFT OUTER JOIN dbo.DailyActivities DA ON P.ID = DA.ID
GROUP BY P.ID

此外,正如我在评论中提到的,我删除了列上的 3+ 部分命名,因为它 will be deprecated