【问题标题】:SQL Query that groups by sets that are unknown when the query is run运行查询时按未知集分组的 SQL 查询
【发布时间】:2015-01-24 05:18:45
【问题描述】:

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

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

问题真的是我希望源列表是动态的 - 我认为它真的需要硬编码吗?

任何指导表示赞赏

【问题讨论】:

  • 您的表格只有一个 source 列,因此您将从哪里获得 source1,source2,etc..
  • 来源是一个变量,因此在 12 月 10 日 11:45 时有来自 ED 的入院,在 12 月 10 日的 12:00 有来自病房的入院。源可以随时间变化 - 即可以将更多源添加到系统中
  • 好的,源列是否具有固定的值集,例如 Ed、Ward 等。
  • 不是真的 - 可以添加新值,尽管这种情况很少见
  • 您需要使用Dynamic Pivot。可以加sample data和expected output吗。

标签: sql sql-server jasper-reports


【解决方案1】:

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

我必须每年做几次这样的查询。最终,在表示层应用程序(如 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)

【讨论】:

  • 这真的很有帮助!非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-16
  • 2015-01-12
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
  • 2020-06-05
  • 2019-04-03
相关资源
最近更新 更多