Manglende konsistens i datamodellen og upræcise SQLsætninger er årsagen til, at mange IT-systemer fejler.



Relaterede dokumenter
De vigtigste SQL-sætninger. SQL kap Oprette database. DDL og DML

Begrænsninger i SQL. Databaser, efterår Troels Andreasen

Views etc. Databaser

DB undervisning 01-01

Data lagring. 2. iteration (implement backend)

Introduktion til SQL queries

Modul 2 Database projekt Multimediedesign 3. semester Gruppe 3 IRF/TUJE

Skriftlig eksamen i kurset. Informationssystemer

Introduktion til Oracle, Datalogi, RUC Af: Jens Lauterbach 2002

Databasesystemer. IT Universitetet i København 7. juni 2005

Import af rekursivt (parent-child) hierarki i Palo

Sidste forelæsning. Jacob Aae Mikkelsen. 28. april 2013 IMADA. Jacob Aae Mikkelsen (IMADA) Sidste forelæsning 28.

Tietgenskolen - Nørrehus. Data warehouse. Database for udviklere. Thor Harloff Lynggaard DM08125

Database optimering - Indeks

Database design for begyndere

Side 1. Databaser og SQL. Dagens gang. Databasebegreber. Introduktion til SQL Kap 1-5

Efterår 2002 Note 10. Temaopgave

Database "opbygning"

Hvad er en relationsdatabase? Odense, den 19. januar Version 1.0

Opgave 1. Opret de 4 tabeller i FTSFrontend programmet. Indsæt mindst 3 forskellige tabelværdier i kunder, målerstatus, byer og regning..

Introduktion til SQL

Skriftlig opgave. Designtanker i database-nære systemer

1. Basal select med (stjerne)

Skriftlig eksamen i Databaser, Vinter 2001/2002. Pa opfordring har jeg udarbejdet mulige lsninger pa eksamensopgaverne, men

Opgave 1 Basal select med (stjerne)

En Kort Introduktion til Oracle

Skriftlig eksamen i. Databaser. Vinter 2002/2003. Vejledende løsninger

En opsamling af artefakter for Hotel Databasen som REST-service Bygger på Hotel opgaven i 8 trin

Dataanalyse og databaser

Jørgen Koch. och. Access. Normalisering m.v.

Database tips. Den forudsætter lidt kendskab til SQL men er for mindre erfarne. Denne guide er oprindeligt udgivet på Eksperten.dk

Kursus/workshop: SQL

Eksamen, DSDS, forår 2009

SQL-opgaver 5 løsning

Eksamen, DSDS, efterår 2007

Introduktion til programmering

Jayne Alice Jensen [Link til portfolio]

Septimas høringssvar vedrørende dokumenteterne FKG datamodellen - Version Fysisk implementering.pdf og FKG_2_3_1_mssql.sql

Tilretning af importdatafiler

Logning. V/ Hans Kennet Larsen

Projekt database. 3 Semester - Mul a Projekt 1. Yaser Osman cph-mo102@cphbusiness.dk. Dan Eskildsen cph-de32@cphbusiness.dk

Afleveringsopgave. Efterår 2001

3. semester, 2. projekt: Database

DATABASE - MIN MUSIKSAMLING

Databaseteori. 19. Databaser. 20. Kartotek eller database. 21. Database

Hvorfor skal vi bruge objekt orienteret databaser?

I mit script tager jeg højde for det problem ved, at gemme et unikt tal mellem 0-9 på 6 cifre og derved vil de så blive vist som 2 online.

MsSQL: Basal performance tuning, part 1

Begrynder til at lave log ind system

XML Difftool brugervejledning

OPC Access 3.0 opdatering via Stored Procedure

Parameters. Denne artikel beskriver hvorfor parameters er gode. Den forudsætter lidt kendskab til C# og ADO.NET.

Eksamen, DSDS, efterår 2008

Projekt Database, Gruppe 4A. Projekt 1, 3. Semester D A T A B A S E. Klasse MulA13 Gruppenummer: A4

SQL Server 2016 Data Adgang

Projekt titel. Projekt navn. Gruppe medlemmer. Klasse/Gruppenummer. Databaseprojekt 1. Ferrari

Data Warehouse Knowledge is Power - Sir Francis Bacon -

Problemstilling ved DBK integration i BIM Software Hvad skal der til. Nicolai Karved, Betech Data A/S

Datamodeller. 1. Elementerne. Vi betragter E/R-diagrammet, som et diagram over entiteter og relationer Tegneregler: Entitet

Database programmerings tips

Dokumentering af umbraco artikeleksport:

Databasesystemer. Databaser, efterår Troels Andreasen. Efterår 2002

Indholdsfortegnelse Databaser og PHP... 3 Opgave... 4 Opgave... 5 Opgave... 6 Sidste opgave er en lille gæstebog... 7 Kilder og nyttige links:...

! Kia Dahlen. Kamilla Klein, Pia Jensen og Maria Korshøj Andersen.

Anne Randorff Højen

Skrevet den 18. Feb 2010 af arne_v I kategorien Programmering / Visual Basic.NET

Brugermanual til Assignment hand in

Databaser Obligatorisk opgave 1

HOFTEALLOPLASTIK - DATAUDTRÆK OG IMPORT TIL EXCEL

Ratingsystem i PHP og MySQL

Indholdsfortegnelse for kapitel 3

Tagwall med Php & MySQL

Skriftlig eksamen i. Datalogi. Databaser. Sommer 2001

Databaseadgang fra Java

Listen over reserverede ord er meget lang, men de væsentligste vil jeg beskrive her i denne artikel:

Trin 1 INSERT INTO Debitor (DebitorNr, KundeKategori, KreditMax, SidstRykket, Sælger ) VALUES (20121, 10, 40000, NULL, "Bjarne Larsen");

Relationel Algebra og SQL

Daglig brug af JitBesked 2.0

Foto-Applikation Dokumentation. Et Kod-i-Ferien projekt

(fig.1. Eksempel på en almindelig entity)

Skriftlig eksamen i. Databaser. Vinter 2002/2003

Procesbeskrivelse - Webprogrammering

Reeksamen, DSDS, forår 2008

Obligatorisk opgave 2. SQL, relationel algebra og relationel kalkyle

Målet for disse slides er at diskutere nogle metoder til at gemme og hente data effektivt.

Afsnittet er temmelig teoretisk. Er du mere til det praktiske, går du blot til det næste afsnit.

Adgang til eksterne referencedata, integration til egne systemer og søgning i egne kundedata som en samlet Master Data Management (MDM) løsning.

Introduktion til programmering

Prepared Statements. Denne artikel beskriver hvorfor prepared statements er gode. Den forudsætter lidt kendskab til Java og JDBC.

Karens lille vejledning til Access

ALMINDELIGT ANVENDTE FUNKTIONER

Projekt database. (vores htmlside)

Databasesystemer. IT Universitetet i København 8. juni 2006

Værktøjer fra værktøjskassen. Søren Breddam, Stevns Kommune

Unge - køb og salg af sex på nettet

Øvelse 9. Klasser, objekter og sql-tabeller insert code here

Indberetningssystemet - vejledning for energikonsulenter

EA3 eller EA Cube rammeværktøjet fremstilles visuelt som en 3-dimensionel terning:

CLmul-b14e Gruppe 2 2. Database projekt

Transkript:

Manglende konsistens i datamodellen og upræcise SQLsætninger er årsagen til, at mange IT-systemer fejler. Af Seniorkonsulent Carsten Saastamoinen-Jakobsen Skal datamodellen blot være på 3NF (normalform)? Er det at finde foreningsmængden mellem 2 tabeller blot at anvende UNION-operatoren? Nej og Nej! Hvis et system skal være stabilt og konsistent hen over tid er 3NF ikke nok. Hvis kravet til datamodellen er 3NF er UNION-operatoren ikke anvendelig i alle situationer. Hvorfor oplever mange udviklere, at deres fejlfrie program efter at have kørt problemfrit i uger, måneder eller måske endda år pludselig fejler. Grunden vil i mange tilfælde være et for dårligt forarbejde. Min kære dansklærer fra gymnasiet, havde den holdning, at mindst den første time af en fire timers eksamen i dansk stil skulle bruges til at foreberede, hvad der skulle blive til en velstruktureret stil i de sidste knap tre timer. Hvis forholdet ikke var 1 til 3 mellem planlægning og udførelse, ville den danske stil selv for den dygtigste skribent blive dårlig. Hvor skulle en detalje med, i hvilken rækkefælge skulle tingene skrives, var alt med eller skulle der under indskrivningen det var før PCtidsalderen pludselig tilføjes noget, som medførte et rodet indhold og forskellige abstraktionsniveauer, hvor det burde være samme abstraktionsniveau, osv. Til orientering medførte det ikke automatisk høje karakterer, men hvordan ville det ikke være blevet uden denne planlægning. Men det medførte, at det var muligt med ro i sindet at forlade eksamenslokalet før de sidste hektiske minutter i forvisning om, at det var så det bedste, der kunne produceres på de 4 timer. Mange systemer udvikles uden en tilsvarende grundig bearbejdelse af datamodellen og uden overvejelser om, hvad en dårlig datamodel får af konsekvenser for skrivning af SQL-sætninger og for de applikationer, der skal udarbejdes. Det er vigtigt, at ALLE SQL-sætninger skrives ud fra, hvordan datamodellen er implementeret i databasesystemet og ikke ud fra de regler, udvikleren mener er gældende, eller som udvikleren tester for i sine applikationer. Skal alle tabeller have en surrogatnøgle som primærnøgle en surrogatnøgle er konstant hen over tid, da der ikke er indholdsbetydning i værdien? JA, absolut!! Men kan man da ikke bruge et Cprnummer som primærnøgle? Nej, omkring 50 personer får ændret deres Cprnummer hvert år. Et Cprnummer indeholde både oplysninger om fødselsdato og køn begge informationer kan ændres. Er et gadenavn ikke entydigt inden for en kommune? Jo, indtil sidste kommunesammenlægning. Ved den forrige kommunesammelægning var det et krav, at gadenavnene var entydige men en regel holder kun indtil nogen finder på at ændre den. Og på den måde kan jeg blive ved. Hvis denne simple regel om altid at bruge surrogatnøgler ikke overholdes, opstår der med garanti problemer på et tidspunkt. Er det ikke godt nok hvad det så end er at alle datavalideringer foretages af applikationen. Nej, der er set i hundredevis af eksempler på, at data er blevet indsat i databasen uden om ap- Copyright 2008 Teknologisk Institut side 1 of 10

plikationerne og med fejl til følge. F.eks. loades data fra en komma-separeret fil, så i nogle forekomster er en kolonne NULL, i andre forekomster er værdien den tomme streng og i andre er det en enkelt blank. Gør det søgningerne på en kolonne simplere? Problemet kan være, at det ikke er planlagt fra starten, at data skal indsættes uden om applikationerne, men ved opkøb, sammenlægning ol. skal et andet firmas data medtages i databasen. Jeg hører ofte, at mange har den holdning, at kravet til deres datamodel skal være, at den er på 3NF (3. normalform). Det er også meget bekvemt, da en erfaren modellør ofte laver datamodellen på denne normalform. Derfor er det jo ikke nødvendigt at undersøge om kvaliteten 3. normalform er overholdt. Ved en struktureret gennemgang af datamodellen inden udarbejdelse af diverse applikationer, kan man forsøge at sikre, at alle dataregler er fundet og specificeret og derefter defineret i databasen, så applikationerne kan nøjes med at teste for forretningslogik. Og så er der jo Boyce-Codd normalformen, som kan synliggøre designfejl og 4. normalform, som tester for sammenhænge, som jævnligt ses uden for teoribøgerne. Der findes også andre begreber, som definerer problemstillinger, der skal overvejes. Det kan være, at der findes super/sub-type hierarkier, der bør defineres for at sikre konsistens. Mange designovervejelser handler om at undgå redundans. Hvad får det egentlig af konse kvenser, hvis der er redundans i en database. Hvis der ikke tages højde for det dårlige design, bliver konsekvensen en meget dårligere datakvalitet. Hvis der skal tages højde for redundante data i applikationen, bliver det en mere kompleks applikation. Efterfølgende vil jeg vise nogle eksempler på de problemstillinger, der forekommer, når ens database indeholder redundante data. Senere i artiklen vil jeg se på, hvad det betyder for udarbejdelse af SQL-sætninger. Det er væsentligt at understrege, at man ikke ud fra et givet datamateriale kan se, om der forekommer redundante data, men kun ved at vide, hvilke regler der forekommer i et givet domæne. Er Enhedspris redundant i efterfølgende tabel? OrderLinie OrderId VareId AntalStk Enhedspris 1 12 3 10 1 14 2 14 2 12 1 10 2 13 3 14 2 14 5 14 3 17 1 20 Ja, hvis en vare ALTID skal sælges til den samme Enhedspris eller til den pris, der er gældende på leveringstidspunktet. Men gælder den regel, at sælges der mindst 100 stk., må der gives rabat, forekommer der ikke redundans. Indtil nu er der blot ingen, der har købt mindst 100 stk., derfor er alle værdier i kolonnen Enhedspris for en given vare den samme. Lige nøjagtig denne problemstilling gør det vanskeligt at skrive sine manipulationssætninger, da alle Copyright 2008 Teknologisk Institut side 2 of 10

regler ikke altid kan læses ud fra definitionerne i databasen eller konkluderes ud fra indholdet af tabellen på det tidspunkt, hvor sætningen skrives. Reglen om de 100 stk. kan evt. være beskrevet i en trigger eller i det modul i forretningslaget, som tester for forretningsregler. Det kan også være, at reglen kun er kendt, men ikke beskrevet. Det vil være lettere at skrive sine manipulations-sætninger, hvis man ved, at der ikke forekommer redundans i databasen. Så når kolonnen Enhedspris er med i tabellen, er det fordi den samme vare kan have forskellige priser. Begrundelsen for at have redundante data i en database er stort set altid, at det giver en bedre performance. Dette er også korrekt i nogle tilfælde, men erfaringen viser, at der sjældent testes for, om det også giver en performance-forbedring af en størrelse, som er værd at gå efter. Ofte overses de problemer det giver, at have redundant information i databasen i form af mere komplicerede manipulations-sætninger og/eller applikationer. Der findes grundlæggende 3 former for redundans forekomst-redundans, hvor informationen kan findes i en anden forekomst i samme tabel kolonne-redundans, hvor informationen kan findes i samme forekomst, men i en anden kolonne redundans mellem tabeller, hvor informationen kan findes i en anden tabel direkte eller indirekte Forekomst-redundans er nok den mest udbredte form, men også der, hvor redundans giver de fleste problemer. I efterfølgende eksempel består tabellen Kunde af 3 kolonner Kundenr, Postnr og Bynavn. Kolonnen Kundenr er primærnøgle og kolonnen Bynavn indeholder redundant information, da Bynavn altid skal være det samme for et givet Postnr. Dvs. at tabellen kun er på 2NF, da der forekommer en transitiv afhængighed. Kunde Kundenr Postnr Bynavn 1 2000 Frederiksberg 2 9000 Aalborg 3 8000 Århus 4 9000 Ålborg 5 1127 København K 6 8000 Århus C Hvis der ved indsættelse af en ny forekomst ikke testes for, om Bynavn er stavet på samme måde, som de forekomster der allerede findes i tabellen, vil der ved manipulation med SE- LECT, UPDATE og DELETE skulle testes for alle stavemåder af Bynavn, hvis der i betingelsen refereres til kolonnen Bynavn. Simplere NEJ, mere kompleks kode Ja. For hvilke stavemåder kan der være anvendt. Resultatet vil blive forkert, hvis der testes for Aalborg stavet med Aa og ikke også for den forkerte stavemåde med Å. Hvis der er 10.000 forekomster stavet korrekt med Aa og 100 forekomster stavet med Å er problemet, at fejlen næppe opdages. Copyright 2008 Teknologisk Institut side 3 of 10

Hvis der skal testes for samme stavemåde, vil det gøre indsættelser og opdateringer mere komplicerede. Hvad skal der forøvrigt ske, hvis den forekomst, der skal indsættes, har den korrekte stavemåde og de eksisterende forekomster i tabellen er stavet forkert. Ja, så skal der rettes i de gamle forekomster, før den nye forekomst kan indsættes. Hvad skal der tilføjes af kode i applikationen for at sikre, at gamle forekomster rettes inden den nye forekomst indsættes? Gør det applikationen simplere? Løsningen er desværre ofte, at man lader stå til. Lidt inkonsistens er vel ikke et problem, før der søges på kolonnen og DET OPDAGES, at ikke alle de ønskede forekomster kommer med i resultatet. Kolonne-redundans giver ikke de samme problemer. I tabellen vises et eksempel, hvor der er kolonne-redundans på kolonnerne Aar, Maaned og Dag. Tid Dato Aar Maaned Dag 2008-7-11 2008 7 11 2008-7-12 2008 7 12 2008-7-13 2008 7 13 2008-7-14 2008 7 14 Konstruktionen laves ofte med det formål at kunne indeksere de kolonner, der indeholder redundans for dermed at opnå en bedre performance. Indsættelser og opdateringer bliver en smule mere kompliceret, især hvis den/de redundante kolonner, er beregnet ud fra komplekse formler. Man skal sikre sig, at den samme formel anvendes alle de steder, hvor der indsættes eller opdateres data. Opstår der fejl, kan værdierne i de redundante kolonner altid genskabes ved en simpel manipulation af tabellen. Problemet vil dog aldrig opstå, hvis de redundante kolonner er defineret som en beregnet kolonne, hvad der f.eks. er muligt i SQL Server, eller de redundante værdier beregnes i en trigger. Såfremt der er redundans i en database bør den vedligeholdes i databasesystemet og ikke i applikationerne. Redundans mellem tabeller giver også problemer. Når vi ser på tabellerne Ordre og Ordrelinie, kan vi se, at der i Ordre-tabellen er medtaget en kolonne, der indeholder den totale pris for en ordre. Hver gang der foretages ændringer i Ordrelinie-tabellen, skal Ordre-tabellen også opdateres. I netop dette tilfælde er problemet ikke så stort, da fejlagtige totaler i Ordretabellen altid kan gendannes ved at genberegne ud fra Ordrelinie-tabellen. Ordre OrdreID KundeID Leveringsdato PrisIalt 1 11 11-12-2008 35 2 13 11-12-2008 10 3 11 12-12-2008 220 4 17 16-12-2008 34 Copyright 2008 Teknologisk Institut side 4 of 10

Ordrelinie OrdreID VareID Antal Enhedspris 1 124 2 10 1 167 3 5 2 167 2 5 3 87 1 100 3 432 2 50 3 564 1 20 4 267 2 17 Tager vi problemet som skitseret under forekomst-redundans og udvider det til også at være redundans mellem tabeller, bliver kompleksiteten større. Vi kunne i et system have 3 tabeller med informationer om personer, f.eks. Kunde, Leverandør og Medarbejder. Hvis alle 3 tabeller indeholder såvel Postnr som Bynavn, vil det medføre endnu mere kompleks kode for at teste, om en værdi i kolonnen Bynavn er stavet korrekt. For ved indsættelse af en leverandør med et endnu ikke eksisterende Postnr i Leverandør-tabellen, skal stavemåden af værdien i kolonnen Bynavn testes op mod tabellen Kunde og/eller tabellen Medarbejder. Hvis værdien i kolonnen Bynavn nu er stavet forkert i en af disse tabeller, har brugeren af systemet måske ikke lov til at rette i disse tabeller. Konsekvensen er, at enten indsættes leverandøren med værdien i kolonnen Bynavn stavet forkert eller også hvad der i praksis viser sig at være den mest gængse løsning der testes ikke. Så hvis du gerne vil sikre dig konsistente data, skal du sørge for at arbejde med normaliserede data. Performance-forbedringer specielt i TP-systemer ved at arbejde på redundante data, giver måske kun forbedringer, fordi der skabes inkonsistente data, og dermed et system med en dårligere datakvalitet. Derfor skal du ved test sikre dig, at det også giver den ønskede performance-forbedring. Men udarbejdelse af manipulations-sætninger bliver i alle tilfælde mere kompliceret. I det efterfølgende eksempel skal vi udføre en UNION-operationen på tabellen Kunde og tabellen Leverandor. Det er interessant at finde ud af, om de 2 tabeller har en fællesmængde, dvs. om der findes kunder der også er leverandører. Findes der ikke en fællesmængde, skal operatoren UNION ALL anvendes i stedet for UNION. Performance-forbedringer skal opnås ved at bruge den rigtige operator. Hvis vi kommer frem til, at en forekomst fra tabellen Kunde med det samme værdi i kolonnen Tlfnr, som en forekomst fra tabellen Leverandor med samme værdi i kolonne Tlfnr, skal opfattes som værende den samme information, har de 2 tabeller en fællesmængde. Vi skal derfor anvende UNION. Problemet er imidlertid, at der kan være forskel på Navn og/eller Adresse i 2 forekomster med samme værdi i kolonnen Tlfnr. Desuden vil der med meget stor sandsynlighed altid være forskel på primærnøglerne, da dette blot er et fortløbende nummer inden for hver tabel. Anvender vi sætningen Copyright 2008 Teknologisk Institut side 5 of 10

SELECT * UNION SELECT * FROM Leverandor får vi ikke fjernet de dubletter, som vi gerne vil have fjernet. Derfor er vi nødt til at løse problemet på en anden måde. For at vise et par løsnings-eksempler anvendes følgende tabeller. CREATE TABLE Kunde ( KundeID INT NOT NULL PRIMARY KEY, Navn VARCHAR(30) NOT NULL, Adresse VARCHAR(30) NOT NULL, Postnr SMALLINT NOT NULL, KundeType CHAR(1) NOT NULL, Tlfnr VARCHAR(8) NOT NULL UNIQUE) CREATE TABLE Leverandor ( LeverandorID INT NOT NULL PRIMARY KEY, Navn VARCHAR(30) NOT NULL, Adresse VARCHAR(30) NOT NULL, Postnr SMALLINT NOT NULL, Tlfnr VARCHAR(8) NOT NULL UNIQUE) GO INSERT INTO Kunde VALUES (1, 'Jens Hansen', 'Nygade 2', 8000, 'A, 12345678') INSERT INTO Kunde VALUES (2, 'Peter Olesen', 'Vestergade 23', 9000, 'A, '98765432') INSERT INTO Kunde VALUES (3, 'Ida Hansen', 'Torvet 8', 8000, 'C, '11223344') INSERT INTO Kunde VALUES (4, 'Sanne Carlsen', 'Søndergade 33', 2000, 'B, '99887766') INSERT INTO Kunde VALUES (5, 'Finn Poulsen', 'Poulsgade 62', 7000, 'B, '11114444') INSERT INTO Leverandor VALUES (1, 'Ida Hansen', 'Torvet 8', 8000, '11223344') INSERT INTO Leverandor VALUES (2, 'Sanne Carlsen', 'Søndergade 33 2. tv.', 2000, '99887766') INSERT INTO Leverandor VALUES (3, 'Finn Poulsen', 'Poulsgade 62', 7000, '11114444') INSERT INTO Leverandor VALUES (4, 'Slagteren', 'Østergade 3', 4000, '66662222') INSERT INTO Leverandor VALUES (5, 'Bageren', 'Nygade 17', 5000, '88884444') Når vi udfører sætningen, får vi forekomster med i resultatet, som opfattes som værende dubletter, selvom KundeId hhv. LeverandorId er udeladt, da der vil være forskelle på indeholdet i andre kolonner i de 2 tabeller. SELECT Navn, Adresse, Postnr, Tlfnr UNION SELECT Navn, Adresse, Postnr, Tlfnr FROM Leverandor ORDER BY Tlfnr Udføres sætningen, får vi det efterfølgende resultat. Kunde med KundeId = 5 og Leverandor med LeverandorId = 3 er kun med i resultatet én gang, da Navn, Adresse, Postnr og Tlfnr er angivet nøjagtig ens i de 2 tabeller. Det samme gælder for Kunde og Leverandor med Navn = Copyright 2008 Teknologisk Institut side 6 of 10

Ida Hansen. Men Navn = Sanne Carlsen er med 2 gange i resultatet, da der er forskel på værdien i kolonnen Adresse i de 2 tabeller. Navn Adresse Postnr Tlfnr Finn Poulsen Poulsgade 62 7000 11114444 Ida Hansen Torvet 8 8000 11223344 Jens Hansen Nygade 2 8000 12345678 Slagteren Østergade 3 4000 66662222 Bageren Nygade 17 5000 88884444 Peter Olesen Vestergade 23 9000 98765432 Sanne Carlsen Søndergade 33 2000 99887766 Sanne Carlsen Søndergade 33 2. tv. 2000 99887766 Hvordan løses dette problem? Da det var kolonnen Tlfnr, som skulles bruges til at finde dubletter, kan vi udføre UNIONoperatoren på denne kolonne. Dette resultat kaldes i sætningen som er vist efterfølgende for KL_Tlf. Vores endelig resultat-tabel skal indeholde lige så mange forekomster som i denne tabel. Vi skal derefter join e tabellerne KL_Tlf, Kunde og Leverandor. Nogle gange skal kolonnerne Navn, Adresse og Postnr tages fra tabellen Kunde andre gange fra tabellen Leverandor. Derfor anvender vi en LEFT JOIN mellem KL_Tlf og tabellerne Kunde og Leverandor. Da vi enten skal tage værdierne fra Kunde eller fra Leverandor anvendes ISNULL. Kunde-kolonnerne vil være NULL, hvis det er en Leverandor og resultatet vil indeholde værdierne fra Leverandor-kolonnerne. På samme måde vil Leverandor-kolonnerne være NULL, hvis det er en Kunde og Kunde-kolonnernes værdi medtages i resultatet. For forekomster i fællesmængden er der både værdier for kolonnerne i tabellen Kunde og for kolonnerne i tabellen Leverandor. I den viste løsning vælges værdierne fra tabellen Kunde Kunde-kolonnerne er første parameter til funktionen ISNULL. SELECT KL_Tlfnr.Tlfnr, ISNULL(Kunde.Navn, Leverandor.Navn) AS Navn, ISNULL(Kunde.Adresse, Leverandor.Adresse) AS Adresse, ISNULL(Kunde.Postnr, Leverandor.Postnr) AS Postnr FROM (SELECT Tlfnr UNION SELECT Tlfnr FROM Leverandor) AS KL_Tlfnr LEFT JOIN Kunde ON KL_Tlfnr.Tlfnr = Kunde.Tlfnr LEFT JOIN Leverandor ON KL_Tlfnr.Tlfnr = Leverandor.Tlfnr Som vi kan se af resultatet, er Navn = Sanne Carlsen kun med 1 gang i resultat-tabellen. En vigtig forudsætning for denne løsning er også, at kolonnen Tlfnr er defineret som værende entydig i hver af de 2 tabeller. UNION i sub-select en fjerner ikke kun dublerede Tlfnr mellem de 2 tabeller, men også evt. dublerede værdier i kolonnen Tlfnr inden for den samme tabel. Copyright 2008 Teknologisk Institut side 7 of 10

Problemet er, at den efterfølgende LEFT JOIN vil danne flere forekomster med det samme Tlfnr i resultat-tabellen. Dette problem kan løses med en APPLY JOIN, men dette vil ikke blive gennemgået her. Navn Adresse Postnr Tlfnr Finn Poulsen Poulsgade 62 7000 11114444 Ida Hansen Torvet 8 8000 11223344 Jens Hansen Nygade 2 8000 12345678 Slagteren Østergade 3 4000 66662222 Bageren Nygade 17 5000 88884444 Peter Olesen Vestergade 23 9000 98765432 Sanne Carlsen Søndergade 33 2000 99887766 Men er denne måde at løse problemet på altid brugbar. Her er det vigtigt at se på definitionen af de 2 tabeller. Da alle kolonner i tabellen Kunde er defineret med NOT NULL, vil kolonnerne fra tabellen Kunde efter LEFT JOIN kun være NULL for de forekomster, hvor informationerne skal tages fra tabellen Leverandor. Så løsningen giver med denne definition af tabellerne, det korrekte resultat. Hvis en af kolonnerne i tabellen Kunde accepterer NULL, vil der måske være et problem. For alle forekomster i fællesmængden af de 2 tabeller, vil data komme fra tabellen Kunde. Men er der NULL i en kolonne fra Kunde, vil data komme fra tabellen Leverandor. Vi får derfor blandet data fra de 2 tabeller i en forekomst i resultat-tabellen. Eksemplet viser, at i tabellen Kunde må Postnr være NULL. Kunde Navn Adresse Postnr Tlfnr Firma A/S Poulsgade 62 NULL 11114444 Leverandor Navn Adresse Postnr Tlfnr Firma A/S Vestergade 11 3000 11114444 I resultatet vil værdien i kolonnen Adresse komme fra tabellen Kunde, men Postnr tages fra tabellen Leverandor. Det er jo ikke sikkert, at kombinationen Adresse = Poulsgade 62 og Postnr = 3000 forekommer. Selvfølgelig er det et problem, at der er angivet en værdi i kolonnen Adresse, og at der mangler en værdi i kolonne Postnr, men det er netop en af de fejl der opstår, når tabellen ikke er defineret præcist og begrænsende nok. Og den uheldige kombination forekommer måske først efter lang tids brug af systemet. Resultat-tabel Navn Adresse Postnr Tlfnr Firma A/S Poulsgade 62 3000 11114444 Vi skal derfor lave en anden løsning af problemet, hvor vi sikrer at alle data i en forekomst i resultat-tabellen enten kommer fra tabellen Kunde eller kommer fra tabellen Leverandor. Copyright 2008 Teknologisk Institut side 8 of 10

Problemet kunne løses ved først at finde Alle forekomster i Kunde, som ikke findes i Leverandor ved sammenligning på Tlfnr difference-mængden mellem Kunde og Leverandor. Alle forekomster i Leverandor, som ikke findes i Kunde ved sammenligning på Tlfnr - difference-mængden mellem Leverandor og Kunde. Alle forekomster i Leverandor, som også findes i Kunde ved sammenligning på Tlfnr fællesmængden mellem Leverandor og Kunde. På disse 3 mellemresultater udføres en UNION ALL. Det er meget vigtigt at konstatere, at differencemængden og fællesmængden ikke er fundet ved at sammenligne forekomst med forekomst ved at bruge operatorerne EXCEPT og IN- TERSECT - men kun ved at sammenligne på kolonnen Tlfnr, som er den kolonne der skal afgøre, om forekomsterne skal opfattes som værende samme information. Sætningen kommer til at se således ud. SELECT Navn, Adresse, Postnr, Tlfnr WHERE NOT EXISTS ( SELECT * FROM Leverandor WHERE Kunde.Tlfnr = Leverandor.Tlfnr) UNION ALL SELECT Navn, Adresse, Postnr, Tlfnr FROM Leverandor WHERE NOT EXISTS ( SELECT * WHERE Kunde.Tlfnr = Leverandor.Tlfnr) UNION ALL SELECT Navn, Adresse, Postnr, Tlfnr FROM Leverandor WHERE EXISTS ( SELECT * WHERE Kunde.Tlfnr = Leverandor.Tlfnr) Det er også vigtigt at understrege, at valg af løsningsforslag kun drejer sig om det korrekte resultat og ikke om performance eller læsbarhed af sætning. Det korrekte resultat vil altid komme forud for performance. Den føste simple sætning med udførelse af UNION-operatoren på de 2 tabeller, ser ud til at løse problemet. Begge tabeller er på 3NF og umiddelbart er designet, som det skal være. De 2 tabeller har defineret en PRIMARY KEY, som er en surrogatnøgle. Desuden er kolonnen Tlfnr i begge tabeller angivet som værende UNIQUE. Alle kolonner skal have en værdi NOT NULL. Så der er gjort mange overvejelser ved definition af tabellerne. Copyright 2008 Teknologisk Institut side 9 of 10

I det viste eksempel er problemet dog, at der kun bør være én tabel, der indeholder kolonnerne Navn, Adresse og Postnr. Hvis der under design-processen var defineret et super/sub-type hierarki med en super-tabel NavnAdresse og 2 sub-type tabeller Kunde og Leverandoer, ville løsningen på ovenstående problem være en simpel SELECT-sætning på super-tabellen NavnAdresse. Men med 2 tabeller skal en af de 2 sidste sætninger anvendes, for at få det korrekte resultat. Som ovenstående eksempler viser, er det meget vigtigt, at den datamodel, der danner grundlag for implementering af databasen, er gennemanalyseret. Ved definition af databasen er det vigtigt, at alle de begrænsninger, der er fundet ved analyse af domænet, medtages. Der må kun tages højde for de begrænsninger, der er defineret i databasen, når der skal udarbejdes manipulations-sætninger. Brug derfor den nødvendige tid på udarbejdelse af datamodellen. Sørg for, at der er testdata der afspejler definitionen af de enkelte kolonner/tabeller, og ikke kun testdata som verdenen ser ud nu. Lav sætninger, der også virker, når de usandsynlige data alligevel bliver gemt i tabellerne. Lad være med at nare dig selv ved letkøbte argumenter, som f.eks. at 3NF er godt nok. Så du bør sikre dig, at dine data altid har en høj kvalitet. Det gør det også lettere, når du på et senere tidspunkt evt. skal anvende dine data i f.eks. en Business Intelligence løsning. Og så er det jo sjovere at videreudvikle i stedet for at bruge tiden på tåbelige og uforståelige fejl, der pludselig opstår. Copyright 2008 Teknologisk Institut side 10 of 10