У меня есть небольшое приложение, которое по ежедневному расписанию выполняет серию сценариев SQL для базы данных Redshift и заполняет таблицы агрегированными данными, готовыми для извлечения клиентом. Скрипты хранятся в текстовых файлах и могут быть легко обновлены, SQL извлекается из файла '| businessday |' заменено на требуемую дату, например, «20180501». Нет надежной логики, чтобы основывать дату на текущей календарной дате.
Требования от клиента изменились, и теперь есть два сценария, которые должны заполнять таблицы только в последний день месяца. Я могу обновить скрипт так, чтобы предикат читал:
WHERE (SELECT businessday FROM bd) = LAST_DAY((SELECT businessday FROM bd))
Где bd - это CTE, поэтому я могу привести строку даты как DATE.
Хотя это правильно не возвращает никаких записей, выполнение занимает лишь незначительно меньше времени, чем когда я запускаю его в течение всего месяца - для возврата 0 строк требуется более минуты. Я ожидал бы, что он быстро определит этот предикат как сбойный и не вернет строки почти мгновенно.
Есть ли способ реструктурировать SQL, чтобы сначала оценить этот предикат?
Насколько я понимаю, вы не можете использовать процедурные операторы IF в Redshift, поэтому я ограничен добавлением предикатов в строку SQL.
Я попытался добавить второй CTE, который не возвращает предикатов в столбцах рабочих дней ключевых таблиц:
WITH bd as (SELECT CAST('20180425' as date) as businessday WHERE
(SELECT CAST('20180425' as date)) = LAST_DAY(( CAST('20180425' as date)))
...
WHERE ts.businessday in (select businessday from bd)
(это нужно изменить, чтобы получить то, что мне нужно, но принцип, похоже, не работает)
Упрощенная строка SQL (пара таблиц и столбцов удалены):
with cte as (select storeid from ttl_store_processed where
businessday = '20180425'),
bd as (SELECT CAST('20180425' as date) as businessday
WHERE (SELECT CAST('20180425' as date)) = LAST_DAY(( CAST('20180425' as date))))
SELECT store.storenumber AS COST_CENTER,
TO_CHAR(DATE(tii.BusinessDay), 'YYYYMM') AS YEAR_MONTH,
ii.ItemCode AS MATERIAL_NUMBER,
SUM(tii.Quantity) AS UNITS
FROM cte s
inner join transactionsale ts
on s.storeid = ts.storeid
inner join Store store
on ts.storeid = store.storeid
inner join transactionsaleitem tsi
on ts.transactionsaleid = tsi.transactionsaleid
inner join transactioninventoryitem tii
on tsi.transactionsaleitemid = tii.transactionsaleitemid
inner join inventoryitem ii
on tii.inventoryitemid = ii.inventoryitemid
WHERE (SELECT businessday FROM bd) = LAST_DAY((SELECT businessday FROM bd))
AND ts.storeid IN (SELECT storeid FROM cte)
AND ts.businessday BETWEEN DATE_TRUNC('MONTH', (SELECT businessday FROM bd))
AND LAST_DAY((SELECT businessday FROM bd))
GROUP BY
store.storenumber,
TO_CHAR(DATE(tii.BusinessDay), 'YYYYMM'),
ii.ItemCode;
cte в настоящее время возвращает ~ 20 магазинов, но потенциально возрастет до 180+. Я попытался применить логику, поэтому эта таблица пуста:
with cte as (select storeid from mcdonaldshk.ttl_store_processed
where businessday = '20180425' and (SELECT CAST('20180425' as date))
= LAST_DAY(( CAST('20180425' as date))))
Это тоже не работает