【问题标题】:Mimic group_concat() combined with GROUP BY模仿 group_concat() 结合 GROUP BY
【发布时间】:2012-04-24 13:25:11
【问题描述】:

我有一张这样的“预订”桌子:

booking_id,
date,
client,
sponsor

我正在尝试获取每月摘要:

SELECT 
  MONTH(date) AS M,
  Sponsor,
  Client,
  COUNT(booking_id) AS c
FROM booking
GROUP BY
 M, Sponsor, Client

现在我想查看客户在哪个日期进行了预订。我尝试使用 STUFF()(在这篇文章中引用:Simulating group_concat MySQL function in Microsoft SQL Server 2005?),但它与 group-by 语句冲突。

根据请求采样数据。目前我有以下内容:

M       Sponsor     Client  c     
March   AB          y       3
March   FE          x       4
April   AB          x       2

期望的输出:

M       Sponsor     Client  c   dates
March   AB          y       3   12, 15, 18
March   FE          x       4   16, 19, 20, 21
April   AB          x       2   4, 8

其中的数字是天数(例如 3 月 12 日、3 月 15 日、3 月 18 日)。在 mysql 中,我会使用 group_concat(date) 来获取最后一列。

非常感谢答案:-)

【问题讨论】:

  • 除了显示您当前正在运行的查询之外,您能否显示一些示例数据和所需的结果?单词问题和对现有查询进行逆向工程都是有趣的练习,但是将整个问题可视化可能会带来更好的解决方案。
  • @Lennart - 好的,但是你想要的输出是什么?
  • @Lamak:列在“所需”下。我正在努力获得最后一列,日期。在 mysql 中你会使用 group_concat 但在 t-sql 中没有这样的东西。
  • 抱歉有点不清楚。
  • 12、15、18从何而来?有没有你不包括的样本数据?当我们要求提供样本数据时,我们并不是指您每月汇总查询的结果。预订表中实际有什么(只是有助于所需输出的行)?

标签: sql-server sql-server-2008 tsql group-by


【解决方案1】:
SELECT [Month] = DATENAME(MONTH, M), Sponsor, Client, c,
  [dates] = STUFF((SELECT N', ' + RTRIM(DATEPART(DAY, [date])) 
    FROM dbo.booking AS b
    WHERE b.Sponsor = x.Sponsor
      AND b.Client = x.Client
      AND b.[date] >= x.M AND b.[date] < DATEADD(MONTH, 1, x.M) 
    ORDER BY [date]
    FOR XML PATH(''),
    TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 2, N'')
FROM 
(
  SELECT 
      M = DATEADD(MONTH, DATEDIFF(MONTH, '19000101', [date]), '19000101'),
      Sponsor,
      Client,
      COUNT(booking_id) AS c
    FROM dbo.booking
    GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, '19000101', [date]), '19000101'),
      Sponsor,
      Client
) AS x
ORDER BY M, Sponsor, Client;

请注意,如果赞助商/客户组合在同一天有两个预订,则日期编号将出现在列表中两次。

编辑这是我的测试方法:

DECLARE @booking TABLE
( 
  booking_id INT IDENTITY(1,1) PRIMARY KEY,
  [date] DATE,
  Sponsor VARCHAR(32),
  Client VARCHAR(32)
);

INSERT @booking([date], Sponsor, Client) VALUES
('20120312','AB','y'), ('20120315','AB','y'), ('20120318','AB','y'),
('20120316','FE','x'), ('20120319','FE','x'), ('20120321','FE','x'), 
('20120320','FE','x'), ('20120404','AB','x'), ('20120408','AB','x');

SELECT [Month] = DATENAME(MONTH, M), Sponsor, Client, c,
  [dates] = STUFF((SELECT ', ' + RTRIM(DATEPART(DAY, [date])) 
    FROM @booking AS b
    WHERE b.Sponsor = x.Sponsor
      AND b.Client = x.Client
      AND b.[date] >= x.M AND b.[date] < DATEADD(MONTH, 1, x.M) 
    ORDER BY [date]
    FOR XML PATH(''),
    TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 2, N'')
FROM 
(
  SELECT 
      M = DATEADD(MONTH, DATEDIFF(MONTH, '19000101', [date]), '19000101'),
      Sponsor,
      Client,
      COUNT(booking_id) AS c
    FROM @booking
    GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, '19000101', [date]), '19000101'), 
      Sponsor, 
      Client
) AS x
ORDER BY M, Sponsor, Client;

结果:

Month   Sponsor Client  c       dates
------- ------- ------- ------- --------------
March   AB      y       3       12, 15, 18
March   FE      x       4       16, 19, 20, 21
April   AB      x       2       4, 8

【讨论】:

  • 谢谢亚伦。我必须稍微调整一下(数据库当然是标准化的),但到目前为止我很高兴:-)
  • 请注意,此方法虽然广受欢迎,但使用了 FOR XML PATH('') 的未记录行为。这意味着 Microsoft 既不测试也不保证它将继续以这种方式运行,也不保证它是确定性的。 Microsoft 对此问题的回答仍然是“这是应用程序问题,而不是数据库问题”。尽管 RDBMS 世界的其他部分已经实现了这种类型的功能。
  • @BaconBits 当然。你可能会觉得 the comments on these posts 很有趣。
  • @AaronBertrand 我只是喜欢指出它从根本上说是一种错误的方法,因为作者不支持它(即使支持代表建议它作为一种解决方法)。如果开发人员不知道它是无证的,因此不受支持,他们就不会像几年前那样向微软施加压力,要求他们只实施GROUP_CONCAT() [OVER()]。 Microsoft Connect 有完整个字符串聚合请求,MS 继续忽略它们。开发人员应该对此感到愤怒,不接受使用完全不相关的功能的令人震惊的晦涩语法的变通方法。
猜你喜欢
  • 1970-01-01
  • 2014-04-22
  • 2013-12-18
  • 2011-07-22
  • 1970-01-01
  • 2020-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多