Avatar billede ae03 Novice
19. februar 2010 - 13:44 Der er 10 kommentarer og
1 løsning

Beregninger med int og decimal i sql

Jeg har brug for i en MS SQL-database at konvertere fødselsdatoen i et cpr-nummer (char) til decimal(9,4) i form af fødselsåret (4 cifre) før kommaet og antal dage siden nytår div med 366 som decimal.
Det går fint med indtil jeg skal beregne decimaltallet ved brug af YEAR(), MONTH() og DAY(), jf. nedenstående kode. Så kommer det ud som yyyy,0000.

SET DATEFORMAT dmy;
GO
UPDATE lbnr.cpr_test
SET Foedsdag_char = LEFT(CPR, 2) + '.' + SUBSTRING(CPR,3,2) + '.' + SUBSTRING(CPR,5,2);
UPDATE lbnr.cpr_test
SET Foedsdag_date = CONVERT(smalldatetime, Foedsdag_char, 4);
UPDATE lbnr.cpr_test
SET Foedsdag = DAY(Foedsdag_date),
    Foedsmaaned = MONTH(Foedsdag_date),
    Foedsaar = YEAR(Foedsdag_date);
UPDATE lbnr.cpr_test
SET Foedsdag_decimal = Foedsaar + (30 * (Foedsmaaned - 1) + Foedsdag) / 366;

Så vidt jeg har kunnet finde ud af på diverse hjemmesider, online-hjælp m.m., skulle der ikke være problemer med at bruge tal i int-format til beregninger, der skal resultere i det decimal-resultat, så hvorfor kommer decimalerne ikke med?

Det lykkes for mig at beregne med decimaler ved brug af nogle længere beregninger med talrige forekomster af CONVERT() og SUBSTRING(), men det bliver noget uoverskueligt, når beregningerne ved hjælp af IF-sætninger skal tage højde for det forskellige antal dage i månederne, så derfor ville jeg gerne simplificere det på ovenstående måde.

Håber, at nogen kan hjlpe mig, eller at der måske ligefrem er nogen, der ligger inde med en endnu enklere måde at gøre det på.
Avatar billede arne_v Ekspert
19. februar 2010 - 16:52 #1
proev:

(30 * (Foedsmaaned - 1) + Foedsdag) / 366

->

(30.0 * (Foedsmaaned - 1) + Foedsdag) / 366
Avatar billede arne_v Ekspert
19. februar 2010 - 16:52 #2
Men faar du ikke store problemer p.g.a. 28/30/31 dags maaneder?
Avatar billede arne_v Ekspert
19. februar 2010 - 16:54 #3
Problemer som kunne undgaaes ved at bruge DATEPART DY.
Avatar billede janus_007 Nybegynder
19. februar 2010 - 21:38 #4
Det er langt mere kompliceret end man lige tror, se her: http://da.wikipedia.org/wiki/CPR-nummer

Og vend tilbage med noget konkret :)
Avatar billede ae03 Novice
22. februar 2010 - 12:02 #5
Tak for rådet om at bruge 30.0. Det virkede og er klart de 30.0 point værd.
Nu jeg ser forklaringen, kan jeg godt huske, at jeg er stødt på det problem (og den løsning) for en del år siden i en eller anden sammenhæng (GIS, programmering el. lign.), der med sikkerhed ikke har noget med sql at gøre, men jeg er alligevel overrasket over, at det er det, der var problemet. Jeg opfatter det nærmest som en fejl, at systemet ved beregning af decimaltal skelner mellem, om der anvendes 30 eller 30.0 i en multiplikation. Bare for at tilfredstille min nysgerrighed: Er der en logisk grund til denne skelnen?
Problemerne med at der er forskellige antal dage i månederne har jeg egentlig løst med 12 separate UPDATE...WHERE, men jeg vil fluks ændre det til brug af DATEPART DY, for det er da en lettere og "smukkere" løsning.
Jeg er ny bruger på eksperten.dk, så hvis der af en eller anden grund går noget galt med overførsel af point, må du lige sige til.

Tak for hjælpen!
Lars
Avatar billede arne_v Ekspert
23. februar 2010 - 03:53 #6
Det er ikke multiplkationen men division som giver et problem.

(int*(int-int)+int)/int -> (int*int+int)/int -> (int+int)/int -> int/int -> int

(double*(int-int)+int)/int -> (double*int+int)/int -> (double+int)/int -> double/int -> double
Avatar billede arne_v Ekspert
23. februar 2010 - 03:53 #7
og et svar
Avatar billede arne_v Ekspert
23. februar 2010 - 03:56 #8
Janu har iøvrigt en god pointe i at der er forskel på CPR nummer logikken og SQLServer logikken med hensyn til betydningen af de to cifre.

Wikipedia linket forklarer CPR nummer logikken.

SQLServer logikken er:

50 -> 1959
...
99 -> 1999
00 -> 2000
...
49 -> 2049
Avatar billede arne_v Ekspert
23. februar 2010 - 03:59 #9
Overvej også hvorvidt du virkeligt behøver CPR numre.

Hvis du behøver dem så bør du:
- opbevare dem krypteret
- have streng bruger kontrol i applikationen
- have data politik for hvem der må bruge hvilke data til til hvilket formål
- bruge krypteret net-trafik
o.s.v.
Avatar billede ae03 Novice
23. februar 2010 - 08:11 #10
Forskellen i datoformater er heldigvis ikke noget problem, da jeg kun beskæftiger mig med unge under 18 år. Ellers kunne det jo klares med kontrol med det 7. ciffer.
Datasikkerheden er på plads. Jeg sidder i en offentlig forvaltning og har data sikkert opbevaret på en sikkerhedsgodkendt server med alt hvad det indebærer af adgangskontrol, logning m.m.m.
Avatar billede ae03 Novice
23. februar 2010 - 08:12 #11
Tak for hjælpen
Avatar billede Ny bruger Nybegynder

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.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester