Avatar billede megoo Nybegynder
26. juni 2003 - 12:19 Der er 31 kommentarer

Beholde/kopiere relationer?

Hej

Scenario:
Jeg har:
- 3 tabeller der linker til hinanden (Bil, MotorType, MotorFabrikat).
- hver tabel har et ID felt som er PK + Identity.
- hver tabel har et felt der linker til en af de andres tabellers ID (som jo er PK + Identity)
- hver tabel har en masse andre felter!!.

Eks:

Bil:
[ID][MotorType][...]
1    1
2    1
3    2

MotorType:
[ID][MotorFabrikat][...]
1    1
2    3
3    3

MotorFabrikat:
[ID][Bil][...]
1    1
2    1
3    1


En Bil består jo så af Bil, Motor, MotorFabrikat mm...

Dvs. én record fra Bil, x antal fra MotorType osv.

Jeg skal lave en export/import ting af én Bil til en anden db (ens), hvor ID'erne kan overlappe.

Export er nogenlunde på plads.

Det er import delen som driller, i og med at ID feltet er PK og Identity.
Det skal jo opdateres i de afhængige tabeller.

Det skal nok siges at data bliver exporteret til en 'flad' fil så der er ikke diverse properties eller andet til at opretholde relationerne når de skal importeres.

Problemet er når man vil indsætte en record i en allerede eksisterende tabel (anden db) med Identity (Auto-nummerering)
så vil ID feltet jo få en ny værdi (fint nok), men feltet bliver refereret til i en anden tabel, så det skal jo også opdateres der for at bevare relationen.
Hvis det kun var én record man kopierede kunne man bare bruge @@Identity og få højeste ID, men når man kopierer flere records...ja, hva så?

Det er bare i SQL script til Query Analyser indtil videre.


Håber i forstår spørgsmålet!
Avatar billede bennytordrup Nybegynder
26. juni 2003 - 12:22 #1
Ligger de to databaser på samme server eller på servere, der har forbindelse med hinanden via TCP/IP?
Avatar billede megoo Nybegynder
26. juni 2003 - 12:29 #2
samme server
Avatar billede megoo Nybegynder
26. juni 2003 - 12:44 #3
måske lidt hjælp til forståelse.

Noget i retning af:

indsæt i tabel [dest_db].[dbo].[Bil]
felterne ([MotorType], [felt3], [felt4])
udvælg felter
  [felt3], [felt4]
fra
  [src_db].[dbo].[Bil]
og udvælg
  [ID]
fra [dest_db].[dbo].[MotorType]

- hvor [felt3]=>[felt3], [felt4]=>[felt4] og [ID]=>[MotorType]
Avatar billede janus_007 Nybegynder
26. juni 2003 - 15:47 #4
Kunne du ikke bare sætte IDENTITY_INSERT ON ?? så kunne du da beholde de samme id's
Avatar billede megoo Nybegynder
27. juni 2003 - 08:58 #5
janus> hvad sker der når man indsætter en explicit værdi som allerede eksisterer?
Avatar billede janus_007 Nybegynder
27. juni 2003 - 09:02 #6
Dvs. at der allerede findes records i den nye tabel og foreign keys ?
Avatar billede janus_007 Nybegynder
27. juni 2003 - 09:14 #7
Hvis det er tilfældet, ville jeg finde max id in min target tabel og så ville jeg kopiere id's i min master til en ny kolonne med: newid = oldid + (targetmaxid - oldid + 1) og gøre det på alle relationerne. Herefter ville jeg lave en IDENTITY_INSERT ON !

Det er en dum situation du står i der :-)
Avatar billede megoo Nybegynder
27. juni 2003 - 11:24 #8
ja. Især da jeg ikke har kontrol over db design'et. Men jeg kan ikke lade være med at spekulere på om det ikke er et almindeligt problem?

Og ja, jeg er SQL novice ;o)
30. juni 2003 - 10:27 #9
Jo, det er et almindeligt problem.
Jeg har set flere applicationer, der anvender GUID's for at løse dette. Det giver godt nok nogle lange PK, men det er pengene værd, hvis man har replikerings opgaver som denne.
Avatar billede janus_007 Nybegynder
30. juni 2003 - 11:03 #10
Ja en GUID ville løse opgaven, men det kræver ligesom at den er implementeret fra starten.

Megoo-> Det tidligere forslag jeg kom med kan nu godt lade sig gøre, post evt. lidt db-design osv... Så kan jeg måske lige kigge på en løsning
Avatar billede megoo Nybegynder
30. juni 2003 - 12:41 #11
Ja, har overvejet GUID's, men desværre har jeg ikke mulighed for at ændre db-design ;o(. Så derfor har jeg brug for en generisk funktionalitet, der kan 'efter-'tilpasses den specifikke db!

janus_007> 'post lidt db-design'? Har du en mail-adr?
Avatar billede janus_007 Nybegynder
30. juni 2003 - 13:29 #12
Jeg kan guide dig lidt igennem...

post tabelnavne, primary/ foreign keys

Kan du ikke ændre på tabeldesignet, på den som du skal have overført fra ??

Kan du oprette nye tabeller ??

Hvor mange rækker snakker vi om ??
Avatar billede megoo Nybegynder
30. juni 2003 - 14:15 #13
janus_007> vil ikke post db-design. Bliver alt for meget her på siden. Skal jo mindst have 3-4 tabeller for at vise det. Men mit eksempel med bilen øverst her på siden skitserer sammenhængen.

For at ekspotere en Bil skal både MotorType og MotorFabrikat ekspoteres (Til en 'flad' fil -> .txt eller lign.)
For at importere skal alt det i filen ind i db'en igen. Lad os bare sige det er den samme db. Dvs. et record-sæt ud og ind igen.

Dvs. det nye Bil.ID vil blive = 4 (3+1!). Dette skal jo reflekteres i MotorFabrikat. Ligeledes gælder det for MotorType & MotorFabrikat!

Jeg ved det; skralder situation.

- Kan godt oprette tabeller og db'er, men ikke redesigne!

- ~ 1-1000. Ved ikke helt, men det kan blive mange. Hastighed er ikke et kritisk punkt, hvis det var det du havde i tankerne.
Avatar billede janus_007 Nybegynder
30. juni 2003 - 14:39 #14
ok. hvis du ikke kan alter table, så opret nye tabeller med de nedenstående felter :O)

alter table Bil
add newbilid int, newmotortype int

alter table MotorType
add newmotortype int, newmotorfabrikat int

alter table Motorfabrikat
add newmotorfabrikat int, newbilid int

find max id i hver af de 3 destinationstabeller.

declare @bmax int, @mtmax int, mfmax int
set @bmax = ??
set @mtmax= ??
set @mfmax = ??

update Bil set newbilid = id + @bmax , newmotortype = motortype + @mtmax
update MotorTypeset newmotortype = id + @mtmax, newmotorfabrikat = motorfabrikat + @mfmax
update Motorfabrikat set newmotorfabrikat = motorfabrikat + @mfmax, newbilid = bil + @bmax

Nu skulle alle 3 tabeller meget gerne have fået nye relationer i form af de nye kollonner.

hint: for at oprette nye tabeller, hvis du ikek må alter. så gør flg:
select * into newBil from Bil where 1 = 2
select * into newMotorType from MotorType where 1 = 2
select * into newMotorfabrikat from Motorfabrikat where 1 = 2

og udfør alter table på dem... husk at ændre table name i alter :O). Nu skal der jo naturligvis ikke oprettes nye records i destionations tabellerne, ellers må du bare vælge nogle max der er noget højere!
Avatar billede megoo Nybegynder
01. juli 2003 - 07:43 #15
Kigger lige på det snarest...
Avatar billede megoo Nybegynder
02. juli 2003 - 08:08 #16
janus_007> er ked af det, men det er desværre ikke hvad jeg har brug for.

Export/Import skal være transperant, dvs. det hjælper ikke at lave nye kolonner mm. Data skal impoteres så de indgår på lige fod med allerede eksisterende data.

Eksemplet jeg gav øverst var måst lidt mangelfuldt.
Laver lige ny:

Bil:
[ID][Motor][...]
1    1
2    3
3    2

Motor:
[ID][Cylindre][...]
1    4
2    4
3    6

FåsIFarverne:
[ID][BilID][Farve]
1    1    Grøn
2    3    Gul
3    1    Sort

Dvs. ekportere man en bil med ID = 1 får man følgende records:
[Bil].[ID]  [Bil].[Motor] 
1      1
-----------------
[Motor].[ID]  [Motor].[Cylindre][...]
1            4
-----------------
FåsIFarverne:
[FåsIFarverne].[ID]  [FåsIFarverne].[BilID]  [Farve]
1                    1                      Grøn
3                    1                      Sort

Og skal de importeres igen:

Bil:
[ID][Motor][...]
1    1
2    3
3    2
4    1 (Importeret!)

Motor:
[ID][Cylindre][...]
1    4
2    4
3    6
4    1 (Importeret!)

FåsIFarverne:
[ID][BilID][Farve]
1    1    Grøn
2    3    Gul
3    1    Sort
4    4    Grøn (Importeret!)
5    4    Sort (Importeret!)

Må selvfølgelig ger oprette temp tabeller og kolonner! Har sådan set nogenlunde frie hænder, må dog ikke ændre db-design eller anvende værktøjer der koster penge! Ellers DTS, SQL, stored procedures, etc...
Avatar billede megoo Nybegynder
02. juli 2003 - 08:10 #17
ahh pi* ... prøver lige igen...

Bil:
[ID][Motor][...]
1    1
2    3
3    2
4    4 (Importeret!)

Motor:
[ID][Cylindre][...]
1    4
2    4
3    6
4    4 (Importeret!)
Avatar billede janus_007 Nybegynder
02. juli 2003 - 09:08 #18
Jamen hvis du anvender DTS betyder det jo intet at dine kolonne navne ikke stemmer overens. Det tilpasser du jo bare i transformations!. Du kan have nok så mange overflødige kolonner i en import/eksport og stadig selv bestemme hvad du vil bruge.
Avatar billede megoo Nybegynder
02. juli 2003 - 12:22 #19
ja, men det er stadig et problem med PK og Identity. Data skal stadig ind i den originale db og de rigtige felter? DTS kan ikke afhjælpe problemet med at når en record bliver sat ind i tabellen [Bil] vil det nye [Bil].[ID] få en værdi én højere end den sidste record i tabellen!
Og denne værdi skal opdateres i de tabeller som har en record der anvender en record med dette ID?
Avatar billede janus_007 Nybegynder
02. juli 2003 - 12:44 #20
Du har sat mange spørgsmålstegn... er ikke lige helt med i hvor langt du forstår eller svarer :O)

Du skal bruge IDENTITY_INSERT ON på din destinationstabel !
Avatar billede megoo Nybegynder
02. juli 2003 - 15:53 #21
hehe.. ;o) er software ingeniør men har ikke haft med db/sql før end for 14 dage siden, så forstår nogenlunde men mangler en del erfaring!!

IDENTITY_INSERT ON: ER ON!

Argghh. Skralder at forklare!

Forstil dig at vi skal indsætte en eksporteret record i tabel Bil.

Den kommer til at se sådan ud
[Bil].[ID]  [Bil].[Motor] 
~
4          1

dvs. Bil.ID som før var 1 er nu 4! (pga Identity=autonumerering!)

Tabel [FåsIFarverne] får indsat 2 records:
[ID][BilID][Farve]
1    1    Grøn
2    3    Gul
3    1    Sort
4    4    Grøn (Importeret!)
5    4    Sort (Importeret!)

Her skal BilID som før havde værdi 1 nu være 4!'

Det kan godt løses, når det er flere records der linker til én record (FåsIFarverne -> Bil)

Men det kan ligesåvel være flere records til flere records! ;oOO
Avatar billede jnd Nybegynder
07. juli 2003 - 16:51 #22
Det dur ikke "kun" at bruge identity_insert, de id'er de vil indsætte er jo "i brug", det lyder som om du har tænkt dig at køre det her i et drifts-miljø bliver du nød til at scripte lidt for at få det til at lykkedes, enterprise manageren kan ikke hjælpe dig her, da det kun er 3 tabeller så det går jo nok.

Det nemmeste er at bruge cursors til den slags. Du skal lave en cursor der ittererer over bilerne, indsætter dem samt deres relaterede informationer i den nye database.

Jeg vil på det kraftigste fraråde at du bruger identity_insert i en kørende database, det skriger på inkonsistens og en en klampet løsning.
Avatar billede janus_007 Nybegynder
07. juli 2003 - 17:11 #23
Rolig der jnd, det er såmænd ikke en klampet løsning! Hvem siger at db'en kører mens overførslen gennemføres? Man kan jo eks.vis bruge transactions styring så går det da ikke helt galt heller :O) husk også at køre en DBCC CHECKIDENT tilsidst!


Men korrekt - en cursor kan godt bruges, men det fraråder jeg ;O) (er dybt modstander af dem *GG*) og prøver altid at løse opgaven på anden vis!
Avatar billede jnd Nybegynder
07. juli 2003 - 18:05 #24
Hvad har du imod cursors?

Det bedste modargument er at de er langsomme, men ind imellem har man et problem som bedst løses ved at behandle data sekventielt, derfor har man cursors. Jeg ser lige umiddelbart to løsninger her, enten laver man en temp. tabel til at "oversætte" mellem databaserne eller man bruger cursors, sidst nævnte kan kodes og testes på 20 min.

Men bortset fra det KAN man ikke bruge identity_insert i ovenstående problem, dette skyldes at du vil være nød til at ændre i database designet for at få den til at virke, det er allerede påpeget at det ikke er ønskeligt.
Avatar billede megoo Nybegynder
08. juli 2003 - 07:53 #25
jnd> hvordan vil du bruge cursors? Eksempel? ;o)
"Du skal lave en cursor der ittererer over bilerne, indsætter dem samt deres relaterede informationer i den nye database." Ja, men kan de hjælpe med at opdatere de nye ID's i de relaterede tabeller?

PS: i den rigtige db er der mere end 3 tabeller, nok nærmerere 40, men antallet der skal ex/importeres er måske 10-15 stykker ad gangen. Ved ikke om det har stor indflydelse på hvilken løsningsmodel der bør vælges!
Avatar billede janus_007 Nybegynder
08. juli 2003 - 11:20 #26
jnd-> sådan set alt :O). Og jeg ved godt hvad en cursor er/kan/gør/hvornår og hvordan. Syntes bare alt for ofte at man ser den dårlige programmør bruge den når han ikke helt lige har styr på sql'en! (ikke at det er tilfældet her bare rolig)
Men lav da endelig et eksempel til megoo *S*

Hvorfor skal man ændre i db-designet?? og jaja hvis det er pga. en ekstra kolonne eller 2 så fjernes de jo igen til slut.
Avatar billede jnd Nybegynder
09. juli 2003 - 10:21 #27
Janus> Du er nød til at reseede identity søjlen FØR du overfører data (jeg går stadig ud fra at systemet er i drift), ergo køre alter table=design ændring på target. Med hensyn til at cursors kan misbruges så har du ret, men jeg synes det er mærkelig begrundelse for ikke at ville bruge dem.
Avatar billede jnd Nybegynder
09. juli 2003 - 10:27 #28
Hov, jeg laver et eksempel når jeg får tid, men jeg har lige noget arbejde der skal ordnes først.
Avatar billede zapzap Nybegynder
29. juli 2003 - 14:58 #29
Hej. Har lige skimmet, men kan løsningen ikke være at lade den ene server starte identity-rækken (seed) med 1, og den anden server med f.eks. 10000? Så kommer der ingen clashes på det, for server 1 vil starte med 1,2,3..., og server 2 vil køre 10001, 10002,...
Avatar billede megoo Nybegynder
29. juli 2003 - 17:01 #30
zapzap> Desværre. Det vil kræve en forskellig implementering/setting fra applikation til applikation. Jo, det kunne nok lade sig gøre, men løser ikke problemstillingen, men lapper kun.
Avatar billede zapzap Nybegynder
04. august 2003 - 13:07 #31
Så må du vel i din kopiering bruge en cursor+loop, og @@identity for hver kopiering?
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