08. februar 2000 - 09:49Der er
13 kommentarer og 1 løsning
Dato fejl
I et system som jeg - meget nødtvunget - yder support på findes en sql script som ser således ud:
select * from contrib where inmsuranceprogramid = <parameterværdi> and to_date(startperiod,'dd-mm-yyyy') > trunc(sysdate)
Omtalte script har altid fungeret - indtil efter år 2000.Herefter fungerer det kun en gang imellem! Til tider kommer der en fejlmeddelse som fortæller, at dato formattet ikke en langt nok.
Jeg skal for en god ordens skyld fortælle to ting: For det første bliver session dato formattet (NVL) sat til dd-mm-yyyy. For det andet er feltet startperiod defineret som varchar2 og kan indeholde en 'talværdi' fx. 13, tegnet '-' og altså en dato.
ja, ja jeg ved det - tåbeligt database design med en attribut der kan fortolkes på mange forskellige måder, men jeg har som nævnt ikke udviklet lortet. Faktisk er jeg primært Delphi programmør og ikke den store Oracle haj, men selv jeg kunne næppe finde på ovenstående design ;-)
Mit spørgsmål er - hvad fanden kan være årsagen til en sådan fejl? Kan Oracle's sql parse være involveret i nævnte problemstilling?
Lad mig afslutningsvis nævne, at omtalte sql script fungere upåklagelig på vores test database, men hvis jeg tager et kopi via CREATE TABLE Tmp_Contrib as (select * from contrib)så virker omtalte sql-script ikke!? Eftersom indholdet af den oprindelige contrib og backup kopien er den samme kan det vel næppe være datagrundlaget som kan medfører fejlen?!
Jeg tror kun det kan være startperiod der laver unoder. Er du 100% sikker på at startperiod indeholder valide datoer i DD-MM-YYYY formatet i *samtlige* de rækker du SELECT'er?
Prøv evt. blot at køre SELECT to_date(startperiod,'dd-mm-yyyy') FROM contrib og se hvad der sker.
Session dato formatet burde ikke betyde noget i denne her sammenhæng, da der netop benyttes explicit konvertering mellem formaterne. Det er kun hvis man bruger implicit format konvertering, at session formatet er vigtigt (fx. WHERE datofelt = varchar2felt).
Jeg skal lige forstå din dato-strengs format. Har jeg forstået det rigtigt, hvis den fx. ser sådan ud: '10-21-09-1999' ? Og ser din streng ALTID sådan ud? Eller er der nogle gange, hvor den kun indeholder datoen ('21-09-1999')?
Jeg kan ikke umiddelbart få den til at æde den første streng. Men hvis jeg indsætter begge strenge i en tabel, og laver en query hvor der kommer andre where-clauses på, som udelukker den illegale streng, så får jeg ingen problemer, da ORACLE åbenbart vælger at evaluere de(n) andre where-clauses først, og ikke evaluerer to_date for de rows der ikke opfylder dem. Det vil sige, at hvis jeg indsætter følgende i min database:
TIMESTAMP: ID: '10-10-1999' 1 'gnyfferblaf' 2
Så kan jeg altså godt få følgende forspørgsel til at virke: select * from TestDate where to_date(TimeStamp,'dd-mm-yyyy') < trunc(sysdate) and id=1
Men ikke: select * from TestDate where to_date(TimeStamp,'dd-mm-yyyy') < trunc(sysdate) and id=2
Kan det være sådan noget, eller har jeg misforstået dit format?
Nej, jeg er helt sikker på at samtlige rækker i CONTRIB tabellens startperiod attribut IKKE indeholder en streng med et valid dato format. Problemet med designet er nemlig, at strengen nogle gange kun indeholder et tal fx. 83 (men altså ikke nogen dato format). Det som sker er at InsuranceprogramId udvælger de rækker i CONTRIB tabellen som indeholder strenge på et valid dato format. Jeg har naturligvis først undersøgt om det så også er tilfældet på det konkrete insuranceprogramId, der i første omgang udløste fejlen.
Umiddelbart er sql parseren under mistanke fordi den eneste grund til, at sql-scriptet ikke virker på et eksakt kopi af tabellen kunne være at rækkerne indsættes i en anden rækkefølge og parseren derfor fortolker indholdet af tabellen anderledes(?)
Det lyder rigtigt hvad JHH siger. Det er også nogenlunde hvad jeg har fået testet mig frem til. Men er det nu også sådan dit format ser ud? Hvis ikke, kan du så ikke sætte nogle eksempler ind på, hvad feltet indeholder?
som det fremgår vil sqlscriptet selvfølgelig fejle, hvis insuranceprogram id IKKE er 2 eller 4 fordi de øvrige strenge ikke opfylder datoformattet. Problemet opstår også når insuranceprogramId = 2 eller 4. Som tidligere nævnt så bestod min første undersøgelse i at fastslå, hvorvidt de enkelte række også indeholdte en valid dato streng på den konkrete insuranceprogramid - det gør de. Selv om database designet stinker så har denne sammenblanding af betydning i startperiod fungerer før. Det mærkelige er nemlig, at det også engang imellem virker på nuværende tidspunkt. Kan der være pillet ved nogle oracle konfigurations parameter som påvirker eksekveringen af scriptet fx. rule baset parsing af sql scriptet?
Ud fra fejlbeskeden og hvad din database indeholder, så lyder det altså meget som om den prøver at parse en streng der ikke er en dato.
Kan du for en god ordens skyld ikke sætte en "and length(StartPeriod)=10" på din query? Hvis det stadig går galt, så begynder jeg at tro på, at det ikke er fordi du parser en ikke-dato-streng.
Det vil jeg prøve DMK. Jeg vender tilbage når jeg har haft tid til at se nærmere på problemet. Jeg har som foreslået ændret på where klausulen således at den ser således ud:
where to_date(startperiod,'dd-mm-yyyy') > trunc(sysdate) and insuranceprogramId = <parameterværdi>
Det gik godt! Men hvorfor fanden skulle sql parseren lige pludselig begynde at opfører sig anderledes når den evaluere et ellers validt datagrundlag?
Jeg har nu også forsøgt en length check, men den fejler stadigvæk. Det konkrete insuranceprogramid har udlukkende strenge med det korrekte dato format og de er alle 10 tegn lange. Sidstnævnte har jeg også undersøgt på baggrund af dit forslag.
select * from (select * from contrib where inmsuranceprogramid = <parameterværdi> ) where to_date(startperiod,'dd-mm-yyyy') > trunc(sysdate)
Jeg ved ikke om evaluerings rækkefølgen for where kan have noget at gøre med det. Hvis ORACLE nogle gange kan finde på, at evaluere to_date før inmsuranceprogramid, så vil det naturligvis gå galt.
Med ovenstående sql er du sikker på, at det ikke vil ske.
Ja dit sql script virker. Hvorvidt det vil vedblive med det er usikkert, men jeg har accepteret svaret fordi din hjælp har kastet lys over hele problemstilingen.
Tak for hjælpen dmk
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.