Avatar billede skindbeni Nybegynder
24. december 2009 - 01:07 Der er 9 kommentarer og
2 løsninger

Opbygning af databasestruktur

Jeg har sat mig for at bygge et økonomiprogram til bogføring.

Om det er en dum ide er ikke til diskussion. Grunden til, at det er et bogføringsprogram jeg vil programmere, er at det er det emne, der interesserer mig gennem min baggrund som revisor :o)

Det drejer sig derfor om, at jeg dels gerne vil prøve at gennemføre at bygge sådan et program og dels at jeg hygger mig med det som min hobby.

Jeg bygger det i Delphi og med Firebird som underliggende database.

Der hvor jeg gerne vil have lidt hjælp til er opbygningen af en solid databasestruktur, der kan håndtere det på en fornuftig måde nu og i fremtiden med mulighed for at bygge videre. Selvom det er hobby og for sjov, kan man aldrig vide, om jeg kan bruge det til noget fornuftigt senere hen. Men grundet det første er det ikke noget, jeg har mulighed eller lyst til at ofre penge på.

Selve oprettelsen af databasen kan jeg sagtens håndtere, men selve strukturen halter.

Derfor kunne jeg bruge et venligt menneske med interesse i databasestruktur til at hjælpe mig enten med et oplæg eller kommentere på mit eget oplæg her eller pr. mail.

Jeg har fx pt. en tabel til kontoplan. Jeg har en tabel til at definere forskellige kassekladder. Jeg har selve kassekladdetabellen. Jeg har en momskodetabel. Jeg har yderligere en periodetabel. Og jeg har en posteringstabel, hvor jeg havde forestillet mig, at alle posteringerne skulle overføres til fra kassekladden, når den blev bogført og samtidig slettes fra kassekladdetabellen.

jeg har dog overvejet en alternativ løsning. I stedet for ovenstående posteirngstabel har jeg overvejet at gemme samtlige kassekladder i kassekladdetabellen efter bogføring i stedet for at overføre til en posteirngstabel. Dette er for at man kan hente gamle kassekladder ind igen.

For at starte så simpelt som det nu kan lade sig gøre med sådan et stort projekt, så vælger jeg kun at fokusere på selve bogføringsdelen og kan det lade sig gøre og jeg ikke er skræmt væk, kan jeg gå videre med debitor/kreditor.
24. december 2009 - 06:36 #1
Det er bestemt en god ide at bruge tid til at skaffe sig en solid database struktur til at begynde med.  Saa bliver det ogsaa nemmere at udbygge og maaske konvertere strukturen efter behov efterhaanden som du udvikler projektet.

Din sidste ide er, har jeg forstaaet, at bruge databasen til at bevare de raa data, saasom kassekladderne, og saa behandle bogfoeringen andetsteds ved at query de oprindelige data.  Den har jeg umiddelbart mest fidus til hvis jeg har fattet dine endnu sparsomme oplysninger.  Den ligger taettest paa principperne i relationelle databaser, og yderligere svarer den til de traditionelle papir og blaek systemer hvor du ikke smider kassekladderne vaek.

Med mindre du opretter spoergsmaalet under jobs/opgaver og saa hyrer hjaelp, hvilket jeg har forstaaet ikke er aktuelt paa nuvaerende tidspunkt, saa vil mene at du skal koere det ved hjaelp af spoergsmaal her paa eksperten.  Lav et indlaeg hvor du, for eksempel, giver et par eksempler paa typiske kassekladder og skitserer de database tabeller du har "leget med" indtil nu, saa kan jeg (og andre ekspert medlemmer) kommentere.
Avatar billede Slettet bruger
24. december 2009 - 11:44 #2
Det er dog et interessant projekt du giver dig i kast med og jeg vil gerne løbende kommentere.

Database strukturen dokumenteres vha. ER- diagrammering - http://en.wikipedia.org/wiki/Relational_model. Enkelt forklaret, går det ud på at relatere tabelerne så det afspejler den virkelighed der administreres. Det er vigtigt at have det på skrift/elektronisk - det er hovedhjørnestene i systemmet - måske har Delphi/firebird det allerede?

skindbeni:'Jeg har fx pt. en tabel til kontoplan'

Er det Konti(PK id,navn,beskrivelse,erDebet,erBalance) - PK betyder primary key.
En sådan kontoplan har stuktur nok, til dannelse af resultat og balance - men ingen underopdelinger i resultatopgørelsen.


skindbeni:'..Og jeg har en posteringstabel, hvor jeg havde forestillet mig, at alle posteringerne skulle overføres til fra kassekladden, når den blev bogført og samtidig slettes fra kassekladdetabellen.'

Ja, det synes jeg er en god ide - og det er også sådan c5, navision (og sikkert andre) gør. Det opfylder, i mine øjne, også kravet til bogføring på den måde at en periodes indskrivning bekræftes og gøres 'ikke redigerbart'.


Held og lykke med det.

Mvh
Benny Andersen
Avatar billede skindbeni Nybegynder
24. december 2009 - 12:04 #3
Hej Christian.

Tak for dit svar.

Jeg er også mest tilhænger af selv at rode med det med hjælp fra andre end at få det serveret. Det første lærer jeg mest af :o)

I de større bogføringsprogrammer eksempelvis C5 gemmes kassekladderne så vidt jeg ved ikke. Har man lemt at udskrive en kassekladde inden bogføring, så er det for sent at gøre bagefter. Det kan man godt undre sig over. Derfor var min første tanke, at der var en kassekladde (tabel) til posteringerne, når de lå i kladdenog ikke var bogført og endnu en tabel til de bogførte posteringer, som kassekladden overføres til ved bogføring.

Min tanke i mit 2. forslag var så at "spare" den ene tabel og lave et felt, der indikerer, om posteirngen / kassekladden er bogført eller i kladde samt et felt til kladdenummer, således at man altid kan trække disse data ud i en forespørgsel.

Og her må jeg krybe til korset. Jeg aner intet om, hvad der er bedst af de to løsninger af hensyn til hastighed, ydeevne, sikkerhed, opbygning osv. indenfor databaser. Det er jeg desværre ikke skolet i. Potentielt kan det jo blive til mange poster i en bogføring gennem nogle år.

Jeg har prøvet at skrive lidt op i et dokument for at få et overblik over tabellerne. Dem vil jeg da gerne vise her (Det fylder en del, da jeg har medtaget alle de tanker jeg har pt.) og høre kommentarer til:

TEKSTTYPER: (til at gemme tekstforslag. Teksttyper kan være posteringstekst, faste tekster i programmet samt andre brugerdefinerede teksttyper)
ID, pk, integer
Tekst, varchar(50)

TEKSTER: (Selve teksterne, der kan bruges som forslag. Fx "salg" eller lign.)
ID, pk, integer
Teksttype, fk, integer
Tekst, varchar(256)
Genvej, integer

REGNSKABSAAR:
Aar_ID, pk, integer
Regnskabsaar, varchar(50)  (fx "2009" eller "2009/10" osv.)
Primo, date
Ultimo, date
Status, varchar(10)  (fx "åben", "lukket")

PERIODER:  (Jeg har god erfaring med at man kan oprette perioder, således man kan indskrænke bogføringsperioden og minimere fejl mht. indtastningsfejl af datoer)
Periodenavn, varchar(50)
Aar, pk1, fk, integer
Primo, pk2, date
Ultimo, date
Status, varchar(10)

KONTOPLAN:
Konto, pk, integer
Kontonavn, Varchar(50)
Kontotype, varchar(10) (Der er nogle foruddefinerede værdier i min applikation)
Moms, integer  (henviser til en værdi i tabellen MOMS)
Sumfra, integer  (henviser til en værdi i feltet KONTO)
DK, varchar(1)  (kan være "D" eller "K". Angiver om kontoen skal foreslå debet eller kreditpostering

MOMS:
Moms, pk, integer
Tekst, varchar(50)
Sats, Decimal(15,2)
Konto, integer
Fri, Decimal(15,2)

KASSEKLADDER: (Jeg har valgt at man kan oprette flere forskellige kassekladder. Lidt ala C5. Begrundelse: Flere brugere kan bruge programmet. Har man bogføringer i en kassekladde, som dog ikke er bogført, kan en anden bruger altid benytte en anden kassekladde. Derudover kan man lave skabeloner, hvis man har ens bogføringer hver måned)
KladdeID, pk, integer
Navn, varchar(50)
Beskrivelse, varchar(256)
Adgang, varchar(7)
Bruger, varchar(50)
Minimum, integer
Maximum, integer
Bilag, integer
BeloebIModpost, integer
OverspringModkonto, integer
OverspringMoms, integer
m.fl.
...
De sidste er kladdeindstillinger

KASSEKLADDE: (Selve kladderne)
ID, pk, integer
KladdeID, fk, integer
Dato, date
Bilag, integer
Kontotype, varchar(1)  (til hvis jeg engang får debitor/kreditor bygget på)
Konto, integer  (henter værdi fra KONTOPLAN, konto)
Posteringstekst, varchar(50)
DebetKredit, Decimal(15,2)  (jeg tænker det er bedre at have een kolonne og evt. i applikationn splitte debet og kredit op i hver sin kolonne end have 2 kolonner i tabellen.
Moms, integer    (værdi fra tabellen MOMS)
Modkonto, integer    (værdi fra kontoplan, konto)

POSTERINGER  (Den alternative tabel til at overføre bogførte posteringer til)
ID, pk, integer
Dato, date
Bilag, integer
Posteringstekst, varchar(50)
DebetKredit, decimal(15,2)
Konto, integer
Transaktionsnr, integer
Momskode, integer

Endnu engang er alt om databaser og programmering selvlært med de begrænsninger det har, så ret endelig på mig, jeg bliver ikke fornærmet :o)

Endnu engang tak og GOD JUL
/Michael.
Avatar billede skindbeni Nybegynder
24. december 2009 - 12:19 #4
Hej Benny.

Tak for dit bidrag også.

Jeg kigger på det mellem jul og nytår, da jeg er nødt til at tage afsted og er væk frem til 2. juledag.

God jul.
25. december 2009 - 09:13 #5
Jamen du synes da at have temmelig godt styr paa principper omkring database strukturer og lignende.

Det kan da godt vaere at jeg har vaeret for laenge vaek fra dansk bogfoering (jeg har vaeret udenlandsdansker siden 1976 og der arbejdet, blandt andet, med Oracle Financials, har nu vaeret pensioneret i nogle aar men jeg naaede at skaffe mig en HD i regnskabsvaesen inden jeg tog fra Danmark) saa jeg er spaendt paa kommentarer fra andre paa eksperten.  Lad mig kommentere om databasestruktur (som det oprindelige spoergsmaal drejede sig om) snarere end om bogfoering.

Den centrale tabel i datastrukturen, der hvor data foedes, maa vaere kassekladden. Saa jeg begynder der.

Saa vidt jeg husker fra Oracle Financials, naar vi havde indfoert en transaktion og saa trykkede paa "post" saa forsvandt den oprindelige transaktion (smide kassekladden vaek som du siger ogsaa sker i C5).  Jeg gaar ud fra at det er af hensyn til hastighed og ydeevne.  Men maaske begynder det, med de teknologiske fremskridt der er gjort, at blive mindre relevant.  Saa jeg skal kommentere ud fra den ide at data indfoeres, i princippet, en gang og forbliver hvor de er og traekkes saa ud i rapporter ved hjaelp af queries naar der skal produceres regnskaber og lignende.

Undtagelsen maa saa nok vaere, af praktiske grunde, at de indfoerte data i en kort periode kan rettes ved simpel overskrivning.  I den periode har de status som kassekladde.  Naar der saa "trykkes paa knappen" skifter de status og kan ikke laengere aendres saaledes at rettelser sker ved modposteringer.

I saa fald skal du nok have, som du selv er inde paa, et ekstra felt i kassekladden som "krydses af" og blokkerer for aendringer.  Tabellen skal nok skifte navn til KASSEINPUT (eller et godt dansk navn).  Kladde er saa en status.  Tabellen POSTERINGER falder saa vaek.

Saa kommentarer til de enkelte felter i KASSEKLADDE/KASSEINPUT:
(a) ID, KladdeId, Dato - ingen kommentarer.
(b) Men skal der vaere en fk til PERIODER/REGNSKABSAAR?  Det ville maaske goere rapporteringen nemmere.
(c) Bilag.  Vil der altid kun vaere et bilag?  Eller kan der til en kassekladde hoere en bilags-mappe der indeholder adskillige elektroniske bilag eller henvisninger til papir fakturaer?  En en-til-mange relation.  Eller kan et bilag vaere relevant for flere kassekladder, for eksempel en beskrivelse af et formaal/projekt?  Saa er vi inde paa en mange-til-mange relation.  I saa fald boer du oprette en tabel BILAG der indeholder alle bilag uanset kassekladde og saa en tabel KASSEKLADDE_BILAG med ID pk, Kassekladde_ID fk, Bilag_id fk.  (BILAG vil naturligvis henvise til snarere end indeholde bilagene, ref til filer for elektroniske bilag eller numre til ringbind og blad for papir fakturaer og lignende.)
(d) Kontotype, konto, moms, modkonto.  De skal vel alle vaere fk for at sikre den relationelle integritet.  Det er vel det du mener med "Konto, henter vaerdi fra KONTOPLAN...").
(e) Posteringstekst, varchar(50).  Er 50 bogstaver altid nok?  Ja, hvis du laver mulighed for adskillige bilag og et af bilagene kunne vaere en laengere beskrivelse.  Er der en relation mellem Posteringstekst og TEKSTTYPER/TEKSTER?  Det har jeg ikke helt forstaaet.
(e) DebitKredit.  Ja, eller simpelt hen kald det "Beloeb." Er det et tal der kan vaere positivt eller negativt?  og naar der traekkes rapporter ud saa gengives tallet i Konto og gengives med omvendt fortegn i Modkonto?
(f) Og saa som sagt et felt for status, kladde eller ej.

Saa kan jeg vist ikke koge mere suppe paa KASSEKLADDE.

KASSEKLADDER.  Ingen kommentarer (jeg forstaar ikke alle felterne men det er ikke vaesenligt i denne sammehang.)

MOMS.  Igen, Konto skal vel vaere fk til KONTOPLAN

KONTOPLAN.  Igen jaevnfoer min manglende erfaring med bogfoering i Danmark, men hvis du ikke "posterer" i databasen, ikke bruger tabellen POSTERINGER saa er nogle af felterne vel overfloedige? Med mindre det foelgende goer sig gaeldende:  I felterne DK, Moms, og Sumfra har du vaerdier saaledes at hvis der i MOMS eller KASSEKLADDE indfoeres kontoer der ikke synes egnede til formaalet saa kommer der en advarsel (eller afvisning.)

PERIODER.  En petittesse: Navnet boer vaere PERIODE fordi hver raekke i tabellen kun indeholder en enkel periode.  Aar fk henviser til REGNSKABSAAR ikke sandt?  Hvis et regnskabsaar altid indeholder en eller flere perioder saa kunne REGNSKABSAAR vel noejes med et eller to felter, en pk og maaske en beskrivelse.  At lade REGNSKABSAAR indeholde primo og ultimo er vel til "mere skade end fortraed" fordi de kan konflikte med primoer og ultimoer i REGNSKABSPERIODE.

Det var saa min jule morgen post mens konen sover laenge.  Jeg kan hoere at hun begynder at roere paa sig nu, men jeg er ogsaa faerdig.  Jeg haaber at dette er nyttigt, enten ved at du kan bruge nogle af mine ideer eller ved at du indser at saadan skal det i hvert fald ikke vaere og saaledes indsnaevrer soegefeltet.  Held og lykke med projektet, og jeg er som sagt spaendt paa at foelge med i hvilke andre kommentarer/reaktioner der kommer.
Avatar billede Slettet bruger
25. december 2009 - 21:11 #6
Lige en kommentar omkring sletning af kasseklade ved postering.

Jeg kan forstå at du synes at miste noget når - det er rigtigt: hvilken posteringer der stammer fra hvilken kassekladde forsvinder!

Jeg har endnu ikke røbet, at jeg har udviklet det regnskabssystem (eller hvad man skal kalde det) som jeg anvender - det er lavet i ms-access.
Ved bogføring af en kladde sker der samtidig backup af netop de tilførte posteringer (eksporteret tekstfil bliver tilføjet zip arkiv) - så hvis jeg ville, kunne jeg implementere en roolback funktion. Desuden sker der check af en række ting (antal poster, summer i kasseklade kontra posteringer), som, hvis ikke alle betingelser er opfyldt, så udføres roolback på posteringer og kassekladde slettes ikke.
Avatar billede skindbeni Nybegynder
27. december 2009 - 15:55 #7
Hej begge to.

Så er jeg hjemme igen og vil kigge og opdatere mine databaser lidt ud fra jeres hjælp.

Jeg skylder nogle points. Vil i begge lægge et svar.

P.S. JEg er i øvrigt også i gang med HD-R studie. Dog kun på 1. år indtil videre :o)
27. december 2009 - 17:34 #8
Svar fra mig.
Avatar billede skindbeni Nybegynder
27. december 2009 - 19:40 #9
Lige for at "svare" på nogle løse ender.

Jeg tror jeg rbejder videre med ideen om at kalde den centrale tabel for POSTERINGER og så oprette et statusfelt, der indkerer, om er er sket bogføring. I modsat fald er der stadig tale om en kladde.

Desuden er der oprettet et felt, der hedder Kladdenr som angiver hvilken kassekladde, der har bogført posten, så det altid kan hentes og udskrives en kassekladde.

---

Mine bevæggrunde for at have et primo- og ultimofelt i tabellen REGNSKABSÅR er for at validere, at en periode nu rent faktisk ligger indenfor et givent regnskabsår.

Eksempelvis regnskabsåret 01.01.2009 - 31.12.2009
Perioder: 01.01.2009 - 31.03.2009 den ligger i regnskabsåret ovenfor, mens 01.10.2008 - 31.12.2008 ikke ligger i ovenstående regnskabsår.

Er det en dum ide (at gøre det sålda)?

---

Er det egentlig overhovedet muligt at have et felt, der er FK og refererer til et felt i samme tabel.

På dansk: i tabellen KONTOPLAN er der bl.a. felterne konto, kontonavn, sumfra osv.

Feltet SumFra skal på en sumkonto angive, fra hvilken konto i kontoplanen, den skal sammentælle, når der udskrives balancer.

Derfor har jeg sat dette felt til at være FK i tabellen KONTOPLAN og referere til samme tabel (KONTOPLAN) og feltet KONTO.

Det giver vel ingen problemer?

---

Hor vigtigt / fornuftigt er det at anvende "Checks" eller hvad det hedder.

Eksempelvis har jeg forsøgt mig med at lave et felt der hedder STATUS i kassekladden/posteringstabellen, der angive,r om den er bogført eller om det stadig er kladdestatus. Firebird har ingen true/false felttype, så jeg anvender integer og bruger i min applikation 0 for false og 1 for true (principielt).

I feltet STATUS har jeg så lavet følgende "check": "STATUS >= 0 AND STAUS <= 1".

Jeg har ALDRIG arbejdet med checks før, men snuste rundt i mit program til databaser og fandt muligheden. Er det ikke korrekt anvendelse af "Checks"?

---

I forbindelse med jeg har snust rundt i mit databaseprogram har eg fundet følgende

"Uniques"
"Indices"
"Dependencies"

Er det noget, som jeg bør snuse mere i eller er det overflødig og til forvirring for mig mon?
27. december 2009 - 23:04 #10
Et par loese svar til de loese ender:

Ultimo og primo i regnskabsaar:  Det kan da godt vaere at det er meget fornuftigt hvad du siger.  Hvis du havde en engelsk kunde med regnskabsaar der vist nok gaar til 27 April saa ville du have et regnskabsaar fra 28/4 til 27/4 som saa kan vaere delt op i en eller flere regnskabsperioder.

Det skulle ikke vaere noget problem at have et felt der refererer til et felt i samme tabel saa som at du i tabellen med konti hvor du for eksempel har et felt Konto og et felt Sumkonto og saa har, for eksempel (jeg ved ikke hvordan du summer op) en konto nr 5000 uden sumkonto, en konto 5100 med 5000 som sumkonto, en konto 5110 med 5100 som sumkonto o.s.v.  Saa taler man ikke om FOREIGN key. 

FK er en af mange eksisterende "constraints" der sikrer "referentiel integritet."  For eksempel hvis en tabel med indkoebsordrer har et felt med kunde_id saa laver man en FK til kunde_id i kundetabellen og sikrer sig derved at man ikke i indkoebsordretabellen kan indfoere kunder der ikke eksisterer. 

Et index paa et felt har to formaal (her er jeg lidt usikker, det kommer jeg tilbage til.) Det foerste formaal er at tabellerne internt i databasen bevares saa den er nem at soege i.  Hvis for for eksempel i en person tabel CPR nummeret er indixed og man saa laver en query der bruger CRP nummeret saa behoever maskinen ikke at soege hele tabellen igennem men kan beregne hvor den skal starte med at soege.  I teorien om relationelle databaser kraeves det at index-vaerdierne er unikke, for eksempel at der ikke kan vaere to forskellige personer med det samme CPR nummer, og tit er det netop denne kontrol man vil have, saa som at fange dobbel CPR numre.  Her synes det at nogle database systemer tillader indices der har duplikater med mindre man laver et unik index.  For en sikkerheds skyld laver jeg normalt CREATE UNIQUE INDEX indexA ON persontabel(CPRnummer).

Unikke indices kan daekke mere end et felt.  Hvis for eksempel man har en tabel over mennesker og en tabel over klubber og mennesker kan vaere medlem af adskillige (eller slet ingen) klubber, en saakaldt mange-til-mange relation, saa kan man lave en klub-medlem tabel med et felt for en person, et felt for en klub, og saa maaske felter der handler om dette medlemskab saa som medlemskabsnummer.  Hvis et menneske er medlem af tre klubber saa staar han paa tre raekker i denne tabel, hver gang med en anden klub reference, og hvis en klub har 50 medlemmer staar den i 50 raekker, men en kombination af menneske og klub maa kun forekomme i en raekke i tabellen.  saa laver man en unik index over de to felter, CREATE UNIQUE INDEX medlem_index ON klub_medlem(personId, klubId).

Dependencies maa saa vaere andre konstraints, for eksempel der soerger for at en vaerdi i feltet sumkonto eksisterer i feltet konto.  Og hvis du i en tabel laver et felt der angiver om en vaerdi er postet eller stadigvaek kladde saa har du et check.

Saa checks, uniques, o.s.v. er bestemt noget du "boer snuse mere i" hen ad vejen.
Avatar billede Slettet bruger
28. december 2009 - 02:14 #11
Svar og kommentar til sumfra i kontoplan.

Det kan man godt, hvis det laves på den rigtige måde. Der er tale om links der gør kontoplanen, som et hele, til en hierakisk struktur. (eller directory som vi kender fra filsystemmets mapper)
Jeg bliver lidt forvirret ved tanken om hvordan det skal gennemløbes, for undersummer skal vel laves før mere overordnede.

Et mere almindeligt links type er 'parent' - altså et træ hvor referencerne går den anden vej - i praksis ville så alle top level konti have parent=null og unhver samlekonto parent=id af 'parent konto'
Et sådan træ traverseres vha et princip der hedder rekursiv nedstigning, noget der i øvrigt tilhører et lidt andet paradigme en relationsdatabasens mængdedeklarations logik - men det er ikke noget problem når man programmerer.

konti med samme 'parent', er ja - siblings! - hvilket leder tanken hen på at resultatopgørelse og balance også er noget med en bestemt rækkefølge (sibling order) - (men det kan måske implementers senere)
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

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