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

时间:2015-01-24 05:18:46

标签: sql sql-server jasper-reports

我一直在努力开发一个合适的查询,用于为医院建立每年每个入院来源的叠加图表。首先,我有一个简单的表格,列出了按来源和日期入院的患者:

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,按年份和源

分组入场资源
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 

这将返回年月的列表以及来源和计数。

我真正想要的是年度月份列表,其中所有来源都计入同一记录中特定年份。

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

问题实际上是我希望源列表是动态的 - 我认为它确实需要硬编码?

任何指导意见

1 个答案:

答案 0 :(得分:1)

正如NoDisplayName建议的那样,你需要深入研究动态sql pivoting的黑暗艺术来做你想要完成的事情。

我每年要做几次这样的查询。最终,在表格层应用程序(如Excel数据透视表或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)