2010-05-14 4 views
2

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

Одна таблица исторические данные имеют квартальную информацию:

CREATE TABLE Quarterly (
unique_ID INT UNSIGNED NOT NULL, 
date_posted DATE NOT NULL, 
datasource TINYINT UNSIGNED NOT NULL, 
data FLOAT NOT NULL, 
PRIMARY KEY (unique_ID)); 

Другой таблица исторических данных (что является очень большим) содержит ежедневную информацию:

CREATE TABLE Daily (
unique_ID INT UNSIGNED NOT NULL, 
date_posted DATE NOT NULL, 
datasource TINYINT UNSIGNED NOT NULL, 
data FLOAT NOT NULL, 
qtr_ID INT UNSIGNED, 
PRIMARY KEY (unique_ID)); 

поля qtr_ID не является частью подачи да ily, которые заполняют базу данных - вместо этого мне нужно ретроактивно заполнить поле qtr_ID в таблице Daily с идентификатором строки Quarterly.unique_ID, используя то, что было бы последними ежеквартальными данными в этом Daily.date_posted для этого источника данных.

Например, если квартальный данные

101 2009-03-31 1 4,5
102 2009-06-30 1 4,4
103 2009-03-31 2 7,6
104 2009 -06-30 2 7,7
105 2009-09-30 1 4,7

и ежедневные данные

1001 2009-07-14 1 3.5 ??
1002 2009-07-15 1 3,4 & &
1003 2009-07-14 2 2,3 ^^

тогда мы хотим ?? qtr_ID, которое должно быть назначено «102» в качестве последней четверти для этого источника данных в эту дату, а & & также будет «102», а ^^ будет «104».

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

Я пробовал различные объединения, используя датифик (где вызов находит минимальное значение датированного больше нуля) и другие попытки, но ничего не работает для меня - обычно мой синтаксис где-то ломается. Любые идеи приветствуются - я буду выполнять любые основные идеи или концепции и отчитываться.

ответ

1

Просто подзапрос четвертьфиналов идентификатора, используя что-то вроде:

(
SELECT unique_ID 
FROM Quarterly 
WHERE 
    datasource = ? 
    AND date_posted >= ? 
ORDER BY 
    unique_ID ASC 
LIMIT 1 
) 

Конечно, это, вероятно, не даст вам лучшую производительность, и это предполагает, что сроки будут добавлены в ежеквартальные последовательно (в противном случае order by date_posted). Однако он должен решить вашу проблему.

Вы могли бы использовать этот подзапрос на вашей INSERT или UPDATE отчетности стоимости вашего qtr_ID поля для вашего Daily таблицы.

+0

К сожалению, это не точно выполнять работу - это вытащить правильный источник данных, но он ранжируется на основе времени, прошедшего с момента (и затем обеспечивает первый ввод) самых ранних квартальных данных, а не того, что было бы самым последним. Итак, в приведенном выше примере он возвращает '101' для ВСЕХ данных из datasource = '1' и '103' для ВСЕХ данных из datasource = '2'. Вот что я побежал: UPDATE Daily SET qtr_ID = ( ВЫБОР unique_id ИЗ Quarterly ГДЕ Daily.datasource = Quarterly.datasource И Daily.date_posted> = Quarterly.date_posted ORDER BY date_posted ASC LIMIT 1 ) – Hank

+0

Кстати, это предложение МНОГО быстрее, чем мой успешный запрос ниже. – Hank

+0

Большая разница в скорости заставила меня работать над предложением выше, что привело к открытию того, что это было всего лишь одно небольшое изменение (сортировка по дате_поставлению в другом направлении), так что это код, который работает, и быстро : UPDATE Daily SET qtr_ID = (SELECT unique_ID FROM Quarterly WHERE Daily.datasource = Quarterly.datasource AND Daily.date_posted> = Quarterly.date_posted ORDER BY date_posted DESC LIMIT 1); Спасибо группе Kenaniah – Hank

0

Следующие функции работают точно так, как предполагалось, но, безусловно, уродливые (с тремя вызовами к тому же DATEDIFF !!), Возможно, видя рабочий запрос кто-то мог бы еще больше уменьшить его или улучшить его:

UPDATE Daily SET qtr_ID = (select unique_ID from Quarterly 
WHERE Quarterly.datasource = Daily.datasource AND 
DATEDIFF(Daily.date_posted, Quarterly.date_posted) = 
(SELECT MIN(DATEDIFF(Daily.date_posted, Quarterly.date_posted)) from Quarterly 
WHERE Quarterly.datasource = Daily.datasource AND 
DATEDIFF(Daily.date_posted, Quarterly.date_posted) > 0)); 
+0

См. Вышеупомянутый ответ для более быстрого решения, чем этот. – Hank

0

После дополнительной работы по этому запросу, я в конечном итоге с огромным улучшением производительности по сравнению с оригинальной концепцией. Наиболее важным улучшением было создание индексов как в таблицах Daily, так и в Quarterly - в Daily я создал индексы (datasource, date_posted) и (date_posted, datasource) ИСПОЛЬЗОВАНИЕ BTREE и on (datasource) ИСПОЛЬЗОВАНИЕ HASH, а в Quarterly я сделал то же самое вещь. Это слишком много, но я уверен, что у меня есть опция, которую может использовать механизм запросов. Это сократило время запроса до менее чем 1% от того, что было. (!!)

Затем я узнал, что с учетом моих конкретных обстоятельств я могу использовать MAX() вместо ORDER BY и LIMIT, поэтому я использую вызов MAX(), чтобы получить соответствующий уникальный_ID. Это сократило время запроса примерно на 20%.

Наконец-то я узнал, что с помощью механизма хранения InnoDB я мог сегментировать кусок таблицы Daily, который я обновлял с помощью одного запроса, что позволило мне многопоточно обрабатывать запросы с небольшой консистентной смазкой и скриптами. Параллельная обработка работала хорошо, и каждый поток сокращал время запроса линейно.

Итак, основной запрос, который выполняет буквально в 1000 раз лучше, чем мой собственный первой попытки:

UPDATE Daily 
SET qtr_ID = 
(
    SELECT MAX(unique_ID) 
    FROM Quarterly 
    WHERE Daily.datasource = Quarterly.datasource AND 
     Daily.date_posted > Quarterly.dateposted 
) 
WHERE unique_ID > ScriptVarLowerBound AND 
     unique_ID <= ScriptVarHigherBound 
; 

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

  • Нет связанных вопросов^_^