【问题标题】:How do you CASE out the unknowns?你如何排除未知数?
【发布时间】:2013-07-25 17:58:42
【问题描述】:

我在使用 CASE 语句将计数选择到多个列时遇到了问题。 CASE 语句对我的工作方式就像 C/C++ 中的 IF 语句。如果值等于 X,则执行 Y ELSE 执行 Z。

为了帮助解释这个问题,让我提供一个查询,它计算名为“Names”的列中的名称,并按“Date”列对它们进行分组。

SELECT [Date]
       COUNT( CASE WHEN [Name] = 'John' THEN 1 ELSE NULL END) AS 'John',
       COUNT( CASE WHEN [Name] = 'Joe' THEN 1 ELSE NULL END) AS 'Joe',
       COUNT( CASE WHEN [Name] = 'Moe' THEN 1 ELSE NULL END) AS 'Moe',
       COUNT( CASE WHEN [Name] = 'Nick' THEN 1 ELSE NULL END) AS 'Nick',
       COUNT( CASE WHEN [Name] = 'Zack' THEN 1 ELSE NULL END) AS 'Zack'
FROM [MyDatabase].[dbo].[LogInData]
WHERE [Date] >= '2013-07-01'
GROUP BY [Date]

这假设我知道我想数数的名字。如果我想在单行中计算查询中未定义的新名称怎么办?我怎样才能动态地搜索表中的所有 DISTINCT 名称,并像上面那样自动单独计算它们,而不必在代码中添加新名称?

感谢您提供的任何帮助。我仍在尝试学习使用 SQL 编写复杂查询的不同方法。我不是在寻找一个确切的答案,但是任何能帮助我指出正确方向的帮助都会很棒。我完全是为了学习和扩展我的知识,而不是给我的东西。

【问题讨论】:

  • 您需要使用动态 sql 来执行此操作。我建议您 select [date], [name], count(1).... 然后在您的表示层中处理枢轴。
  • 我假设你是 2008 年或更好

标签: sql sql-server database tsql pivot


【解决方案1】:

你会用另一种方式来做:

SELECT [Date], [Name], COUNT(*)
  FROM ...
  GROUP BY [Date], [Name];

那么也许你可以旋转,但你不一定要在查询中这样做。在不知道您拥有的名称(以及列数)的情况下这样做将需要动态 SQL 来构建适当的数据透视 - 但同样,您可以在表示层转置此信息并让 SQL Server 以优化的方式返回此数据去做。

也就是说,我相信 bluefeet 很快就会给出一个例子。

其实bluefeet不在了,我来填一下:

DECLARE @date DATE = '2013-07-01';

DECLARE @sql NVARCHAR(MAX) = N'', @cols NVARCHAR(MAX) = N'';

SELECT @cols += STUFF((SELECT ',' + QUOTENAME(Name)
                       FROM dbo.LoginData
                       WHERE [Date] >= @date
                       GROUP BY Name
                       FOR XML PATH('')), 1, 1, '');

SET @sql = N'SELECT *
  FROM (SELECT * FROM dbo.LoginData AS d
  WHERE [Date] >= @date
  ) AS d
  PIVOT (COUNT([Name]) FOR [Name] IN (' + @cols + ')) AS p;';

EXEC sp_executesql @sql, N'@date DATE', @date;

SQLfiddle demo

【讨论】:

  • 数据库中的视图逻辑是邪恶的。
  • 伙计,你们今天很快。我在底部添加了一点,即理想情况下并不需要确切的答案。任何可以让我了解更多关于自己解决这个问题的有用方向也足够了。但是,感谢您的快速回复!
  • @Fastidious 好吧,您还没有评论 SQL Server 是否真的要求在同一行返回这些。如果这是为了简化客户端编码,我建议您还研究如何让客户端代码以我在 group by 中展示的传统方式操作 SQL Server 提供的数据。跨度>
  • 谢谢!我会指定的。它需要在同一行中返回,以便我可以将计数水平合并为一条记录。
  • 天哪,看起来不错!我可以麻烦您让一些 cmets 解释一下这段代码是如何工作的吗?你也没有,但我想我会问,因为我试图分解你在这里做了什么。
【解决方案2】:

如果您不需要将它们全部放在一行中,那么您可以这样做:

SELECT [Date],
       [Name],
       COUNT(*)
FROM [MyDatabase].[dbo].[LogInData]
WHERE [Date] >= '2013-07-01'
GROUP BY [Date],[Name]

【讨论】:

  • 是的,需要它们在一行中。我会在我原来的问题中指定。但是,也感谢分享这个例子。这确实有助于我理解计算名字的其他方法。
猜你喜欢
  • 2017-11-28
  • 1970-01-01
  • 2019-08-30
  • 2020-08-07
  • 2022-08-19
  • 1970-01-01
  • 1970-01-01
  • 2012-06-29
  • 1970-01-01
相关资源
最近更新 更多