#sql #oracle
#sql #Oracle
Вопрос:
Я пытаюсь запустить sql-скрипт для тестовой базы данных. Я получаю сообщение об ошибке «строка литерала не соответствует строке формата» — странно то, что мой коллега запускает тот же запрос на том же тестовом сервере и не получает никаких ошибок, только когда я его запускаю, я получаю ошибки. Я полностью запутался в этом вопросе. Куда мне отсюда идти?
Я запускаю свой запрос с помощью командной строки SQLPlus. Я получаю сообщение об ошибке в первой строке: выберите NVL…..
select NVL(to_char(add_months(to_date(max(mem.birth_date)), 780), 'yyyymmdd'), ' ')
into local_turn_65_on
from member mem
where mem.member_id in (
select cmr.member_id
from case_member cmr
where cmr.case_id = due_tasks_rec.case_id
and cmr.current_row_ind = 'Y'
and cmr.case_member_end_date = 29991231
and cmr.case_member_role in ('AA','AB','AD','DP'))
and mem.update_end_date = 29991231
and mem.birth_date between
(to_char(add_months(sysdate,-780), 'yyyymmdd'))
and
(to_char(add_months(sysdate,-780), 'yyyy') || '1231');
Если бы кто-нибудь мог указать мне правильное направление, я был бы очень признателен!
Комментарии:
1. Какой тип данных
birth_date
? Если это adate
, то замените:to_date(max(mem.birth_date))
наmax(mem.birth_date)
2. это не создаст никакой разницы, если это дата, заменив на_date, хотя @a_horse_with_no_name
3. @casper1111 я предполагаю, что это процедура / функция / блок, можете ли вы также опубликовать какой-нибудь код над этой ошибкой?
4. тип данных — число (8)
5. @HimanshuAhuja: если это дата, то
to_date()
вызов должен быть удален , а не заменен. Вызовto_date()
значения, которое уже являетсяdate
, создаст подобные проблемы.
Ответ №1:
тип данных — число (8)
Затем вам нужно указать модель формата для преобразования этого числа в дату; вместо
to_date(max(mem.birth_date))
вам нужно сделать:
to_date(max(mem.birth_date), 'YYYYMMDD')
или даже более явно:
to_date(to_char(max(mem.birth_date)), 'YYYYMMDD')
На данный момент ваш код полагается на настройки NLS вашего текущего сеанса для получения используемой модели формата, и ошибка означает, что она не соответствует передаваемому вами значению. Причина, по которой ваш коллега может успешно выполнить один и тот же запрос, заключается в том, что их сеанс имеет разные настройки NLS. Вот почему вы не должны полагаться на настройки NLS (или неявные преобразования — они часто идут рука об руку), поскольку у вас нет контроля над тем, как другие люди будут запускать ваш код.
Вы можете увидеть эффект на урезанном примере:
alter session set nls_date_format = 'DD-Mon-RR';
with mem (birth_date) as (select 20190328 from dual)
select NVL(to_char(add_months(to_date(max(mem.birth_date)), 780), 'yyyymmdd'), ' ')
from mem;
ORA-01861: literal does not match format string
или даже проще:
with mem (birth_date) as (select 20190328 from dual)
select to_date(max(mem.birth_date))
from mem;
ORA-01861: literal does not match format string
Добавление модели формата создает дату:
with mem (birth_date) as (select 20190328 from dual)
select to_date(max(mem.birth_date), 'YYYYMMDD')
from mem;
TO_DATE(M
---------
28-Mar-19
и ваша настройка и преобразование теперь тоже работают:
with mem (birth_date) as (select 20190328 from dual)
select NVL(to_char(add_months(to_date(max(mem.birth_date), 'YYYYMMDD'), 780), 'yyyymmdd'), ' ')
from mem;
NVL(TO_C
--------
20840328
Вы также должны хранить даты как даты, а не как числа, но это отдельная проблема…
Комментарии:
1. Я почти уверен, что casper1111 вернется и скажет, что он / она не проектировал базу данных — это был кто-то другой, кто решил, что сохранение даты в виде числа было бы разумным поступком. Те люди, которые занимаются подобными вещами, очевидно, никогда не были вынуждены жить со своим неправильным выбором.
2. Да, вот почему это отдельная проблема, и ответ не просто «не делай этого» — как бы мне (слишком часто) ни хотелось, чтобы это было *
![]()
3. Спасибо всем за вашу помощь. @Alex Poole — спасибо! — путем добавления ‘yyyymmdd’ после (mem.birth_date) исправлена моя проблема! Теперь строка кода выглядит так: выберите NVL(to_char(add_months(to_date(max(mem.birth_date), ‘ггггмдд’), 780), ‘ггггмдд’), ‘ ») который работает!
4. @Alex Poole Это должно было работать и с to_date, просто сделать его доступным для чтения в том формате, в котором он получен, например, yyyymmdd, или использовать формат даты СУБД по умолчанию, который работает так же. Что вы скажете по этому поводу?
5. @HimanshuAhuja — это то, что я сделал — предоставил модель формата для существующего
to_date()
вызова. Установка модели формата по умолчанию (т. Е. сеанса) все равно будет зависеть от настроек NLS — даже если они установлены в том же скрипте, в котором выполняется запрос. Этого лучше вообще избегать.
Ответ №2:
Я предполагаю, что дополнительное, to_char
должно быть, решило проблему, просто сделав этот числовой формат символьной строкой, а затем использовав to_date и добавив месяцы, сработало бы.
select NVL(to_char(add_months(to_date(to_char(max(mem.birth_date))), 780), 'yyyymmdd'), ' ')
Комментарии:
1. Нет,
birth_date
это число, поэтому вы преобразуетеmax(mem.birth_date)
из числа в строку, что уже происходило неявно; а затем преобразуете эту строку в дату — по-прежнему без предоставления надлежащей модели формата. Это будет работать, только еслиNLS_DATE_FORMAT
установлено значение YYYYMMDD. Итак, сеанс коллеги настроен таким образом, но сеанс capser1111 настроен по-другому. (Итак, не полагайтесь на NLS … *![]()