2016-05-01 4 views
0

У меня есть таблица с 20 миллионами строк.SQL - Как сшить две строки из одной таблицы

Каждая строка представляет день + клиент.

Не все дни представлены рядами.

Мне нужно получить для ряда дат, скажем 2015-01-01 до 2016-01-01 таблицу, которая будет иметь для каждого клиента строку, ближайшую сверху до 2015-01-01, и ближайшую снизу 2016-01-01

Таблица:

enter image description here

Желаемый результат:

enter image description here

Подводя итог, это 2 строки из той же таблицы, сшитой в одну строку.

Простое отбор и соединение происходит навсегда. Каков правильный способ запроса этих данных?

+0

Опубликуйте запрос, который вы попробовали, а также разместите таблицы и данные как текст вместо изображений, чтобы другие могли попробовать их. Вы говорите, что ваше соединение происходит очень медленно. Можете ли вы также опубликовать вывод объяснения? – e4c5

+0

Есть ли столбец первичного ключа в этой таблице, который однозначно идентифицирует каждую строку? – krokodilko

+0

Я думаю, что ваш пример данных смущен. Как клиент 2 получит значение 213, когда он появится только в таблице для клиента 1? Как бы клиент 2 имел дату 2015-01-01, если это не отображается в таблице? –

ответ

0

Существует несколько подходов. Возможно, самым простым является использование substring_index()/group_concat() хак:

select client, min(date) as date1, max(date) as date2, 
     substring_index(group_concat(random order by date), ',', 1) as random1, 
     substring_index(group_concat(random order by date desc), ',', 1) as random2 
from t 
where date >= '2015-01-01' and 
     date < '2016-01-01' 
group by client; 

Учитывая ваши данные выборки, это должно работать нормально.

Более традиционный подход будет использовать агрегацию и присоединяется:

select c.client, c.date1, c.date2, t1.random as random1, t2.random as random2 
from (select t.client, min(date) as date1, max(date) as date2 
     from t 
     where date >= '2015-01-01' and date < '2016-01-01' 
     group by client 
    ) c join 
    t t1 
    on c.client = t1.client and c.date1 = t1.date join 
    t t2 
    on c.client = t2.client and c.date2 = t2.date; 

Это также облегчает добавление более двух столбцов данных.

0

Один из способов заключается в использовании двух зависимых подзапросов - но это не может быть очень эффективным, MySql не очень умный в оптимизации зависимых подзапросов .:

SELECT client, 
     date as date1, 
     ( SELECT date FROM table t2 
      WHERE t1.client = t2.client 
      AND t2.date > t1.date 
      ORDER BY t2.date LIMIT 1 
     ) as date2, 
     random As random1, 
     ( SELECT random FROM table t2 
      WHERE t1.client = t2.client 
      AND t2.date > t1.date 
      ORDER BY t2.date LIMIT 1 
     ) as random2  
FROM table t1 

Вы можете создать многоколоночном индекс на table(client, date), чтобы ускорить этот процесс запрос вверх.

+0

Очень медленно. особенно если у меня нет только двух столбцов, но 10 – Amit

+0

Если в таблице будет первичный ключ (суррогатная ПК), тогда было бы возможно решение с соединением - но вы не упомянули об этом в вопросе, если таблица имеет любой PK, поэтому я предполагаю, что PK не существует, и в этом случае это решение невозможно. – krokodilko

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