сложная группа по запросу MySQL - PullRequest
4 голосов
/ 05 августа 2010

У меня есть таблица со следующими строками:

id. user_id, type  - link 

 1. 555, image - http://1
 2. 555, image - http://2
 3. 654, image  - http://3
 4. 245, video - http://..
 5. 555, image - http://..
 6. 878, text  - http://..

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

выход

1. 555, image - http://1, http://2  ** GROUPED BY DATE, if they are same type and not break type after it.
2. 654, image - http://3
3. 245, video - http://..
4. 555, image - http://..
5. 878, text  - http://.

Кстати, я собираюсь сделать Facebook как новостную ленту, если у кого-то есть идея получше, поделитесь, пожалуйста.

Ответы [ 5 ]

3 голосов
/ 12 августа 2010
SELECT `date`, `user_id`, `type`, GROUP_CONCAT(`link`)
FROM `table`
GROUP BY `date`, `user_id`, `type`
1 голос
/ 12 августа 2010

Это не так просто сделать в SQL, так как он зависит от порядка, к которому SQL не очень подходит.

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

SELECT @rownum:=@rownum+1 AS id, t.user_id, type, date, urls FROM
 (SELECT MIN(ID) AS original_id, user_id, type, date, GROUP_CONCAT(url) urls FROM
  (SELECT i1.*, 
   IF(i1.type='image', 
     IFNULL((SELECT MIN(i2.ID)-1 FROM Items i2
             WHERE i2.ID>i1.ID AND 
                  (i2.type!=i1.type OR i1.user_id!=i2.user_id OR i1.date!=i2.date)), 
            (SELECT MAX(id) FROM Items)), 
     i1.ID) AS lastRow,
   IF (i1.type='image', 
     IFNULL(SELECT MAX(i3.ID)+1 FROM Items i3 
             WHERE i3.ID<=i1.ID AND 
                  (i3.type!=i1.type OR i1.user_id!=i3.user_id OR i1.date!=i3.date)), 
            (SELECT MIN(id) FROM Items)), 
      i1.ID) AS firstRow) AS groupItems
  GROUP BY user_id, type, date, firstRow, lastRow) t, (SELECT @rownum:=0) r
  ORDER BY t.original_id; 

Запрос использует коррелированный подзапрос, чтобы найти начальный и конечный идентификаторы каждой группы изображений. Граница группы - это элемент, который не совпадает с типом, пользователем или датой.

SELECT i1.ID, 
  IF(i1.type='image', 
     IFNULL((SELECT MIN(i2.ID)-1 FROM Items i2
             WHERE i2.ID>i1.ID AND 
                  (i2.type!=i1.type OR i1.user_id!=i2.user_id OR i1.date!=i2.date)), 
            (SELECT MAX(id) FROM Items)), 
     i1.ID) AS lastRow,
  IF (i1.type='image', 
     IFNULL(SELECT MAX(i3.ID)+1 FROM Items i3 
             WHERE i3.ID<=i1.ID AND 
                  (i3.type!=i1.type OR i1.user_id!=i3.user_id OR i1.date!=i3.date)), 
            (SELECT MIN(id) FROM Items)), 
      i1.ID) AS firstRow

Для каждого элемента столбцы firstRow / lastRow дают начало и конец группы. Затем мы можем использовать GROUP_CONCAT для объединения всех URL-адресов. Для сохранения порядка выводится MIN (id), давая первый идентификатор каждой группы.

SELECT MIN(id) AS original_id, user_id, type, date, GROUP_CONCAT(url) urls FROM
 (SELECT i1.*, 
  IF(i1.type='image', 
     IFNULL((SELECT MIN(i2.ID)-1 FROM Items i2
             WHERE i2.ID>i1.ID AND 
                  (i2.type!=i1.type OR i1.user_id!=i2.user_id OR i1.date!=i2.date)), 
            (SELECT MAX(id) FROM Items)), 
     i1.ID) AS lastRow,
  IF (i1.type='image', 
     IFNULL(SELECT MAX(i3.ID)+1 FROM Items i3 
             WHERE i3.ID<=i1.ID AND 
                  (i3.type!=i1.type OR i1.user_id!=i3.user_id OR i1.date!=i3.date)), 
            (SELECT MIN(id) FROM Items)), 
      i1.ID) AS firstRow) AS groupItems
 GROUP BY user_id, type, date, firstRow, lastRow

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

SELECT @rownum:=@rownum+1 AS id, user_id, type, date, urls FROM
 (SELECT MIN(ID) AS original_id, user_id, type, date, GROUP_CONCAT(url) urls FROM
  (SELECT i1.*, 
   IF(i1.type='image', 
     IFNULL((SELECT MIN(i2.ID)-1 FROM Items i2
             WHERE i2.ID>i1.ID AND 
                  (i2.type!=i1.type OR i1.user_id!=i2.user_id OR i1.date!=i2.date)), 
            (SELECT MAX(id) FROM Items)), 
     i1.ID) AS lastRow,
   IF (i1.type='image', 
     IFNULL(SELECT MAX(i3.ID)+1 FROM Items i3 
             WHERE i3.ID<=i1.ID AND 
                  (i3.type!=i1.type OR i1.user_id!=i3.user_id OR i1.date!=i3.date)), 
            (SELECT MIN(id) FROM Items)), 
      i1.ID) AS firstRow) AS groupItems
  GROUP BY user_id, type, date, firstRow, lastRow) t, (SELECT @rownum:=0) r
  ORDER BY t.original_id; 

SQL лучше всего подходит для работы с неупорядоченными наборами данных, а не с последовательностями, как здесь. Если вы можете сделать это в коде презентации или, возможно, лучше на уровне приложения, я думаю, это будет быстрее и более гибким. Решение с ручным кодированием позволяет найти начало и конец каждой группы за один проход данных. Я сомневаюсь, что SQL-запрос будет выполняться так же эффективно.

1 голос
/ 05 августа 2010

Есть ли причина, по которой вам НУЖНО сделать это в SQL?Я пытаюсь выполнить сбор данных в SQL и вставить форматирование в код, из которого вызывается SQL.

Я бы выполнил простой SQL-запрос, извлекая все файлы изображений, но упорядоченный по user_id / date.Затем мой код просматривал бы результаты, объединяя каждый файл изображения в одну и ту же строку вывода, пока не изменится идентификатор пользователя / дата, и в этом случае мы знаем, что нам нужно начать новую строку с новым идентификатором пользователя / датой.

Это также упрощает произвольное форматирование текста, особенно если вы собираетесь выдавать HTML.

0 голосов
/ 18 августа 2010

Я мог бы рассмотреть другое хранилище данных, такое как CouchDB или RavenDB. Это было бы намного лучше при обслуживании контента такого типа, и не пришлось бы иметь дело с внешними ключами или объединениями.

Просто используйте непрерывную репликацию в базы данных всех друзей.

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

0 голосов
/ 16 августа 2010

этот запрос поможет:

select id, user_id, `type`, group_concat(link) from images
group by user_id, `type`, date
order by id
...