Domanda

Modificare:Permettetemi di riformularlo completamente, perché non sono sicuro che esista un modo XML come quello che stavo descrivendo originariamente.

Ancora un'altra modifica:Questo deve essere un processo ripetibile e deve poter essere configurato in modo da poter essere chiamato nel codice C#.

Nel database A, ho una serie di tabelle, correlate da PK e FK.Una tabella genitore, con tabelle figli e nipoti, diciamo.

voglio copiare un insieme di righe dal database A al database B, che ha tabelle e campi con nomi identici.Per ogni tabella, voglio inserire nella stessa tabella nel database B.Ma non posso essere costretto a utilizzare le stesse chiavi primarie. La routine di copia deve creare nuovi PK per ogni riga nel database B e deve propagarli alle righe figlie.In altre parole, mantengo le stesse relazioni tra i dati, ma non gli stessi esatti PK e FK.

Come risolveresti questo problema?Sono aperto a suggerimenti.L'SSIS non è del tutto escluso, ma non mi sembra che farà esattamente questa cosa.Sono anche aperto a una soluzione in LINQ, o all'utilizzo di DataSet tipizzati, o all'utilizzo di qualcosa XML, o praticamente qualsiasi cosa che funzioni in SQL Server 2005 e/o C# (.NET 3.5).La soluzione migliore non richiederebbe SSIS e non richiederebbe la scrittura di molto codice.Ma ammetto che questa soluzione “migliore” potrebbe non esistere.

(Non ho inventato io questo compito, né i vincoli;mi è stato regalato così.)

È stato utile?

Soluzione 10

Penso che molto probabilmente ciò che userò saranno set di dati tipizzati.Non sarà una soluzione generalizzata;dovremo rigenerarli se una qualsiasi delle tabelle cambia.Ma in base a quanto mi è stato detto, non è un problema;non si prevede che le tabelle cambino molto.

I set di dati renderanno ragionevolmente semplice scorrere i dati in modo gerarchico e aggiornare i PK dal database dopo l'inserimento.

Altri suggerimenti

Penso che l'utilità SQL Server tablediff.exe potrebbe essere quello che stai cercando.

Guarda anche questo filo.

Innanzitutto, lasciatemi dire che SSIS è la soluzione migliore.Ma per rispondere alla domanda che hai posto...

Non credo che sarai in grado di farla franca creando nuovi ID ovunque, anche se potresti, ma dovresti prendere gli ID originali da utilizzare per le ricerche.

Il meglio che puoi ottenere è un'istruzione di inserimento per la tabella.Ecco un esempio del codice da eseguire SELECTServe per ottenere i dati dal tuo campione XML:

declare @xml xml 
set @xml='<People Key="1" FirstName="Bob" LastName="Smith">
  <PeopleAddresses PeopleKey="1" AddressesKey="1">
    <Addresses Key="1" Street="123 Main" City="St Louis" State="MO" ZIP="12345" />
  </PeopleAddresses>
</People>
<People Key="2" FirstName="Harry" LastName="Jones">
  <PeopleAddresses PeopleKey="2" AddressesKey="2">
    <Addresses Key="2" Street="555 E 5th St" City="Chicago" State="IL" ZIP="23456" />
  </PeopleAddresses>
</People>
<People Key="3" FirstName="Sally" LastName="Smith">
  <PeopleAddresses PeopleKey="3" AddressesKey="1">
    <Addresses Key="1" Street="123 Main" City="St Louis" State="MO" ZIP="12345" />
  </PeopleAddresses>
</People>
<People Key="4" FirstName="Sara" LastName="Jones">
  <PeopleAddresses PeopleKey="4" AddressesKey="2">
    <Addresses Key="2" Street="555 E 5th St" City="Chicago" State="IL" ZIP="23456" />
  </PeopleAddresses>
</People>
'

select t.b.value('./@Key', 'int') PeopleKey,
    t.b.value('./@FirstName', 'nvarchar(50)') FirstName,
    t.b.value('./@LastName', 'nvarchar(50)') LastName
from @xml.nodes('//People') t(b)

select t.b.value('../../@Key', 'int') PeopleKey,
    t.b.value('./@Street', 'nvarchar(50)') Street,
    t.b.value('./@City', 'nvarchar(50)') City,
    t.b.value('./@State', 'char(2)') [State],
    t.b.value('./@Zip', 'char(5)') Zip
from 
@xml.nodes('//Addresses') t(b)

Ciò che fa è prendere i nodi dall'XML e analizzare i dati.Per ottenere l'ID relazionale dalle persone usiamo ../../ per risalire la catena.

Elimina l'approccio XML e utilizza la procedura guidata di importazione/SSIS.

Di gran lunga il modo più semplice è il confronto dei dati SQL di Red Gate.Puoi configurarlo per fare esattamente quello che hai descritto in un minuto o due.

Adoro anche il confronto SQL e il confronto dati di Red Gate, ma per quanto ne so non soddisferà i suoi requisiti per la modifica delle chiavi primarie.

Se le query tra database/server collegati sono un'opzione, è possibile farlo con una procedura memorizzata che copia i record da padre/figlio nel DB A in tabelle temporanee su DB B e quindi aggiungere una colonna per la nuova chiave primaria nella tabella figlio temporanea che aggiorneresti dopo aver inserito le intestazioni.

La mia domanda è: se i record non hanno la stessa chiave primaria, come fai a sapere se si tratta di un nuovo record?C'è qualche altra chiave candidata?Se si tratta di nuove tabelle, perché non possono avere la stessa chiave primaria?

Ho creato la stessa cosa con una serie di procedure memorizzate.

Il database B avrà le proprie chiavi primarie, ma memorizzerà le chiavi primarie del database A, a scopo di debug.Significa che posso avere più di un database A!

I dati vengono copiati tramite un server collegato.Non troppo veloce;SSIS è più veloce.Ma SSIS non è per principianti e non è facile codificare qualcosa che funzioni con la modifica delle tabelle di origine.

Ed è facile chiamare una procedura memorizzata da C#.

Lo scripterei in una procedura memorizzata, utilizzando gli inserti per eseguire il lavoro duro.Il tuo codice prenderà i PK dalla Tabella A (presumibilmente tramite @@Scope_Identity): presumo che il PK per la Tabella A sia un campo Identità?

Potresti utilizzare tabelle temporanee, cursori o potresti preferire utilizzare CLR: potrebbe prestarsi a questo tipo di operazione.

Sarei sorpreso di trovare uno strumento in grado di farlo immediatamente con a) chiavi predeterminate o b) campi di identità (chiaramente le tabelle B e C non li hanno).

Svuoti le tabelle di destinazione ogni volta e poi ricominci da capo?Ciò farà una grande differenza per la soluzione che devi implementare.Se esegui ogni volta una reimportazione completa, potresti fare qualcosa di simile a quanto segue:

Crea una tabella temporanea o una variabile di tabella per registrare le chiavi primarie vecchie e nuove per la tabella padre.

Inserisci i dati della tabella padre nella destinazione e utilizza il file PRODUZIONE clausola per acquisire i nuovi ID e inserirli con i vecchi ID nella tabella temporanea.NOTA:L'uso della clausola di output è efficiente e consente di eseguire l'inserimento in blocco senza scorrere ogni record da inserire.

Inserisci i dati della tabella figlia.Partecipa alla tabella temporanea per recuperare la nuova chiave esterna richiesta.

Il processo di cui sopra può essere eseguito utilizzando lo script T-SQL, il codice C# o SSIS.La mia preferenza sarebbe per SSIS.

Se aggiungi ogni volta, potrebbe essere necessario mantenere una tabella permanente per tenere traccia della relazione tra le chiavi primarie del database di origine e le chiavi primarie del database di destinazione (almeno per la tabella padre).Se fosse necessario mantenere questo tipo di dati fuori dal database di destinazione, è possibile fare in modo che SSIS li memorizzi/recuperi da una sorta di database di registrazione o anche da un file flat.

Probabilmente potresti evitare lo scenario precedente se nella tabella padre è presente una combinazione di campi che possono essere utilizzati per identificare in modo univoco quel record e quindi "trovare" la chiave primaria per quel record nel database di destinazione.

Quando ho a che fare con attività simili ho semplicemente creato una serie di procedure memorizzate per svolgere il lavoro.

Poiché l'attività specificata è piuttosto personalizzata, difficilmente troverai una soluzione "pronta all'uso".

Giusto per darti qualche suggerimento:

  • Se i database si trovano su server diversi, utilizzare server collegati in modo da poter accedere sia alle tabelle di origine che a quelle di destinazione semplicemente tramite TSQL

Nella procedura memorizzata:

  • Identifica gli elementi principali che devono essere copiati: hai detto che le chiavi primarie sono diverse, quindi devi utilizzare invece vincoli univoci (dovresti essere in grado di definirli se le tabelle sono normalizzate)
  • Identificare gli elementi figlio che devono essere copiati in base ai genitori identificati, per verificare se alcuni di essi sono già nel db di destinazione utilizzare nuovamente l'approccio dei vincoli univoci
  • Identificare gli elementi nipote (stessa logica di genitore-figlio)
  • Copiare i dati iniziando dal livello più basso (nipoti, figli, genitori)

Non sono necessari cursori ecc., è sufficiente memorizzare i risultati immediati nella tabella temporanea (o nella variabile della tabella se si lavora all'interno di una procedura memorizzata)

Questo approccio ha funzionato abbastanza bene per me.

Ovviamente puoi aggiungere parametri alla procedura memorizzata principale in modo da poter copiare tutti i nuovi record o solo quelli specificati.

Fammi sapere se è di qualche aiuto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top