我一直在努力开发一个合适的查询,用于为医院建立每年每个入院来源的叠加图表。首先,我有一个简单的表格,列出了按来源和日期入院的患者:
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
问题实际上是我希望源列表是动态的 - 我认为它确实需要硬编码?
任何指导意见
答案 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)