Oracle OCI: consulta com campo de data
Pergunta
Cliente compilado com OCI: 10.2.0.4.0
Servidor: Oracle9i Enterprise Edition Release 9.2.0.4.0
A consulta problemática é:
SELECT CODIGO FROM LOG WHERE TEL = :telnumber AND DATE_PROC = '05-JUL-08'
Descrição da tabela:
SQL>describe LOG;
TEL NOT NULL VARCHAR2(15)
CODIGO NOT NULL VARCHAR2(20)
DATE_PROC NOT NULL DATE
Por mais simples que pareça, quando executado diretamente no servidor com sqlplus, ele retorna um resultado, mas quando executado do aplicativo que usa OCI, essa consulta retorna OCI_NO_DATA
sempre. No começo, o valor da data também era um espaço reservado, mas descobri que mesmo dando a um literal como '05-JUL-08'
não funcionou. Eu tentei o seguinte:
- Eu tentei o básico: consultar o banco de dados do cliente funciona. É esse que me dá problemas
O seguinte funciona:
SELECT CODIGO FROM LOG WHERE TEL = :telnumber
Executando
ALTER SESSION SET NLS_DATE_FORMAT="DD-MM-YYYY";
antes da consulta no servidor e no cliente. Mesmo resultado: o servidor retorna dados, clienteOCI_NO_DATA
- Tentei mudar
DATE_PROC
formato, combinando isso com o uso deTO_DATE()
. Mesmo resultado. - Pesquisado, pesquisado, pesquisado. Sem resposta
Estou um pouco desesperado para encontrar uma resposta, apreciaria qualquer ajuda e pode fornecer tantos detalhes mais necessários. Obrigado.
--- Mais informações ---
update log set DATE_PROC = TO_DATE('20080705162918', 'YYYYMMDDHH24MISS') where CODIGO='BancoOne';
Eu tentei combinações diferentes usando trunc () e "alter session Set NLS_DATE_FORMAT" ... e é isso que recebo:
SELECT CODIGO FROM LOG WHERE TEL = 11223344 AND DATE_PROC = TO_DATE('20080705162918', 'YYYYMMDDHH24MISS');
No servidor: Retornos: "Bancoone" (bom valor)
No aplicativo OCI: Retorna OCI_NO_DATA
SELECT CODIGO FROM LOG WHERE TEL = 11223344 AND trunc(DATE_PROC) = TO_DATE('20080705', 'YYYYMMDD');
No servidor: Retornos: "Bancoone"
No aplicativo OCI: retorna "Bancoone"
Portanto, o ponto é: por que o aplicativo OCI está fornecendo resultados diferentes se ambos estão acessando o mesmo servidor de banco de dados?
Além disso, para esclarecer o objetivo do aplicativo OCI: ele tem uma consulta a ser configurada pelo usuário. A idéia é que o usuário adapte a consulta conforme desejado para se encaixar no campo Data presente no banco de dados de destino, é por isso que não devo incluir as instruções "Alter Session Set NLS_DATE_FORMAT" no meu código, pois não vou saber o formato da data. Dessa forma, quero fornecer flexibilidade ao usuário e não confie em formatos de data específica. Isso faz sentido? Alguma sugestão?
Solução
Sua coluna date_proc é uma data, você deve sempre Compare com uma data e Nunca confie na conversão implícita de dados.
Experimente isso:
SELECT CODIGO FROM LOG WHERE TEL = :telnumber AND DATE_PROC = DATE '2008-07-05'
ou isto:
SELECT CODIGO
FROM LOG
WHERE TEL = :telnumber
AND DATE_PROC = to_date('05-JUL-08', 'DD-MON-RR')
Se puder, evite usar um formato de data em seu código que usa letras por meses (porque o código vai falhar Quando você muda a linguagem padrão) e apenas dois chars por anos (ambiguidade do século). Eu gosto de usar 'YYYY/MM/RR'
Porque esse formato será classificado como a data original.
Outras dicas
Como os registros foram inseridos?
Os campos de data armazenam informações de tempo e, portanto, ao inserir registros usando o SysDate, o campo de data conterá diferentes "valores" para registros nesse dia. Quando você executa Date_proc = '05 -Jul-08 ', você está dizendo onde Date_proc é igual exatamente em 5 de julho de 2008 às 12:01:00. Se você inseriu o registro às 12:01 com o Sysdate, ele não será devolvido. Você já tentou usar um entre ou trunc?
Aqui está um exemplo:
drop table test_date;
create table test_date (id number, ud date);
insert into test_date values (1, '15-jan-10');
insert into test_date values (2, '15-jan-10');
insert into test_date values (3, '15-jan-10');
insert into test_date values (6, sysdate); -- sysdate as of writing is 15-JAN-2010 08:01:55
insert into test_date values (7, sysdate); -- sysdate as of writing is 15-JAN-2010 08:01:55
insert into test_date values (8, '16-jan-10');
commit;
select id, ud, to_char(ud, 'dd-MON-yyyy HH:MM:SS') from test_date where ud = '15-jan-10';
---------------------- ------------------------- --------------------
1 15-JAN-10 15-JAN-2010 12:01:00
2 15-JAN-10 15-JAN-2010 12:01:00
3 15-JAN-10 15-JAN-2010 12:01:00
select id, ud, to_char(ud, 'dd-MON-yyyy HH:MM:SS') from test_date where trunc(ud) = '15-jan-2010';
---------------------- ------------------------- --------------------
1 15-JAN-10 15-JAN-2010 12:01:00
2 15-JAN-10 15-JAN-2010 12:01:00
3 15-JAN-10 15-JAN-2010 12:01:00
6 15-JAN-10 15-JAN-2010 08:01:55
7 15-JAN-10 15-JAN-2010 08:01:55
Eu diria que você está fazendo a pergunta errada.
O Oracle conta com o compartilhamento de SQL para desempenho e quando você coloca uma string, como '20080705', o SQL não pode ser compartilhado. Detalhes aqui.
Portanto, o valor dos dados deve ser um espaço reservado e deve ser do tipo de dados correto (data). O exemplo aqui deve ajudar a fazer isso.
Dito isto, se isso funcionar
SELECT CODIGO FROM LOG
WHERE TEL = 11223344 AND
trunc(DATE_PROC) = TO_DATE('20080705', 'YYYYMMDD');
Mas isso não
SELECT CODIGO FROM LOG
WHERE TEL = 11223344
AND DATE_PROC = TO_DATE('20080705162918', 'YYYYMMDDHH24MISS');
Eu estaria tentando
SELECT TO_CHAR(DATE_PROC,'DD-MM-YYYY HH24:MI:SS') FROM LOG
WHERE TEL = 11223344 AND
trunc(DATE_PROC) = TO_DATE('20080705', 'YYYYMMDD');
Acabamos de receber esse erro (OCI_NO_DATA) ser causado por alguém que muda a hora do dia no PC. Quando eles colocam a data/hora de volta à hora certa, o aplicativo começou a funcionar bem.