Агрегирование SQL для меньшего набора результатов - PullRequest
3 голосов
/ 06 октября 2009

У меня есть база данных, для которой мне нужно объединить записи в другой меньший набор. Этот результирующий набор должен содержать разницу между максимумом и минимумом определенных столбцов исходных записей, в которых они суммируются с определенной суммой, постоянной величиной закрытого интервала C.

Константа C определяет способ агрегирования исходных записей, и ни одна запись в результирующем наборе никогда не превышает ее. Естественно, я должен выполнить это в естественном порядке первичного ключа ..

Для иллюстрации: таблица имеет:

  • [ключ]
  • [а] * * 1 010
  • [Ь]
  • [minColumn]
  • [maxColumn]
  • [N]

... все имеют тип данных.

Я получаю после набора результатов, в котором есть записи, где MAX (maxColumn) - MIN (minColumn) для этой группы такой, что при суммировании их разности она меньше или равна константе C.

Помимо значений MAX (maxColumn) и MIN (minColumn), мне также нужны значения столбца FIRST записи [a] и столбца LAST записи [b] перед созданием новой записи в этом наборе результатов. Наконец, столбец N должен быть суммирован для всех исходных записей в группе.

Есть ли эффективный способ сделать это без курсоров?

----- [Trivial Sample] -------------------------------------- ----------------------

Я пытаюсь сгруппировать по несколько сложной форме бегущей суммы, постоянной С.

Существует только одна таблица, все столбцы имеют тип 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 

Мне нужно, чтобы набор результатов выглядел как константа C, равная 210:

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

Ответы [ 3 ]

2 голосов
/ 09 октября 2009
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.

*/
1 голос
/ 09 октября 2009

Я немного запутался в логике группировки результатов, которую вы пытаетесь получить, но из описания того, что вы ищете, я думаю, что вам нужно предложение HAVING. Вы должны быть в состоянии сделать что-то вроде:

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

... для того, чтобы отфильтровать разницу между вашими максимальными и минимальными значениями, как только вы определили свою группировку. Надеюсь, что это полезно

1 голос
/ 07 октября 2009

объявляют @c int

выберите @c = 210

выберите firstA = min (a), lastB = max (b), MIN_minColumn = min (minColumn), MAX_maxColumn = max (maxColumn), SUM_N = sum (N) от @t где minColumn <= @ c </p>

объединение всех

выберите a, b, minColumn, maxColumn, N от @t где minColumn> @ c

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...