【问题标题】:SQL Aggregation for a smaller result set较小结果集的 SQL 聚合
【发布时间】:2009-10-06 19:37:37
【问题描述】:

我有一个数据库,我需要将记录聚合到另一个较小的集合中。此结果集应包含原始记录的特定列的最大值和最小值之间的差,它们加起来为某个 SUM,即闭区间常数 C。

常数 C 决定了原始记录的聚合方式,结果集中的任何条目都不会超过它。自然我应该以自然主键顺序运行它..

为了说明:表有:

  • [键]
  • [a]
  • [b]
  • [分钟列]
  • [最大列]
  • [N]

...都是 int 数据类型。

我正在寻找一个结果集,其中包含该组的 MAX(maxColumn) - MIN(minColumn) 的条目,这样当它们的差值相加时,它小于或等于常数 C。

除了 MAX(maxColumn) 和 MIN(minColumn) 值之外,在此结果集中创建新条目之前,我还需要 FIRST 记录列 [a] 和 LAST 记录列 [b] 值。最后,N 列应该对组中的所有原始记录求和。

有没有一种没有光标的有效方法?

-----[简单示例]-------------------------------------- ----------------------

我正在尝试按一个稍微复杂的运行总和形式进行分组,常数 C。

只有一张表,列都是int类型和样本数据

declare @t table (
  PK int primary key
    , int a, int b, int minColumn, int maxColumn, int N 
)

insert @t values (1,5,6,100,200,1000)
insert @t values (2,7,8,210,300,2000)
insert @t values (3,9,10,420,600,3000)
insert @t values (4,11,12,640,800,4000)

因此:

key, a,   b, minColumn, maxColumn,    N
---------------------------------------
1,   5,   6,       100,       200, 1000 
2,   7,   8,       210,       300, 2000 
3,   9,  10,       420,       600, 3000 
4,   11, 12,       640,       800, 4000 

我需要结果集看起来像,对于 210 的常数 C:

firstA | lastB | MIN_minColumn | MAX_maxColumn | SUM_N
5       8                  100             300    3000 
9       10                 420             600    3000 
11      12                 640             800    4000 

[添加赏金和示例如下所述]

对于 C = 381,它应该包含 2 行:

firstA | lastB | MIN_minColumn | MAX_maxColumn | SUM_N
5            8             100             300    3000 
9           12             420             800    7000

希望这能更好地说明问题.. 对于常数 C 比如说 1000,您将在结果中获得 1 条记录:

firstA | lastB | MIN_minColumn | MAX_maxColumn | SUM_N
5           12             100             800   10000

【问题讨论】:

  • 一组示例数据和示例结果将阐明这一点。
  • 你想按什么分组?
  • 您的问题缺少为您解决此问题所需的一切:表格、列、示例数据、分组细节和预期结果
  • 添加了简单示例,如果需要进一步解释问题,请告诉我。干杯。
  • 您运行的是什么 SQL Server 版本?

标签: sql sql-server database tsql


【解决方案1】:
DECLARE @c int
SELECT @c = 210

SELECT MIN(a) firstA,
       MAX(b) lastB, 
       MIN(minColumn) MIN_minColumn, 
       MAX(maxColumn) MAX_maxColumn, 
       SUM(N) SUM_N
FROM @t t 
JOIN (SELECT key, floor(sum/@c) as rank
        FROM (SELECT key, 
                     (SELECT SUM(t2.maxColumn - t2.minColumn) 
                        FROM @t t2 
                       WHERE t2.key <= t1.key 
                    GROUP BY t1.key) as sum
               FROM @t t1) A
     ) B on B.key = t.key
GROUP BY B.rank

/*

Table A: for each key, calculating SUM[maxColumn-minColumn] of all keys below it.
Table B: for each key, using the sum in A, calculating a rank so that:
  sum = (rank + y)*@c where 0 <= y < 1. 
  ex: @c=210, rank(100) = 0, rank(200) = 0, rank(220) = 1, ...
finally grouping by rank, you'll have what you want.

*/

【讨论】:

  • 太棒了。我遇到的唯一问题是 GROUP BY 不包含作为外部引用的列,至少 MS SQL 报告了这个解析错误。我想它是写在另一个数据库上的?删除它仍然会产生正确的结果,但在实践中,我希望它能够用于 [key] 更改(即 key 在生产中通常是复合的)。对此有何建议?无论如何都会接受答案...
  • 谢谢。我不明白你到底想做什么。我在 SQL Server 2005 上测试了这个查询并且它有效。您想修改它以添加其他列,还是将其用作另一个查询中的连接表?
  • 已将其缩小到可以追溯到 SQL 2000 的差异,该 SQL 2000 在单个聚合子句或类似子句上接受 group-by。问题在于创建/真实表,其中 GROUP BY 不会通过解析.. 否则在示例和表 variable 上它可以工作。
  • 好的,只是为了确认对于所提出的问题(这是一个令人困惑的练习),解决方案确实有效。对于稍作修改的数据,它需要进行微小的更改,但这是可以预料的。出色的工作 Najm,感谢您的额外帮助和您的时间。我希望我可以再次对解决方案进行投票,或者某些选项 SO 还没有:)..
【解决方案2】:

声明@c int

选择@c = 210

选择 firstA = min(a), lastB = max(b), MIN_minColumn = min(minColumn), MAX_maxColumn = max(maxColumn), SUM_N = sum(N) 从T 其中 minColumn

联合所有

选择a、b、minColumn、maxColumn、N 从T 其中 minColumn > @c

【讨论】:

  • 非常接近,谢谢,但没有为 C = 381 生成正确的结果集。它应该包含 2 行:{ 5, 8, 100, 300, 3000 } { 9, 12, 420, 800 , 7000 } 但它会生成 3,如上例所示。
  • 不知道如何解决,但我正在寻找一个 WHERE 子句来进行“分组”,这样 (MAX_maxcolumn - MIN_mincolumn)
  • 条件 "MAX_maxcolumn - MIN_mincolumn )
  • 谢谢.. 它绝对与第 1 行无关,但更像是“任何地方”,即。它相对于“分组”的最后一条记录,或者更好地说,是最新的结果记录。您的样本将产生 { 5, 6, 100, 300, 3000 }, { 9, 12, 420, 800, 7000 }, { 13, 16, 810, 870, 8000 }... 所以是的,5 & 6 将是分组为 1 条记录。
【解决方案3】:

我对您尝试生成的结果的分组逻辑有点困惑,但是从您要查找的内容的描述来看,我认为您需要一个 HAVING 子句。您应该能够执行以下操作:

SELECT groupingA, groupingB, MAX(a) - MIN(b)
FROM ...
GROUP BY groupingA, groupingB
HAVING (MAX(a) - MIN(b)) < C

...为了过滤掉最大值和最小值之间的差异,一旦你确定了你的分组。希望对您有所帮助

【讨论】:

  • 编辑们非常友好地将帖子格式化为完美:) 上面的示例满足了说明问题的 4 个场景,我承认这有点奇怪。我愿意接受有关最简单、最短、优雅的方法的建议,我很乐意重新发布优化标题并为其提供赏金并参考公认的解决方案..但我不确定 HAVING 会产生正确的结果对于上面的示例。
猜你喜欢
  • 2013-08-16
  • 1970-01-01
  • 2018-06-24
  • 2015-05-26
  • 1970-01-01
  • 2019-07-26
  • 2019-01-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多