2013-10-10 4 views
2

Я только начинаю изучать MySQL, и я столкнулся с этой проблемой, в которой я остро нуждался в решении или просто в логике.Группа MySQL по номеру серии

Например, у меня есть эта таблица:

id   a 
--  -- 
1   1 
2   2 
3   3 
4   5 
5   6 
6   7 
7   9 
8  10 
9  11 
10  12 

Теперь, что я хочу, чтобы отобразить все данные в столбце a, которые должны быть сгруппированы по сериям. В этом случае результат должен быть:

series_start|series_end|count 
------------+----------+----- 
      1   3  3 
      5   7  3 
      9   12  4 

Для этого требуется много подзапросов и объединений. Я просто не могу понять это.

+1

Вопросы, требующие кода, должны демонстрировать минимальное понимание решаемой проблемы. Включите попытки решения, почему они не работают и ожидаемые результаты. – Kermit

+0

Она нуждается в несколько соединений, но не подзапросов ;-) не – Strawberry

+0

ВЫБРАТЬ аа начало , MIN (CA) конец , MIN (CA) - AA + 1 Diff ОТ my_table ЛЕВЫЙ РЕГИСТРИРУЙТЕСЬ my_table б ВКЛ аа = ба + 1 ЛЕВЫЙ РЕГИСТРИРУЙТЕСЬ my_table гр О са> = аа ЛЕВЫЙ РЕГИСТРИРУЙТЕСЬ my_table д на дА = c.a + 1 Где ба IS NULL и кальциевые IS NOT NULL И да IS NULL ГРУППА АА; – Strawberry

ответ

0

Вот одно решение, используя user defined variables:

select min(series_start) series_start, 
    max(series_end) series_end, 
    1 + max(series_end) - min(series_start) count 
from (
    select t1.a series_start, 
    t2.a series_end, 
    @val:=IF(@prev=t2.a-1,@val,@val+1) val, 
    @prev:=t2.a 
    from yourtable t1 
    join yourtable t2 on t1.a = t2.a-1 
    join (select @val:= 0, @prev:= 0) t 
    order by t2.a 
) t 
group by val 
+0

Он работает нормально, но мне нужно прочитать больше, чтобы полностью понять этот метод, определяемый пользователем. Спасибо за ответ. :) –

+0

@Tuyhakaw - не беспокойтесь, рад, что смогу помочь! В основном переменная 'val' отслеживает последовательные записи. Сгруппировавшись по этой переменной, вы можете использовать агрегированные функции для достижения ваших результатов. С наилучшими пожеланиями. – sgeddes

+0

Кстати, у меня есть дополнительный вопрос: что делает «соединение» с таблицами? Я знаю о 'left',' right' и других 'joins', но не об этом. –

2

Это проблема, а вот еще один способ ее решения, который также использует переменные:

SELECT 
    MIN(a) AS series_start, 
    MAX(a) AS series_end, 
    MAX(a) - MIN(a) + 1 AS series_count 
FROM (
    SELECT 
    a, 
    @r := @r + 1 AS r 
    FROM 
    yourtable, 
    (SELECT @r := 0) AS x 
    ORDER BY 
    a 
) s 
GROUP BY 
    a - r 
ORDER BY 
    a - r 
; 

Вот как оно работает.

подзапрос присваивает номера строк для строк таблицы и возвращает эту строку набора:

a r 
-- -- 
1 1 
2 2 
3 3 
5 4 
6 5 
7 6 
9 7 
10 8 
11 9 
12 10 

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

Основные группы запроса результаты по разнице между r и a: для последовательных значений, она всегда будет такой же:

a r a - r 
-- -- ----- 
1 1  0 
2 2  0 
3 3  0 
5 4  1 
6 5  1 
7 6  1 
9 7  2 
10 8  2 
11 9  2 
12 10  2 

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

series_start series_end series_count 
------------ ---------- ------------ 
      1   3    3 
      5   7    3 
      9   12    4 

SQL-Fiddle демонстрацию этого запроса, для которых я заимствовал @ схему sgeddes'S, можно найти here.


UPDATE

Как числовые переменные не могут быть использованы (в соответствии с комментариями), можно назначить номера строк с помощью треугольного автообъединения, но это будет гораздо менее эффективно, чем при использовании переменного. Во всяком случае, вот модифицированная версия, изменения в предыдущем запросе быть выделены жирным шрифтом:

SELECT 
    MIN(a) AS series_start, 
    MAX(a) AS series_end, 
    MAX(a) - MIN(a) + 1 AS series_count 
FROM (
    SELECT 
    data.a, 
    COUNT(*) AS r 
    FROM 
    yourtable AS data 
    INNER JOIN 
    yourtable AS tally 
    ON 
    data.id >= tally.id 
    GROUP BY 
    data.a 
) s 
GROUP BY 
    a - r 
ORDER BY 
    a - r 
;

Сам подход остается неизменным: подзапрос возвращает ранжированный набор строк, который затем обрабатывается так же, как ранее.

Демо-версия SQL Fiddle для модифицированного запроса доступна here.

+0

O.O Я не могу использовать метод выше. Наша компания использует CGI, который обрабатывает любое слово, которое звездочками «@» является переменной, и рассматривается как нормальная строка, которая будет объединена с самим утверждением. Без начального значения он будет оставлен пустым, что приведет к ошибке. –

+0

'@ r' действительно является переменной в этом контексте, но я не совсем понимаю, что вы говорите о том, как ваш CGI обрабатывает слово, начинающееся с' @ '. В конце концов, рассматривает ли он его как переменную или как строку? В любом случае, если это проблема только в подзапросе '(SELECT @r: = 0)', вы можете попробовать удалить его и заменить '@r: = @r + 1 AS r' на' @r: = IFNULL (@r, 0) + 1 AS r'. –

+0

Любое слово, начинающееся с символа '@', рассматривается как переменная (типа string). Я не мог использовать также: = для назначения значений, это вызывает ошибку. –

Смежные вопросы