2
votes

Comment dupliquer des enregistrements, les modifier et les ajouter à la même table

J'ai une question et j'espère que vous pourrez m'aider. :)

Ce que j'ai est un tableau comme celui-ci:

ID  Col1        Col2        ReverseID
1   Number 1    Number A    
2   Number 2    Number B    
3   Number 3    Number C    
4   Number A    Number 1    1
5   Number B    Number 2    2
6   Number C    Number 3    3

Ce que je veux réaliser est:

  • Créez une copie de chaque enregistrement avec des colonnes commutées et ajoutez-les à la table d'origine
  • Ajoutez l'ID du doublon à la colonne ReverseID de l'enregistrement d'origine et vice-versa

La nouvelle table devrait donc ressembler à:

SELECT * INTO #tbl
FROM myTable

UPDATE #tbl
SET Col1 = Col2,
    Col2 = Col1,
    ReverseID = ID

INSERT INTO DUPLICATEtable(
        Col1,
        Col2,
        ReverseID
)

SELECT Col1,
       Col2,
       ReverseID
FROM #tbl

Ce que j'ai fait jusqu'à présent, c'est travailler avec une table temporaire:

ID  Col1        Col2        ReverseID
1   Number 1    Number A    4
2   Number 2    Number B    5
3   Number 3    Number C    6
4   Number A    Number 1    1
5   Number B    Number 2    2
6   Number C    Number 3    3

Dans cet exemple de code, j'ai utilisé une table secondaire juste pour m'assurer de ne pas compromettre les enregistrements de données d'origine.

Je pense que je pourrais ignorer la partie SET et changer les colonnes de la dernière instruction SELECT pour obtenir la même chose, mais je ne suis pas sûr.

Quoi qu'il en soit - avec cela, je termine jusqu'à:

ID  Col1        Col2        ReverseID
1   Number 1    Number A    
2   Number 2    Number B    
3   Number 3    Number C    

La question demeure donc: comment puis-je ajouter correctement les ReverseID aux enregistrements d'origine?

Comme mes connaissances en SQL sont assez faibles, je j'en suis presque sûr, ce n'est pas la manière la plus simple de faire les choses, alors j'espère que vous les gars et les filles pourrez m'éclairer et me conduire vers une solution plus élégante.

Merci d'avance!

br mrt

Edit:

J'essaye d'illustrer mon problème initial, donc cette publication devient longue. ;)

 ED .

Tout d'abord: mon frontend n'autorise aucune instruction SQL, je dois me concentrer sur les classes, les attributs, les relations.

Première cause fondamentale: Les instances d'une classe B (B1, B2, B3, ...) sont liées entre elles dans la relation de classe, ce sont des relations plusieurs-à-plusieurs de la même classe. Mon frontend n'autorise pas les tables de jointure, c'est donc une solution de contournement.

Indiquer qu'un utilisateur ajoute une relation avec B1 comme premier côté (je l'ai juste appelé 'gauche') et B2 comme deuxième côté (droite):

En naviguant à partir de B1, deux relations apparaîtront (FK_Left, FK_Right), mais une seule d'entre elles contiendra une valeur (disons FK_Left).

En naviguant à partir de B2, le value ne sera listée que dans l'autre relation (FK_Right). Donc du côté des utilisateurs, il y a toujours deux relations affichées, mais cela dépend de la façon dont l'enregistrement a été entré, si l'on peut trouver les données derrière relation_left ou relation_right. Ce n'est pas pratique.

Si j'avais tous les enregistrements avec des partenaires inverses, je peux simplement masquer l'une des relations et l'utilisateur verra toutes les informations derrière une relation, quelle que soit la manière dont il a été saisi.

Deuxième cause fondamentale: Le frontend fournit une vue matricielle, qui obtient la classe de relation en entrée et affiche les partenaires de gauche dans les colonnes et les partenaires de droite en lignes.

Disons que je veux voir toutes les instances de A dans les colonnes et leurs partenaires en lignes. , cela n'est possible que si toutes les relations concernant les instances de A sont entrées de la même manière, par ex. toutes les instances A comme partenaire de gauche.

La vue matricielle doit être librement filtrable en ce qui concerne les lignes et les colonnes, donc si j'avais des relations en double, je peux filtrer sur n'importe lequel des partenaires dans les lignes et les colonnes. p >

désolé pour le long texte, j'espère que cela a rendu ma situation un peu plus claire.


7 commentaires

est-ce une chose ponctuelle? ou allez-vous le faire périodiquement?


Qu'essayez-vous de résoudre ici? Stocker deux fois les mêmes données est bien ... redondant. Et maintenant, vous faites pointer chaque ligne existante vers la même ligne mais en sens inverse. Cela a beaucoup de drapeaux rouges partout. Pourquoi ne pas simplement créer une vue qui «inverse» les données? Ce serait assez simple avec une déclaration de mise à jour après la deuxième insertion, mais cela semble juste qu'une meilleure solution ait plus de sens ici.


@sabhari Ce sera une seule fois une machine productive pour mettre à jour les anciens jeux d'enregistrements, tous les nouveaux enregistrements seront automatiquement créés de la "nouvelle" manière


@SeanLange Les nombres dans les colonnes sont des ID de relation avec d'autres tables et c'est une sorte de table de relations m: n. Le frontend montre les relations unidirectionnelles, vous devez donc commencer à un certain nœud (selon celui qui a été entré en premier) pour voir la relation. Comme amélioration, les utilisateurs pourront insérer des relations bidirectionnelles, c'est pourquoi je souhaite copier chaque ensemble. En cas de suppression / modification, je peux utiliser le ReverseID pour trouver facilement le duplicata et faire de même avec le duplicata.


Mais faire deux copies des données est tellement fragile. C'est une mauvaise idée. Créez une vue qui inverse les données à la place. Ou modifiez simplement vos jointures à cette table pour autoriser l'utilisation de OR.


Oui, je ne me sens pas confiant avec cette "solution" aussi, mais je ne sais pas comment l'améliorer. Le frontend n'autorise aucune instruction SQL, je ne peux utiliser qu'une seule table en entrée. Je vais illustrer cela et l'ajouter à la question initiale.


hmm, comme je vois que vous êtes ignorant comme moi, je vais donc continuer avec cette "solution";)


3 Réponses :


1
votes

L'astuce pour ce genre de chose est de commencer avec un SELECT qui obtient les données dont vous avez besoin. Dans ce cas, vous avez besoin d'un ensemble de résultats avec Col1, Col2, reverseid.

CREATE VIEW myTableWithReversals AS
SELECT Col1, Col2, null reverseid FROM myTable
 UNION ALL
SELECT Col2 Col1, Col1 Col2, ID reverseid FROM myTable;

Convainquez-vous que c'est correct - valeurs de colonne échangées, etc.

Ensuite, procédez comme suit: p >

 SELECT Col1, Col2, null reverseid FROM myTable
  UNION ALL
 SELECT Col2 Col1, Col1 Col2, ID reverseid FROM myTable;

Si vous faites cela à partir d'une interface graphique comme ssms, n'oubliez pas de DROP TABLE #tmp;

MAIS, vous pouvez obtenir le même résultat avec une requête pure, sans dupliquer les lignes. Pourquoi faire de cette façon?

  1. Vous enregistrez l'espace perdu pour les lignes inversées.
  2. Vous obtenez toujours les lignes inversées jusqu'à la dernière seconde, même si vous oubliez d'exécuter le processus pour les inverser et les insérer dans le tableau.
  3. Il n'y a pas de problème de cohérence si vous insérez ou supprimez des lignes du tableau.

Voici comment procéder.

INSERT INTO myTable (Col1, col2, reverseid)
SELECT Col1, Col2, reverseid FROM #tmp;

Vous pouvez même en faire une vue et l'utiliser comme s'il s'agissait d'une table à l'avenir.

SELECT Col2 Col1, Col1 Col1, ID reverseid
  INTO #tmp   FROM myTable;

Ensuite, vous pouvez dire SELECT * FROM myTableWithReversals WHERE Col1 = 'value' etc.


3 commentaires

votre première instruction renvoie une erreur Les noms de colonne dans chaque table doivent être uniques. Le nom de colonne 'col1' dans la table '#tmp' est spécifié plus d'une fois. J'ai essayé d'utiliser SELECT Col2 Col1, Col1 Col2, ID reverseid à la place, c'est ce que vous vouliez dire ?


Mes noms de colonne Col1 sont des espaces réservés dans le but de donner un exemple. Vous les remplaceriez par vos propres noms de colonnes.


oui, mais dans votre premier bloc de code, vous avez sélectionné Col1 trois fois, ce qui, je pense, n'est pas comme prévu?



1
votes

Je suggérerais simplement d'utiliser une vue au lieu d'essayer de créer et de maintenir deux copies des mêmes données. Ensuite, vous sélectionnez simplement dans la vue au lieu de la table de base.

create view MyReversedDataView as

select ID
    , Col1
    , Col2
from MyTable

UNION ALL

select ID
    , Col2
    , Col1
from MyTable


0 commentaires

1
votes

Permettez-moi de supposer que la colonne id est auto-incrémentée. Ensuite, vous pouvez le faire en deux étapes:

update t
    set reverseid = tr.id
    from myTable t join
         myTable tr
         on tr.reverseid = t.id;

Ceci insère les nouveaux identifiants avec le bon reverseid . Nous devons maintenant mettre à jour les valeurs précédentes:

insert into myTable (Col1, Col2, reverseid)
    select col2, col1, id
    from myTable t
    order by id;  -- ensures that they go in in the right order

Notez qu'aucune table temporaire n'est nécessaire.


11 commentaires

Je ne comprends pas votre dernier bloc de code, pouvez-vous l'expliquer un peu? J'obtiens une erreur sur le tr.id L'identifiant en plusieurs parties "tr.id" n'a pas pu être lié.


@mrt. . . J'ai ajouté le nom de la table que vous utilisez, ce qui devrait résoudre le problème.


merci, mais malheureusement cela n'a pas aidé, même erreur même si j'ai coupé toutes les lignes après tr.id


@mrt. . . Les exemples de données dans votre question ont une colonne appelée id . Je ne sais pas pourquoi votre requête ne le verrait pas.


hmm, peut-être que j'ai mal compris vos déclarations. Au départ, je pensais que t était le nom de votre table. Mais maintenant, après avoir inséré myTable , je suis confus. Si j'écris le code comme vous, il échoue presque à la update t car t n'est pas connu ... Si je spécifie myTable au lieu de < code> t , il échoue au tr.id . myTable t est-il une sorte de notation d'alias? Je connais juste la table AS t


@mrt. . . t est un alias pour votre table. SQL Server prend en charge les alias pour update lorsqu'ils sont définis dans la clause from . Je ne vois aucune raison d'être confus.


hmm, si je supprime le semikolon après tr.ID je n'obtiens aucune erreur. le semikolon rompt-il la notation d'alias pour la clause de mise à jour?


@mrt. . . Aie. C'était une faute de frappe. Le point-virgule n'aurait jamais dû être là.


bien, maintenant ça marche. Il y a une autre petite erreur dans votre premier bloc de code, vous ne changez pas de colonne. Si je change Col1, Col2 en Col2, Col1 dans l'instruction INSERT ou SELECT , cela fonctionne comme prévu , peut-être que vous pouvez mettre à jour ceci afin que ce soit une réponse entièrement correcte. THX


@mrt. . . Y a-t-il une raison pour laquelle vous ne pensez pas que ce soit "tout à fait correct"? Je remarque que vous ne l'avez pas accepté.


non c'est tout à fait correct, mais je choisis la vue UNION, donc j'ai marqué le commentaire de Seans comme "réponse", malheureusement j'ai dû décocher votre commentaire, bien qu'il soit tout à fait correct