2009-09-18 10 views
0

Je voudrais une requête qui, à son plus simple, rejoindra 2 tables ensemble sans autre relation expresse autre que chaque ligne dans ce que j'appellerai la table "pool" correspondre exactement à 1 rangée dans mon autre tableau. Je ne m'inquiète pas quelle ligne, je veux juste que chaque rangée dans ma table primaire obtienne une rangée simple de la table de «piscine» et sachez que chaque rangée de la piscine sera seulement utilisée une fois. Je pensais quelque chose comme ROW_NUMBER() OVER() pourrait être utilisé pour faire correspondre sur un numéro de ligne arbitraire qui serait bien, mais je pense qu'il faut au moins 2 fournisseurs de l'ensemble de lignes interne; Je pensais qu'il y aurait quelque chose de plus simple.Utilisez chaque ligne dans une table en la joignant à une autre table

Pour résoudre le problème de manière un peu plus succincte, vous disposez d'une table d'ID et vous souhaitez la joindre à une table d'enregistrements pour attribuer les ID. Vous ne pouvez utiliser chaque identifiant qu'une seule fois. Quelle structure de requête ou quelle jointure pouvez-vous utiliser pour renvoyer un ensemble de lignes de tous les enregistrements affectés chacun à un ID. Peu importe quel enregistrement obtient quel ID, seulement que chaque ID ne peut être utilisé qu'une seule fois.

Contexte

Pour ceux qui sont intéressés par l'arrière-plan, ce que j'ai est une entité logique qui est composée d'une ligne d'en-tête dans une table d'en-tête qui est générique pour beaucoup d'objets qui nous donne son ID, puis un enregistrement dans une table spécifique à l'entité. J'utilise une requête comme suit pour pregenerate un groupe d'ID dans la table d'en-tête:

declare @idsTable TABLE(ID INT); 

INSERT INTO Header (HeaderType) 
OUTPUT INSERTED.id INTO @idsTable 
SELECT 4 as HeaderType 
    FROM Company c WHERE c.CompanyType = 12; 

À ce stade, j'ai un tas de lignes d'en-tête et les ids (identité) qui ont été affectés aux lignes. Maintenant, je veux utiliser un INSERT similaire dans la table spécifique aux objets, mais j'ai besoin de faire correspondre un ID de @idsTable à seulement 1 ligne dans ma requête de sélection (et donc ma requête d'insertion). Quelque chose comme:

INSERT INTO Specific (HeaderiD, Value1, ...) 
SELECT * 
    FROM @idsTable 
    JOIN RecordsToWrite r2r ON ??? 

Répondre

1

Pourquoi avez-vous renoncez ROW_NUMBER? Exemple chez Adventure Works

SELECT 
    * 
FROM 
(
    SELECT 
     TOP 10 ROW_NUMBER() OVER(ORDER BY EmployeeId) AS join_id,* 
    FROM 
     HumanResources.Employee 
) t1 
INNER JOIN 
(
    SELECT 
     TOP 10 ROW_NUMBER() OVER(ORDER BY DepartmentId) AS join_id,* 
    FROM 
     HumanResources.Department 
) t2 ON t1.join_id = t2.join_id 
+0

Je n'ai pas abandonné, je pensais juste que ce n'était pas particulièrement lisible et qu'il y aurait quelque chose de plus simple. C'est précisément ce que je voulais dire par la solution row_number. –

0

malentendu peut-être im, mais ne peux pas vous le faire:

SELECT * FROM @ idsTable, RecordsToWrite

OU faire une croix Rejoignez

+0

Ce serait n'importe quelle combinaison entre les deux; vous ne pouvez utiliser qu'une ligne de la part de idstable ONCE. –

1

Si je comprends bien vos données , puis le nombre de lignes dans la table RecordsToWrite et le nombre de nouvelles lignes qui proviennent de la requête ... FROM Company ... devrait être le même. Dans ce cas:

  • ajouter un UID simple colonne UNIQUEIDENTIFIER à votre table RecordsToWrite avec la valeur DEFAULT CONTRAINTE (NEWID()), de sorte qu'il est généré automatiquement.
  • changer votre table @idsTable et déclaration à ce

-

declare @idsTable TABLE(ID INT, UID UNIQUEIDENTIFIER); 
INSERT INTO Header (HeaderType) 
OUTPUT INSERTED.id, r.UID INTO @idsTable 
SELECT 4 AS HeaderType, r.UID 
FROM RecordsToWrite r --// maybe other filters to get only number or records as in: 
--//FROM Company c WHERE c.CompanyType = 12; 

Puis rejoindre sur cette colonne UID dans votre deuxième requête.

modifier: nouveau Le code suivant fonctionne très bien sur mon sql-2008, ce qui signifie que je peux utiliser sortie avec INSERT ainsi.Pouvez-vous, essayez:

CREATE TABLE TestOutput (ID INT IDENTITY, TAG VARCHAR(10)); 

DECLARE @idsTable TABLE(ID INT, UID UNIQUEIDENTIFIER); 

INSERT INTO TestOutput (TAG) 
OUTPUT INSERTED.id, NEWID() INTO @idsTable 
SELECT tag 
FROM ( SELECT 'test-1' as tag 
UNION ALL SELECT 'test-2' 
) x 

SELECT * FROM @idsTable 
SELECT * FROM TestOutput 

DROP TABLE TestOutput; 

et j'obtenir des résultats suivants:

ID   UID 
----------- ------------------------------------ 
1   422FF4F0-9CFB-4F67-94C8-2D3B225E39B0 
2   0BD2B2D2-1319-4981-9E26-C09FE844359C 

ID   TAG 
----------- ---------- 
1   test-1 
2   test-2 
+0

J'utilise une approche similaire pour stocker des objets dans une base de données relationnelle, où les classes de base sont stockées dans une table et celles spécifiques aux enfants dans des tables spécifiques. Mais la différence est que je garde la colonne UID au niveau parent, de sorte que chacun de mes objets a aussi un UID global. Je ne le garde pas sur la table des enfants, car tous les FK et les liens de table sont faits sur la colonne INT plutôt que sur l'UID. Avoir UID me donne plus de flexibilité parce que je peux également le spécifier du code de client et être toujours capable de lier à l'objet d'autres requêtes. – van

+0

Cette requête ne fonctionnera pas telle quelle, car vous insérez uniquement la colonne (HeaderType) et vous sélectionnez 2 colonnes dans votre requête de sélection. Moins pédantiquement, je n'ai jamais pu obtenir l'instruction OUTPUT pour accepter quelque chose qui ne provient pas de la table INSERTED. Quand j'essaie, je reçois un 'L'identifiant en plusieurs parties "r.UID" ne peut pas être lié. " Erreur. Dans ce cas, il n'est pas acceptable de modifier la table HEADER pour y trouver le Guid. –

+0

Juste pour être un peu plus clair, c'est l'approche simple que je pensais pouvoir exister mais qui ne pouvait pas fonctionner. J'aimerais si cela pourrait fonctionner. –

Questions connexes