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.
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]
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 !
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.
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?
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.
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!
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:
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
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...
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.
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?
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.
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!
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.
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!
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.
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.
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,...
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.
Så må du vel i din kopiering bruge en cursor+loop, og @@identity for hver kopiering?
Synes godt om
Ny brugerNybegynder
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.