Comparando datas no Oracle SQL


141

Estou tentando fazer com que ele mostre o número de funcionários contratados após 20 de junho de 1994, mas recebo um erro dizendo "Identificador inválido de JUN". Por favor, ajude, obrigado!

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

1
Note também que você pode usar um > <ouBETWEEN '' AND ''
Andrew

Respostas:


296

31-DEC-95não é uma corda, nem é 20-JUN-94. São números com algumas coisas extras adicionadas no final. Deve ser '31-DEC-95'ou '20-JUN-94'- observe as aspas simples ',. Isso permitirá que você faça uma comparação de cadeias.

No entanto, você não está fazendo uma comparação de cadeias; você está fazendo uma comparação de datas . Você deve transformar sua string em uma data. Ou usando a TO_DATE()função interna ou um literal de data .

ATÉ A PRESENTE DATA()

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

Este método tem algumas armadilhas desnecessárias

  • Como a_horse_with_no_name observou nos comentários,, DECnão significa necessariamente dezembro. Depende das suas configurações NLS_DATE_LANGUAGEe NLS_DATE_FORMAT. Para garantir que a sua comparação com o trabalho em qualquer local que você pode usar o modelo de formato de data e hora MM em vez
  • O ano de 95 é inexato. Você sabe que quer dizer 1995, mas e se fosse 50, são 1950 ou 2050? É sempre melhor ser explícito
select employee_id
  from employee
 where employee_date_hired > to_date('31-12-1995','DD-MM-YYYY')

Literais de data

Um literal de data faz parte do padrão ANSI, o que significa que você não precisa usar uma função específica do Oracle. Ao usar um literal, você deve especificar sua data no formato YYYY-MM-DDe não pode incluir um elemento de hora.

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

Lembre-se de que o tipo de dados de data do Oracle inclui um elemento de hora, portanto a data sem uma parte de hora é equivalente a 1995-12-31 00:00:00.

Se você deseja incluir uma parte do tempo, precisará usar um literal de carimbo de data / hora, que assume o formato YYYY-MM-DD HH24:MI:SS[.FF0-9]

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

Outras informações

NLS_DATE_LANGUAGEé derivado de NLS_LANGUAGEe NLS_DATE_FORMATé derivado de NLS_TERRITORY. Eles são definidos quando você criou o banco de dados inicialmente, mas podem ser alterados alterando o arquivo de parâmetros de inicialização - somente se realmente necessário - ou no nível da sessão usando a ALTER SESSIONsintaxe. Por exemplo:

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

Isso significa:

  • DD dia numérico do mês, 1 - 31
  • MM mês numérico do ano, 01 a 12 (janeiro é 01)
  • YYYYAno de 4 dígitos - na minha opinião, isso é sempre melhor do que um ano de 2 dígitos, YYpois não há confusão com o século a que você está se referindo.
  • HH24 hora do dia, 0 - 23
  • MI minuto da hora, 0 - 59
  • SS segundo, 0-59

Você pode descobrir suas configurações atuais de idioma e idioma de data consultando V$NLS_PARAMETERSse toda a gama de valores válidos consultando V$NLS_VALID_VALUES.

Leitura adicional


Aliás, se você quiser o count(*)que precisa agrupar poremployee_id

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

Isso fornece a contagem por employee_id .


13
+1 para usar uma máscara de formato em to_date (). Observe que isso ainda pode falhar em ambientes diferentes devido a configurações de idioma diferentes. DECnem sempre é necessariamente um mês válido. Geralmente é melhor para usar números em vez de nomes
a_horse_with_no_name

1
Você pode especificar um horário com um literal ANSI - você só precisa especificar um timestampliteral em vez de um dateliteral: timestamp '2015-01-30 19:42:04' (porque no ANSI SQL o datetipo de dados não tem tempo, apenas o timestamptipo).
A_horse_with_no_name

1
Os literais de data ANSI são realmente uma maneira concisa de comparar a necessidade de digitar TO_DATE e formato de data toda vez. Bom para desenvolvedores do LAZY como eu. Uma coisa a notar é realmente os DATE 2016-04-01meios 2016-04-01 00:00:00. E acho que essa sintaxe funciona desde o Oracle 9i, pois é aqui que a sintaxe ANSI-SQL foi introduzida no Oracle.
LeOn - Han Li 31/03

1
Meu pensamento evoluiu significativamente nos últimos 4 anos @Leon :-) 'Atualizei a resposta. Mencionei que um literal de data não incluía um elemento de tempo, mas eu o expliquei de maneira mais explícita, como você afirmou. O suporte estendido 9i terminou há quase 6 anos ... e foi lançado há 14 anos. Não deve mais ser relevante para a grande maioria dos usuários.
Ben


6

Conclusão,

to_char trabalha à sua maneira

Assim,

Sempre use este formato AAAA-MM-DD para comparação em vez de MM-DD-AA ou DD-MM-AAAA ou qualquer outro formato


4

Você pode usar trunc e to_date da seguinte maneira:

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;

2

da sua consulta:

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

acho que não é necessário exibir o número de funcionários contratados após 20 de junho de 1994. se você deseja mostrar o número de funcionários, pode usar:

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

Eu acho que é uma boa prática comparar datas que você pode usar:

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

-4

Aspas simples devem estar lá, desde a data convertida em caractere.

Selecione employee_id, count (*)
Do funcionário
Onde to_char (funcionário_data_contratado, 'DD-MON-AA')> '31 -DEC-95 ';

1
Este SQL usa um formato de data implícito, nem sempre funciona.
Jon Heller

5
Ele está funcionando bem apenas para suas configurações específicas de NLS_ *; pode não funcionar em outros clientes ou servidores. A resposta aceita explica por que um formato de data explícito é importante.
Jon Heller

Este método está comparando cadeias de caracteres, não datas. A segunda sequência começa com um "3", então a comparação funciona como "ordem alfabética". Curiosamente, esse tipo de comparação realmente funciona (mais ou menos por acidente) se você usar um formato como AAAA-MM-DD. Mas, claro, é melhor para comparar as datas para datas ...
Nick Perkins
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.