"Jens Gregersen" <jensg@oncable.dk> skrev i en meddelelse
news:41e58fb0$0$310$edfadb0f@dread11.news.tele.dk...
>
> "Kaj Julius" <julius.x@lindbjergparken.nospm.dk> skrev i en meddelelse
> news:41d4a7a8$0$169$edfadb0f@dread11.news.tele.dk...
>>
>> "Jens Gregersen" <jensg@oncable.dk> skrev i en meddelelse
>> news:41d2fc38$0$206$edfadb0f@dread11.news.tele.dk...
>>>
>>> "Kaj Julius" <julius.x@lindbjergparken.nospm.dk> skrev i en meddelelse
>>> news:41d1f8c1$0$180$edfadb0f@dread11.news.tele.dk...
>>>>
>>>>> SELECT
>>>>> A.ITOISSC,A.ICSECNO,A.IIIION0,A.DTOESHP,A.IIIIBV0
>>>>>
>>>>> FROM D2D A
>>>>>
>>>>> skal forøges med 1 kolonne, der er lig med værdien i a.dtoeshp + 2
>>>>> dage.
>>>>
>>>> Hvis udgangspunktet (A.DTOESHP) er defineret som et date field, ville
>>>> du normalt bare kunne tilføje
>>>>
>>>> , A.DTOESHP + 2 DAYS AS nytfeltnavn
>>>>
>>>> men da du jo antyder, at A.DTOESHP er et numerisk felt, er det straks
>>>> sværere, da det først skal omdannes til et datofelt, hvilket betyder en
>>>> omvej over et alfafelt, hvor året er omdannet til et 4 cifret årstal,
>>>> sådan at det bliver til en normalt ISO dato. Derfor tilføjes 20000000
>>>> eller 19000000, afhængig af årstal (år < 30 antages at tilhøre dette
>>>> årtusind). Ydermere skal det alfanumereiske felt omdannes til formatet
>>>> YYYY-MM-DD, før konverteringen til datoformat kan gennemføres.
>>>> Resultatet? se her:
>>>>
>>>> CAST(SUBSTR(CHAR(A.DTOESHP + CASE WHEN A.DTOESHP < 300000 THEN 20000000
>>>> ELSE 19000000 END), 1, 4) CONCAT '-' CONCAT SUBSTR(CHAR(A.DTOESHP +
>>>> CASE WHEN A.DTOESHP < 300000 THEN 20000000 ELSE 19000000 END), 5, 2)
>>>> CONCAT '-' CONCAT SUBSTR(CHAR(A.DTOESHP + CASE WHEN A.DTOESHP < 300000
>>>> THEN 20000000 ELSE 19000000 END), 7, 2) AS DATE) + 2 DAYS AS
>>>> nytfeltnavn
>>>>
>>>> Som du kan se, så er det aldrig en god idé at opbevare datoer i
>>>> numeriske felter, hvis man skal arbejde videre med dem...
>>>>
>>>> mvh.
>>>> Kaj
>>>
>>> Hej
>>>
>>> tak for forsøget, har imellemtiden fundet at feltet dtoeshp er et
>>> karakterfelt, gør det det nemmere? den løsning med at ændre som du
>>> beskriver ser ud til at være for langhåret for mig at arbejde med.
>>>
>>> Her under lidt mere fra databasen d2d:
>>>
>>> ITOISSC ICSECNO IIIION0 DTOESHP IIIIBV0
>>> ------- ------------- ----------- ------- ------------
>>> 724 484041AP38300 KI869R 041214 D20043490054
>>> 724 484041AP80100 KI869N 041214 D20043490054
>>>
>>> Vil være glad for at høre nærmere - arbejder selv videre med probl.
>>>
>>> Hej fra Jens Gregersen
>>>
>>
>> Hej Jens
>>
>> Jo, det bliver da lidt lettere, når der er tale om et alfa-felt (en
>> konvertering mindre)...
>>
>>
>> Problemet med at arbejde med datoer er, at ikke alle måneder har lige
>> mange dage osv. Dette betyder, at det at tilføje et antal dage til en
>> dato ikke er så lige til endda. Man skal også tage højde for skudår mm.
>> Derfor har de fleste databaser mulighed for at bruge en felttype som er
>> specielt egnet til at repræsentere en dato. Har man først defineret et
>> felt som en datotype, har de fleste SQL varianter desuden et mindre
>> arsenal af funktioner til at beregne på disse datofelter.
>>
>> DB2 er ikke anderledes. Også den skal have have data i datofelter for at
>> kunne beregne på dem. Du har nu et alfafelt, indeholdende en dato. Ikke
>> godt!! Du er nødt til at få denne dato konverteret til et "rigtigt"
>> datofelt. Dette kan gøres ved at "caste" det felt du har til et datofelt.
>> Men for at kunne gøre det, skal alfafeltet indeholde datoen i formatet
>> YYYY-MM-DD (også kaldet ISO formatet, fordi den er defineret af
>> International Standards Organisation) - altså f.eks. 2004-12-22. Desværre
>> indeholder dit felt kun værdien 041222 - der mangler altså oplysninger om
>> hvilket århundrede datoen vedrører, ligesom der skal være bindestreg
>> mellem årstallet, måneden og dagen.
>>
>> At tilføje bindestregerne er forholdsvist enkelt, idet det kan gøres ved
>> at splitte værdien op i tre dele vha. SUBSTR funktionen og sætte dem
>> sammen igen med CONCAT operatoren, idet vi tilføjer en bindestreg:
>>
>> SUBSTR(DTOESHP, 1, 2) CONCAT '-' CONCAT SUBSTR(DTOESHP, 3, 2) CONCAT '-'
>> CONCAT SUBSTR(DTOESHP, 5, 2)
>>
>> Resultatet af dette er en streng med formatet 04-12-22. Desværre er dette
>> ikke nok til at DB2 anerkender den som en datostreng. Årstallet skal være
>> på 4 tegn. En dato kan som den viste kan teoretisk være et hvilket som
>> helst århundrede, f.eks. 1804-12-22. Man er derfor nødt til at vedtage en
>> konvention for konverteringen, f.eks. at hvis det to-cifrede årstal er
>> mindre end 30, ligger året i det 2100 århundrede, altså f.eks.
>> 2004-12-22, mens det ellers ligger i det 20. århundrede, f.eks. vil
>> 981222 skulle opfattes som 1998-12-22.
>>
>> Datoen skal altså tilføjes enten 19 eller 20. Dette kan gøres med en CASE
>> sætning, hvor man tester på de første to tegn (som vi igen uddrager med
>> SUBSTR funktionen:
>>
>> CASE WHEN SUBSTR(DTOESHP, 1, 2) < '30' THEN '20' ELSE '19' END
>>
>> Det hele sættes nu sammen til en korrekt ISO dato streng:
>>
>> CASE WHEN SUBSTR(DTOESHP, 1, 2) < '30' THEN '20' ELSE '19' END CONCAT
>> SUBSTR(DTOESHP, 1, 2) CONCAT '-' CONCAT SUBSTR(DTOESHP, 3, 2) CONCAT '-'
>> CONCAT SUBSTR(DTOESHP, 5, 2)
>>
>> Resultatet er en streng hvor 041222 er konverteret til 2004-12-22 og
>> 981222 er konverteret til 1998-12-22
>>
>> Se det er jo fint nok, men for at kunne arbejde med denne datostreng,
>> skal den omdannes til et rigtig dato format. Dette gøres med en CAST
>> funktion:
>>
>> CAST(CASE WHEN SUBSTR(DTOESHP, 1, 2) < '30' THEN '20' ELSE '19' END
>> CONCAT SUBSTR(DTOESHP, 1, 2) CONCAT '-' CONCAT SUBSTR(DTOESHP, 3, 2)
>> CONCAT '-' CONCAT SUBSTR(DTOESHP, 5, 2) AS DATE)
>>
>> Vi har nu en rigtig datovariabel, som vi kan arbejde videre med, f.eks.
>> addere 2 dage til værdien:
>>
>> CAST(CASE WHEN SUBSTR(DTOESHP, 1, 2) < '30' THEN '20' ELSE '19' END
>> CONCAT SUBSTR(DTOESHP, 1, 2) CONCAT '-' CONCAT SUBSTR(DTOESHP, 3, 2)
>> CONCAT '-' CONCAT SUBSTR(DTOESHP, 5, 2) AS DATE) + 2 DAYS
>>
>> I eksemplet hvor DTOESHP indeholdt værdien 041222, vil værdien af
>> ovenstående nu være 2004-12-24. Variablen vil desuden være et rigtigt
>> datofelt, som vil kunne formateres iht. normale regler for præsentation
>> af datoer. Det er derfor muligt, at du vil se datoen præsenteret som
>> 24.12.2004 (alm. europæisk format). Men det er kun en præsentation. Den
>> interne datarepræsentation kan være en hel anden.
>>
>> Du skriver ikke noget om, hvad du skal bruge værdien til. Skal du have
>> den tilbage til det oprindelige format igen (YYMMDD)? For så forestår der
>> endnu en konvertering. Hvis du på nogen måde kan undgå det, så lad være.
>> Datoer bør gemmes i dato-felter!
>>
>> mvh.
>> Kaj
>
> Hej Kaj - har været væk lidt fra problemet - men har nu prøvet det - og
> voila det virker perfekt!!
>
> SELECT DISTINCT A.ITOISSC, D.ICSECNO, G.IIIION0,
> A.DTOESHP, A.IIIIBV0,
> CAST(CASE WHEN SUBSTR(DTOESHP, 1, 2) < '30' THEN '20' ELSE '19' END CONCAT
> SUBSTR(DTOESHP, 1, 2) CONCAT '-' CONCAT SUBSTR(DTOESHP, 3, 2) CONCAT '-'
> CONCAT SUBSTR(DTOESHP, 5, 2) AS DATE) + 2 DAYS AS SHIP_ETA_DATE
>
>
> FROM tabel A
> , tabel B
> , tabel C
> osv - og herunder rapporten- eller lidt af den:
>
>
> SHIP
> ETA
> ITOISSC ICSECNO IIIION0 DTOESHP IIIIBV0 DATE
> ------- ------------- ----------- ------- ------------ ----------
> 706 94KFRV1602401 AS9994 041227 EU14392 2004-12-29
> 706 94KFRV1602501 AS9998 041227 EU14392 2004-12-29
> 706 FQ4FRV1862401 KI773E 041229 EU14419 2004-12-31
>
> - jeg glemte at skrive omkring årstal - der kan kun forekomme 2004 eller
> 2005 data, men din løsning med case funktionen er smuk.
>
> Alt i alt har du hjulpet mig med en perfekt løsning på problemet - jeg
> arbejder professionelt med sql og logistik, opgaven er at forsendelsesdata
> inkl shipdate (dtoeshp) skal tillægges en transittid, på f.eks. 2 dage for
> at komme frem til en eta date - så din løsning ser jo rigtig fornuftig ud.
> Når jeg afleverer opgaven vil jeg især fremhæve den smukke og 'enkle'
> løsning på et reelt dato/sql problem.
>
> ***
> Præmis: rapporten gemmes i en tabel - kaldet test, og man programmerer en
> query ud fra en samkørsel med en kalendertabel for at finde ud af hvilken
> ugedag forsendelsen lander - kan man da bruge case funktionen til en logik
> hvor man siger at dagtype 6 = lørdag, dagtype 7=søndag og dagtype
> 8=hellidag, hvis dagtype er 1-5 skal feltet bare være blank - så brugerne
> kan tage højde for dette i deres videre planlægning - eks. sådan?:
> (nedenstående virker kke)
>
> SELECT A.*, B.DAYTYPE AS WEEKDAY
>
> FROM TEST A,CALENDER B
>
> CASE WHEN B.DAYTYPE = '6' THEN 'SATURDAY' ELSE ' ',
> CASE WHEN B.DAYTYPE = '7' THEN 'SUNDAY' ELSE ' ',
> CASE WHEN B.DAYTYPE = '8' THEN 'HOLIDAY' ELSE ' ',
>
> WHERE A.SHIP_ETA_DATE = b.caldate
>
> Håber du kan svare på det - eller en anden i gruppen - på forhånd tak
>
> Jens Gregersen - jensg@hej.oncable.dk (hej slettes fra mailadressen inden
> afsendelse)
)
>
Hej Jens
Nej, faktisk er det meget enklere:
SELECT A*, CASE B.DAYTYPE WHEN '6' THEN 'SATURDAY' WHEN ''7' THEN 'SUNDAY'
WHEN '8' THEN 'HOLIDAY' ELSE NULL END
FROM TEST A, CALENDER B
WHERE A.SHIP_ETA_DATE = b.caldate
Hvis du hellere vil have en blank en en null værdi, så erstat NULL med ' '
Som du kan se er CASE en rigtig god konstruktion, som kan lette ens arbejde
meget.
Btw.: CASE har faktisk to former. Jeg kunne også have valgt formen:
CASE WHEN B.DAYTYPE = '6' THEN 'SATURDAY' WHEN B.DAYTYPE = '7' THEN 'SUNDAY'
WHEN B.DAYTYPE = '8' THEN 'HOLIDAY' ELSE NULL END
Begge former er rigtigt gode, men da det er det samme felt man spørger til
hele tiden, foretrækker jeg den første form. I andre tilfælde, hvor det kan
være forskellige ting man eller felter man spørger til eller man ikke kan
nøjes med at spørge til en værdi, men skal bruge en formel, er den sidste
form bedre.
Derfor hedder den første form også "simple-when-clause", mens den mere
avancerede version hedder "searched-when-clause".
Håber du kan bruge det (og at jeg ikke lyder for nørdet og forelæsende)...
/ Kaj