Сравнение дат в Oracle SQL


147

Я пытаюсь заставить его отображать количество сотрудников, нанятых после 20 июня 1994 г., но я получаю сообщение об ошибке "Недействительный идентификатор JUN. Пожалуйста, помогите, спасибо!"

Select employee_id, count(*)
From Employee
Where to_char(employee_date_hired, 'DD-MON-YY') > 31-DEC-95; 

1
Также обратите внимание, что вы можете использовать либо > <илиBETWEEN '' AND ''
Эндрю

Ответы:


307

31-DEC-95не является строкой и не является 20-JUN-94. Это числа с добавлением дополнительных деталей на конце. Это должно быть '31-DEC-95'или '20-JUN-94'- обратите внимание на апостроф, '. Это позволит вам провести сравнение строк.

Однако вы не выполняете сравнение строк; вы делаете сравнение дат . Вы должны преобразовать свою строку в дату. Либо с помощью встроенной TO_DATE()функции, либо литерала даты .

ВСТРЕТИТЬСЯ()

select employee_id
  from employee
 where employee_date_hired > to_date('31-DEC-95','DD-MON-YY')

У этого метода есть несколько ненужных подводных камней.

  • Как отмечалось в комментариях a_horse_with_no_name,, DECэто не обязательно означает декабрь. Это зависит от ваших NLS_DATE_LANGUAGEи NLS_DATE_FORMATнастроек. Чтобы убедиться, что ваше сравнение с работой в любой локали, вы можете вместо этого использовать модель формата datetime MM
  • 95-й год неточен. Вы знаете, что имеете в виду 1995 год, но что, если это был 50-й год, это 1950 или 2050 год? Всегда лучше быть откровенным
select employee_id
  from employee
 where employee_date_hired > to_date('31-12-1995','DD-MM-YYYY')

Литералы даты

Литерал даты является частью стандарта ANSI, что означает, что вам не нужно использовать специфические функции Oracle. При использовании литерала вы должны указать дату в формате, YYYY-MM-DDи вы не можете включать элемент времени.

select employee_id
  from employee
 where employee_date_hired > date '1995-12-31'

Помните, что тип данных Oracle date включает в себя элемент времени, поэтому дата без временной части эквивалентна 1995-12-31 00:00:00.

Если вы хотите включить временную часть, вам нужно будет использовать литерал временной метки, который принимает формат YYYY-MM-DD HH24:MI:SS[.FF0-9]

select employee_id
  from employee
 where employee_date_hired > timestamp '1995-12-31 12:31:02'

Дальнейшая информация

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

alter session set nls_date_format = 'DD.MM.YYYY HH24:MI:SS';

Это означает:

  • DD числовой день месяца, 1 - 31
  • MM числовой месяц года, 01 - 12 (01 января)
  • YYYYГод из четырех цифр - на мой взгляд, это всегда лучше, чем год из двух цифр, YYпоскольку нет никакой путаницы с тем, к какому столетию вы имеете в виду.
  • HH24 час дня, 0-23
  • MI минута часа, 0-59
  • SS секунда минуты, 0-59

Вы можете узнать свой текущий язык и настройки языка даты с помощью запроса, V$NLS_PARAMETERSsа полный диапазон допустимых значений - с помощью запроса V$NLS_VALID_VALUES.

дальнейшее чтение


Кстати, если вы хотите, count(*)вам нужно сгруппировать поemployee_id

select employee_id, count(*)
  from employee
 where employee_date_hired > date '1995-12-31'
 group by employee_id

Это дает вам количество за employee_id .


13
+1 за использование маски формата в to_date (). Обратите внимание, что это все равно может не работать в других средах из-за разных языковых настроек. DECне обязательно всегда действительный месяц. Обычно лучше использовать числа вместо имен
a_horse_with_no_name

1
Вы можете указать время с помощью литерала ANSI - вам просто нужно указать timestampлитерал вместо dateлитерала: timestamp '2015-01-30 19:42:04' (потому что в ANSI SQL dateтип данных не имеет времени, а имеет только timestampтип данных).
a_horse_with_no_name 03 фев.15,

1
Литералы даты ANSI - это действительно краткий способ сравнения необходимости каждый раз вводить TO_DATE и Date-Format. Хорошо для ЛЕНИВШИХ разработчиков вроде меня. На самом деле следует обратить внимание на DATE 2016-04-01средства 2016-04-01 00:00:00. И я думаю, что этот синтаксис работает с Oracle 9i, поскольку именно здесь синтаксис ANSI-SQL был введен в Oracle.
LeOn - Хан Ли

1
Мое мышление значительно изменилось за последние 4 года @Leon :-) 'Я обновил ответ. Я упоминал, что литерал даты не включает элемент времени, но я назвал это более явно, как вы заявили. Расширенная поддержка 9i закончилась почти 6 лет назад ... и была выпущена 14 лет назад. Для подавляющего большинства пользователей это уже не должно быть актуально.
Бен


6

Вывод,

to_char работает по-своему

Так,

Всегда используйте этот формат ГГГГ-ММ-ДД для сравнения вместо ММ-ДД-ГГ или ДД-ММ-ГГГГ или любого другого формата.


4

Вы можете использовать trunc и to_date следующим образом:

select TO_CHAR (g.FECHA, 'DD-MM-YYYY HH24:MI:SS') fecha_salida, g.NUMERO_GUIA, g.BOD_ORIGEN, g.TIPO_GUIA, dg.DOC_NUMERO, dg.* 
from ils_det_guia dg, ils_guia g
where dg.NUMERO_GUIA = g.NUMERO_GUIA and dg.TIPO_GUIA = g.TIPO_GUIA and dg.BOD_ORIGEN = g.BOD_ORIGEN
and dg.LAB_CODIGO = 56 
and trunc(g.FECHA) > to_date('01/02/15','DD/MM/YY')
order by g.FECHA;

3

из вашего запроса:

Select employee_id, count(*) From Employee 
Where to_char(employee_date_hired, 'DD-MON-YY') > '31-DEC-95' 

Я думаю, это не для отображения количества сотрудников, нанятых после 20 июня 1994 года. Если вы хотите показать количество сотрудников, вы можете использовать:

Select count(*) From Employee 
Where to_char(employee_date_hired, 'YYYMMMDDD') > 19940620 

Я думаю, что лучше всего сравнить даты, которые вы можете использовать:

employee_date_hired > TO_DATE('20-06-1994', 'DD-MM-YYYY');
or
to_char(employee_date_hired, 'YYYMMMDDD') > 19940620;

-4

Одинарная кавычка должна быть там, поскольку дата преобразована в символ.

Выберите employee_id, count (*)
От сотрудника
Где to_char (employee_date_hired, 'DD-MON-YY')> '31 -DEC-95 ';

1
Этот SQL использует неявный формат даты, он не всегда будет работать.
Jon Heller

5
Он работает нормально только для ваших конкретных настроек NLS_ *, он может не работать на других клиентах или серверах. Принятый ответ объясняет, почему важен явный формат даты.
Jon Heller

Этот метод сравнивает строки, а не даты. Вторая строка начинается с «3», поэтому сравнение работает как «в алфавитном порядке». Интересно, что этот тип сравнения действительно работает (вроде как случайно), если вы используете такой формат, как ГГГГ-ММ-ДД. Но, конечно, лучше сравнивать даты с датами ...
Ник Перкинс,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.