SQL 查询时按未知集合分组的查询 运行

SQL Query that groups by sets that are unknown when the query is run

我一直在尝试开发一个 suitable 查询来构建医院每年每个入院来源的入院堆积图。首先,我有一个简单的 table,其中列出了按来源和日期入院的患者:

vwAdmissons
--------------------
Source | VARCHAR(20)
Admit  | Date
--------------------

一些示例数据

Accident and Emerg    17/12/13 03:18
Ward                  17/12/13 08:16
Accident and Emerg    17/12/13 15:52
OT/recovery           17/12/13 17:10
OT/recovery           17/12/13 22:22
OT/recovery           17/12/13 22:24
Accident and Emerg    17/12/13 23:49
Ward                  18/12/14 09:16
OT/recovery           18/12/14 11:40
OT/recovery           18/12/14 16:42
Ward                  18/12/14 17:48
OT/recovery           18/12/14 19:57
OT/recovery           18/12/14 19:58
Accident and Emerg    18/12/14 22:15
OT/recovery           19/12/14 00:00
OT/recovery           19/12/14 11:49
Ward                  19/12/14 12:11
OT/recovery           19/12/14 12:47
OT/recovery           19/12/14 16:43
OT/recovery           19/12/14 17:10
OT/recovery           19/12/14 17:45
Ward                  19/12/14 17:56
OT/recovery           20/12/14 00:10
Accident and Emerg    20/12/14 04:01
OT/recovery           20/12/14 05:46
Other Hospital        20/12/14 07:49
Ward                  20/12/14 18:43

我可以 运行 SELECT 在此 table 上按年月和来源对录取来源进行分组

SELECT Count(*)                                AS Total,
       dbo.vwAdmissons.Source,
       Year(dbo.vwAdmissons.Admit)             AS AdmitYear,
       Datename(month, dbo.vwAdmissons.Admit)  AS AdmitMonth,
       Datename(month, dbo.vwAdmissons.Admit) + ' '
       + RIGHT(Year(dbo.vwAdmissons.Admit), 2) AS Monthyear
FROM   dbo.vwAdmissons
GROUP  BY Year(dbo.vwAdmissons.Admit),
          Datename(month, dbo.vwAdmissons.Admit),
          dbo.vwAdmissons.Source
ORDER  BY Year(dbo.vwAdmissons.Admit),
          Datename(month, dbo.vwAdmissons.Admit),
          dbo.vwAdmissons.Source 

这个 returns 年月和来源和计数的列表。

我真正想要的是一个年月列表,所有源都计算同一记录中的特定年月。

year-month  source1 count, source2 count, source3 count

我猜这对于未知来源列表是不可能的?

我不确定构建年月源(百分比)堆叠图的替代方法是什么?

我真正想要的输出是这样的:

year-month  |  Accident and Emerg | Ward | OT/recovery
December-13        3                1      3
January-14
February-14

真正的问题是我希望源列表是动态的 - 我认为它确实需要以某种方式进行硬编码?

感谢任何指导

正如 NoDisplayName 所建议的那样,您需要深入研究动态 sql 旋转的黑暗艺术,才能完成您想要完成的任务。

我一年必须做几次这样的查询。最终,在 Excel 枢轴 table 或 SSRS 矩阵等表示层应用程序中进行这种类型的旋转是理想的,但如果您需要在 SQL 中进行,这是一种方法。

请注意,这是老派的枢轴语法,我碰巧更喜欢新的 t-sql PIVOT 运算符。

DECLARE @MyDynamicSQL varchar(2000)

/*@LINEBREAK is just something inserted at the end of lines to make the dynamic sql more readable if it needs to be debugged*/
DECLARE @LINEBREAK AS varchar(2) = CHAR(13) + CHAR(10) 

/* Build the first line of the dynamic sql statement which is just a derived column we'll alias as "MonthYear" */
SET @MyDynamicSQL = 'SELECT [MonthYear] = Datename(month, dbo.vwAdmissons.Admit) + ''-'' + RIGHT(CAST(Year(dbo.vwAdmissons.Admit) AS varchar(4)),2) ' + @LINEBREAK

/* Append to the first line, the variable number of "Source" values that you'll want to pivot out as columns. Group By just gives the distinct list of Sources.
This syntax for building the string of columns is weird if you've never seen it before, but worth learning I think.
QUOTENAME simply ensures that the field names will be enclosed in brackets or quotes in the even that the returned values from this query contain spaces, etc.*/
SELECT @MyDynamicSQL = @MyDynamicSQL +
 ',' + QUOTENAME([Source]) + ' = COUNT(CASE [Source] WHEN ' + QUOTENAME([Source],'''') + ' THEN 1 ELSE NULL END) ' + @LINEBREAK
FROM dbo.vwAdmissons
GROUP BY [Source]

/*Rest of the dynamic SQL - same as what you had but notice there's source column in the group by*/
SET @MyDynamicSQL = @MyDynamicSQL + 'FROM   dbo.vwAdmissons
GROUP  BY Year(dbo.vwAdmissons.Admit),
          Datename(month, dbo.vwAdmissons.Admit)
ORDER  BY Year(dbo.vwAdmissons.Admit),
          Datename(month, dbo.vwAdmissons.Admit)'

PRINT (@MyDynamicSQL) --this is just for debugging/testing
EXEC(@MyDynamicSQL)