2010-09-07 3 views
2

J'ai besoin d'aide pour les éléments suivants. J'ai 2 tables. Le premier contient les données capturées par le client. Exemple.SQL Server 2005: Insertion d'enregistrements manquants dans une table figurant dans une autre table de référence

[Data] Tableau

PersonId Visit   Tested  Done 
01   Day 1   Eyes  Yes 
01   Day 1   Ears  Yes 
01   Day 2   Eyes  Yes 
01   Day 3   Eyes  Yes 
02   Day 1   Eyes  Yes 
02   Day 2   Ears  Yes 
02   Day 2   Smell  Yes 
03   Day 2   Eyes  Yes 
03   Day 2   Smell  Yes 
03   Day 3   Ears  Yes 

et la deuxième table contient les informations de ce qui doit être testé.

[Ref] Tableau

Visit  Test 
Day 1  Eyes 
Day 1  Ears 
Day 1  Smell 
Day 2  Eyes 
Day 2  Ears 
Day 2  Smell 
Day 3  Eyes 
Day 3  Ears 
Day 3  Smell 

maintenant je suis en train d'écrire une requête d'insertion sur le [Data] pour insérer les tests non existants qui devaient être effectués. Le résultat que je suis à la recherche par exemple:

[Data] table après:

PersonId Visit   Tested  Done 
01   Day 1   Eyes  Yes 
01   Day 1   Ears  Yes 
01   Day 1   Smell  No 
01   Day 2   Eyes  Yes 
01   Day 2   Ears  No 
01   Day 2   Smell  No 
01   Day 3   Eyes  Yes 
01   Day 3   Ears  No 
01   Day 3   Smell  No 
02   Day 1   Eyes  Yes 
02   Day 1   Ears  No 
02   Day 1   Smell  No 
02   Day 2   Eyes  No 
02   Day 2   Ears  Yes 
02   Day 2   Smell  Yes 
02   Day 3   Eyes  No 
02   Day 3   Ears  No 
02   Day 3   Smell  No 
03   Day 1   Eyes  No 
03   Day 1   Ears  No 
03   Day 1   Smell  No 
03   Day 2   Eyes  Yes 
03   Day 2   Ears  No 
03   Day 2   Smell  Yes 
03   Day 3   Eyes  No 
03   Day 3   Ears  Yes 
03   Day 3   Smell  No 

Si nécessaire, il sera OK pour créer une troisième table [résultats]. Toute aide sera grandement appréciée.

Cordialement Jacques

Répondre

0

Je pense que vous aurez besoin d'une table personne avec seulement les PERSONID, vous pouvez faire une jointure croisée (jointure externe complète) avec votre table ref test pour arriver à un calendrier de personIDs et les tests attendus. Puis, avec cet ensemble de planification, effectuez une jointure externe avec l'ensemble des tests effectués sur les ID de personne et attendez des valeurs nulles au lieu de non. Puis, si vous le souhaitez, vous pouvez convertir vos nulls en 'non'.

+0

Merci, je vais faire un essai va faire savoir. –

0

Ceci est probablement pas la meilleure façon, mais .... Et si vous deviez créer une clé primaire sur la table [Data],

PK: (PersonID, Visit, Tested) 

Ensuite, vous pouvez créer une fonction pour insérer chaque personID, et le jour

CREATE PROCEDURE InsertTests 
@PersonID int 
, @Day nvarchar(10) 

Begin 

BEGIN TRY 
INSERT INTO [Data] 
(PersonID, Visit, Tested, Done) 
VALUES 
(@PersonID, @Day, Eyes, No) 
END TRY 
BEGIN CATCH 
END CATCH 

BEGIN TRY 
INSERT INTO [Data] 
(PersonID, Visit, Tested, Done) 
VALUES 
(@PersonID, @Day, Ears, No) 
END TRY 
BEGIN CATCH 
END CATCH 

BEGIN TRY 
INSERT INTO [Data] 
(PersonID, Visit, Tested, Done) 
VALUES 
(@PersonID, @Day, Smell, No) 
END TRY 
BEGIN CATCH 
END CATCH 

End 
1

Je me méfie de la conception de base de données si elle requiert (ainsi que quelques autres drapeaux rouges), mais la requête suivante devrait vous donner ce que vous demandez:

INSERT INTO Results 
(
    person_id, 
    visit, 
    tested, 
    done 
) 
SELECT 
    P.person_id, 
    T.visit, 
    T.test, 
    'No' 
FROM 
    (SELECT DISTINCT person_id FROM Results) P -- Replace with Persons table if you have one 
CROSS JOIN Templates T 
LEFT OUTER JOIN Results R ON 
    R.person_id = P.person_id AND 
    R.visit = T.visit AND 
    R.test = T.test 
WHERE 
    R.person_id IS NULL 

Ou bien:

INSERT INTO Results 
(
    person_id, 
    visit, 
    tested, 
    done 
) 
SELECT 
    P.person_id, 
    T.visit, 
    T.test, 
    'No' 
FROM 
    (SELECT DISTINCT person_id FROM Results) P -- Replace with Persons table if you have one 
INNER JOIN Templates T ON 
    NOT EXISTS 
    (
     SELECT * 
     FROM 
      Results R 
     WHERE 
      R.person_id = P.person_id AND 
      R.visit = T.visit AND 
      R.test = T.test 
    ) 
0

est ici une solution peut-être-plus simple en utilisant Common Table Expressions:

WITH allTestsForEveryone AS 
(
SELECT * 
FROM (SELECT DISTINCT PersonID FROM DATA) a 
CROSS JOIN REF 
), 
allMissingTests AS 
(
SELECT PersonID,Visit,Test FROM allTestsForEveryone 
EXCEPT 
SELECT PersonID,Visit,Tested FROM DATA 
) 
INSERT INTO [DATA] (PersonID, Visit, Tested, Done) 
SELECT PersonID, Visit, Test, 0 AS Done FROM allMissingTests; 

Le premier CTE (allTestsForEveryone) vous donne un ensemble de tous les tests nécessaires tous les jours pour toutes les personnes . Dans le second CTE (allMissingTests), nous soustrayons les tests que ont pris en utilisant l'opérateur EXCEPT, et ajoutons un '0' pour représenter leur statut non fait quand nous les insérons (vous pouvez le remplacer par 'Non' - quand j'ai exécuté ce test j'ai utilisé une colonne bit). Nous insérons ensuite les résultats du second CTE dans Data.

+0

Belle utilisation de SAUF. Notez que mettre le 0 en 2ème CTE est complètement inutile. Juste l'utiliser comme un littéral dans le SELECT. Aussi, je pense qu'il serait plus clair de mettre simplement le contenu du 1er CTE dans le second CTE. – ErikE

+0

En fait, je trouve l'approche des deux CTE "plus claire", donc ... des traits différents, je suppose. :) Mais je suis d'accord avec vous sur le fait de mettre le 0 dans le SELECT - édité! –

0
INSERT Data 
SELECT P.PersonID, R.Visit, D.Test, 'No' 
FROM 
    Person P -- or (SELECT DISTINCT PersonID FROM Data) P 
    CROSS JOIN Ref R 
WHERE 
    NOT EXISTS (
     SELECT 1 
     FROM Data D 
     WHERE 
     P.PersonID = D.PersonID 
     AND R.Visit = D.Visit 
     AND R.Test = D.Test 
    ) 

Et je ne peux pas résister affichant une version courte de la réponse de @ djacobson:

ALTER TABLE Data ADD CONSTRAINT DF_Data_Done DEFAULT ('No') 

INSERT Data (PersonID, Visit, Test) 
SELECT P.PersonID, R.Visit, D.Test 
FROM Person P CROSS JOIN Ref R 
EXCEPT SELECT PersonID, Visit, Test FROM Data 
Questions connexes