【问题标题】:Is it possible to group by a combination of rows?是否可以按行组合进行分组?
【发布时间】:2011-03-16 01:05:51
【问题描述】:

我有一个结果,它为我提供了从我的数据库中查询的一系列值:

Start        End
-----        ---
    1          3
    5          6
  137        139      

根据这些,我需要在数据库中查询该范围内的记录,这可能会返回如下内容:

Id    Name
----- ------
    1 foo
    2 bar
    3 baz

Id    Name
----- ------
    5 foo
    6 baz

Id    Name
----- ------
  137 foo
  138 bar
  139 baz

我想对这些结果进行分组,保留任何 id 范围,因为它们与同一事物相关。例如,1-3 与 137-139 相同,因此计数为 2,但当然,“范围”可以是 2 中的任何一个:

RangeStart   RangeEnd   Count
----------   --------   -----
       137        139       2
         5          6       1

还要注意顺序要改变分组,所以 foo/bar/baz 和 foo/baz/bar 是不一样的。

如何做到这一点?

编辑:我有开始结果(开始,结束),我只关心最终结果(范围开始,范围结束,计数)。我实际上并不需要中间结果,我只是将它们用作解释。

【问题讨论】:

  • 为什么你有 137、139、2 而不是 1、3、2?
  • 它可以是,我想为简单起见,你是对的,它应该是第一个“范围”,所以 1、3、2 也可以。我试图指出,只要它指向正确的范围,这并不重要。最后我将显示“foo, bar, baz, 2”

标签: sql tsql


【解决方案1】:

这里有两个查询:

  • 第一个连接字符串 根据范围和分组 然后显示每个的第一个范围 字符串组。它还具有 字符串的总次数 出现了。
  • 第二个显示串联的 字符串及其各自的总数。

设置:

DECLARE @Tags TABLE ( 
  TagID INT, 
  Tag   VARCHAR(3) 
)  

INSERT @Tags  
SELECT 1, 'Foo' UNION ALL 
SELECT 2, 'Bar' UNION ALL 
SELECT 3, 'Baz' UNION ALL 
SELECT 4, 'Foo' UNION ALL 
SELECT 5, 'Bar' UNION ALL
SELECT 6, 'Baz'

DECLARE @Ranges TABLE ( 
  StartRange INT,  
  EndRange   INT 
) 

INSERT @Ranges 
SELECT 1,3 UNION ALL 
SELECT 2,3 UNION ALL  
SELECT 3,4 UNION ALL 
SELECT 4,6

查询以显示第一个范围和结果:

/* Get the first start and end ranges with a match and */
/* the total number of occurences of that match        */
SELECT
  StartRange,
  EndRange,
  Total
FROM (
  SELECT
    StartRange,
    EndRange,  
    Csv,
    ROW_NUMBER() OVER (PARTITION BY Csv ORDER BY StartRange ASC)  AS RowNum,
    ROW_NUMBER() OVER (PARTITION BY Csv ORDER BY StartRange DESC) AS Total
  FROM ( 
    /* For each range and its associated Tag values, */ 
    /* Concatenate the tags together using FOR XML   */ 
    /* and the STUFF function                        */ 
    SELECT 
      StartRange, 
      EndRange, 
      ( 
      SELECT STUFF(   
      (SELECT ',' + Tag 
      FROM @Tags WHERE TagID BETWEEN r.StartRange AND r.EndRange 
      ORDER BY TagID 
      FOR XML PATH('')),1,1,'')  
      ) AS Csv 
    FROM @Ranges r
  ) t1 
) t2
WHERE RowNum = 1
ORDER BY StartRange, EndRange

/* Results */

StartRange  EndRange    Total
----------- ----------- -----
1           3           2
2           3           1
3           4           1

查询以显示连接的字符串和总计:

/* Get the concatenated tags and their respective totals */ 
SELECT
  Csv,
  COUNT(*) AS Total
FROM ( 
  /* For each range and its associated Tag values, */ 
  /* Concatenate the tags together using FOR XML   */ 
  /* and the STUFF function                        */ 
  SELECT 
    StartRange, 
    EndRange, 
    ( 
    SELECT STUFF(   
    (SELECT ',' + Tag 
    FROM @Tags WHERE TagID BETWEEN r.StartRange AND r.EndRange 
    ORDER BY TagID 
    FOR XML PATH('')),1,1,'')  
    ) AS Csv 
  FROM @Ranges r 
) t1 
GROUP BY Csv
ORDER BY Csv

/* Results */

Csv          Total
------------ -----------
Bar,Baz      1
Baz,Foo      1
Foo,Bar,Baz  2

字符串连接方法由Jeremiah Peschka提供

【讨论】:

  • 好的,它可以满足我的需要,但我确实需要第一个序列范围而不是 CSV。我实际上将它绑定到一个 BindingNavigator,当用户循环浏览时,我查询从 StartRange 到 EndRange 的名称以显示。有什么帮助吗?
  • 我注意到第一个查询中有一些冗余,因此更正了。此外,将保护此解决方案免受具有重复项(即 1,2 和 1,2)的范围行的影响。但大概可以使用主键来处理。
  • 应该说“不会被保护..”
  • 效果很好,尽管在我的情况下子查询成本确实很昂贵。我希望 SQL 只修改 CHECKSUM_AGG 函数来考虑订单。
  • 同意。我会附和另一个:SQL Server 迫切需要一个字符串连接函数,这样你就不必做这些奇怪的 XML hack。
猜你喜欢
  • 2012-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 2020-02-06
相关资源
最近更新 更多