Это не так просто сделать в 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-запрос будет выполняться так же эффективно.