У меня есть сценарий, который запускает сквозной запрос SAS, который подключается к базе данных Oracle. Это было частью cronjob, работающего на Unix-сервере, и не было проблем в течение многих лет. Однако в последние несколько недель задание начало зависать на этом конкретном шаге — согласно журналам, раньше оно выполнялось около 15 секунд, но теперь оно будет выполняться бесконечно, прежде чем нам придется убить задание. В журнале нет связанных ошибок или предупреждений — задание создаст файл блокировки и просто будет работать бесконечно, пока нам не придется его убить.
Шаг, на котором задание зависает, вставлен ниже. Есть две макропеременные &start_dt и &end_dt, которые представляют диапазон дат, для которого задание извлекает данные о продажах.
В ходе исследования мы попробовали несколько разных подходов, и смогли заставить этот шаг работать успешно и в обычное время, изменив три вещи:
запуск сценария через клиент Enterprise Guide, который подключается на тот же сервер, в отличие от запуска скрипта через CLI/shell сценарий
Изменение библиотеки, в которую шаг пишет, чтобы она работала, а не записывалась
набор данных в библиотеку данных продаж (как показано в коде ниже)
Изменение дат на жестко заданные значения вместо макропеременных.
Что касается самих переменных даты, они представляют собой строки в формате date9, например &start_dt = '08-мая-22', &end_dt = '14-мая-22'. Первоначально я подозревал, что проблема связана со структурой дат, так как это более старый проект, который я унаследовал, но меня смущает, почему задание выполнялось без проблем так долго, вплоть до нескольких недель назад, даже с этими странно отформатированными датами. макрос варс.
Другая возможность, которую я рассматривал, заключалась в том, что какой-то ресурс на сервере unix был заблокирован, когда он дошел до этого шага, возможно, из-за какого-то зависшего задания или какого-то другого конфликта со старым файлом, таким как журнал или предыдущий набор данных sas. .
Проблемная версия шага в скрипте, вставленном ниже:
PROC SQL;
connect to oracle(user=&uid pass=&pwd path='@dw');
create table salesdata.shipped as
Select
SKN_NBR,
COLOR_NBR,
SIZE_NBR,
SALESDIV_KEY,
ORDER_LINE_QTY as QUANTITY label = "SUM(ORDER_LINE_QTY)",
EX1 as DOLLARS label = "SUM(EX1)" from connection to oracle(
select
A1."SKN_NBR",
A1."COLOR_NBR",
A1."SIZE_NBR",
decode(A1."SALESDIV_KEY", 'ILB', 'IQ',
'IQ ', 'IQ',
'IQC', 'IQ',
'ISQ', 'IQ',
'IWC', 'IQ',
'QVC'),
SUM(A1."ORDER_LINE_QTY"),
SUM(A1."ORDER_LINE_QTY" * A1."ORDER_LINE_PRICE_AMT")
from DW.ORDERLINE A1, DISTINCT_SKN A2, DW.ORDERSTATUSTYPE A3
where
A2."SKN_NBR" = A1."SKN_NBR" AND
A1."CURRENT_STATUS_DATE" Between &start_dt and &end_dt AND
A1."ORDERLINESTATUS_KEY" = A3."ORDERLINESTATUS_KEY" AND
A3."ORDERSTATUS_SHIPPED" = 'Y' AND
A1."ORDER_LINE_PRICE_AMT" > 0
group by A1."SKN_NBR",
A1."COLOR_NBR",
A1."SIZE_NBR",
decode(A1."SALESDIV_KEY", 'ILB', 'IQ',
'IQ ', 'IQ',
'IQC', 'IQ',
'ISQ', 'IQ',
'IWC', 'IQ',
'QVC')
order by A1."SKN_NBR",
A1."COLOR_NBR",
A1."SIZE_NBR",
decode(A1."SALESDIV_KEY", 'ILB', 'IQ',
'IQ ', 'IQ',
'IQC', 'IQ',
'ISQ', 'IQ',
'IWC', 'IQ',
'QVC')
) as t1(SKN_NBR, COLOR_NBR, SIZE_NBR, SALESDIV_KEY, ORDER_LINE_QTY, EX1)
;
disconnect from oracle; quit;
[1]: https://i.stack.imgur.com/GGjin.jpg
@Tom, если я изменю &start_dt и &end_dt на жестко закодированные значения «08-May-22» и «14-May-22» и запишу результаты для работы, а не на диск, шаг выполняется без проблем.
И как вы пытаетесь присвоить значения макропеременным? Кроме того, Oracle действительно не хочет знать, о каком веке вы говорите? Это 1922, 1822?
@Tom Я добавил более подробную информацию в ответ ниже, макропеременные назначаются с использованием шага данных для объединения некоторых строк и применения форматов из набора данных календаря дат. Изменение формата на этом этапе для использования 4-х символьных лет вместо двух, по-видимому, решает проблему. Спасибо, что указали мне правильное направление, я продолжу и приму ваш ответ.
Вопрос stackoverflow.com/questions/60452323/… относится к той же теме
Какой стиль вам нужно использовать для констант даты в Oracle, зависит от ваших настроек в Oracle. Но обычно вы можете использовать такие выражения, как одно из этих
date '2022-05-14'
'2022-05-14'
Кажется, вы утверждаете, что в вашей системе вы можете использовать такие значения, как
'14-May-22'
(откуда Oracle знает, какой век вы имеете в виду?).
Обратите внимание, что в Oracle важно использовать одинарные кавычки вокруг констант, поскольку он интерпретирует строки в двойных кавычках как имена объектов.
Поэтому, если у вас есть значение даты в SAS, просто убедитесь, что значение переменной макроса выглядит так, как хочет Oracle.
Например, чтобы установить ENDDT на сегодняшнюю дату, вы можете использовать:
data _null_;
call symputx('enddt',quote(put(today(),date11.),"'"));
run;
Что было бы так же, как
%let enddt='17-MAY-2022';
Похоже, что несколько недель назад наши администраторы баз данных обновили некоторые настройки в Oracle, которые повлияли на то, насколько строга база данных с точки зрения того, какие форматы она может принимать. Итак, версии, которые мы использовали ранее (ДД-МММ-ГГ), теперь неприемлемы.
Или вы просто перешли от таких строк, как 28-APR-22, которые, возможно, легче распознать в порядке ДЕНЬ-МЕСЯЦ-ГОД, к более неоднозначной строке, такой как 17-MAY-22, которая может означать сегодня, но также может означать почти 5 лет? тому назад?
Так что ответ @Tom был полезен - похоже, что наши администраторы баз данных несколько недель назад обновили некоторые настройки, которые повлияли на то, насколько строг Oracle в отношении того, какие форматы дат принимаются.
Что бы это ни стоило, переменные макроса даты создавались на лету с использованием неуклюжего шага данных, который считывался из набора данных ключа даты:
Вы заметите, что последняя часть строки даты, составленная для переменных bost, использует year2. формате, так что только две последние цифры года.
По мнению @Tom, это, по-видимому, сбивает с толку Oracle с точки зрения того, в каком веке он находится, поэтому работа зависает.
data dateparm;
set salesdata.week_end_date;
start = "'" || put(day(week_end_date - 6), z2.) || '-' || put(week_end_date - 6, monname3.) || '-' ||
put(week_end_date - 6, year2.) || "'";
end = "'" || put(day(week_end_date), z2.) || '-' || put(week_end_date, monname3.) || '-' ||
put(week_end_date, year2.) || "'";
call symput('start_dt', start);
call symput('end_dt', end);
run;
Однажды я изменил этот шаг, чтобы использовать year4. формат для последнего фрагмента, задание было выполнено без каких-либо инцидентов как в Unix, так и в E-guide. Пример ниже:
data dateparm;
set npdd.week_end_date;
start = "'" || put(day(week_end_date - 6), z2.) || '-' || put(week_end_date - 6, monname3.) || '-' ||
put(week_end_date - 6, year4.) || "'";
end = "'" || put(day(week_end_date), z2.) || '-' || put(week_end_date, monname3.) || '-' ||
put(week_end_date, year4.) || "'";
call symput('start_dt', start);
call symput('end_dt', end);
run;
Почему бы просто не использовать формат DATE11 для генерации строки DD-MMM-YYYY?
Похоже, вы просто спрашиваете об этом условии (
between &start_dt and &end_dt
), которое, как вы утверждаете, не работает. Но я не вижу нигде в вашем посте, где вы показываете выражение, которое действительно работает.