SQL Server 2005:在另一个引用表中的表中插入缺少的记录

SQL Server 2005:在另一个引用表中的表中插入缺少的记录,sql,sql-server-2005,insert,Sql,Sql Server 2005,Insert,我需要以下方面的帮助。我有两张桌子。第一个保存客户端捕获的数据。例如 [数据]表 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

我需要以下方面的帮助。我有两张桌子。第一个保存客户端捕获的数据。例如

[数据]表

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
第二个表包含需要测试的内容的信息

[Ref]表

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
现在,我正在尝试对[Data]编写一个插入查询,以插入需要执行的不存在的测试。我正在寻找的结果例如:

[数据]下表:

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
如果需要,可以创建第三个[结果]表。 我们将非常感谢您的帮助

问候
Jacques

我认为您需要一个仅包含Personid的person表,然后您可以与您的test ref表进行交叉连接(完全外部连接),以制定Personid和预期测试的时间表

然后,使用该计划集,对Personid上执行的测试集进行外部联接,并期望为null而不是no


然后,如果需要,可以将空值转换为“否”。

这可能不是最好的方法,但是……如果要在[Data]表上创建主键

PK: (PersonID, Visit, Tested)
然后您可以为每个personID和Day创建一个要插入的函数

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

如果数据库设计需要这样做(以及其他一些危险信号),我会怀疑它,但是下面的查询应该会给出您的要求:

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
或者:

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
    )

下面是一个可能更简单的解决方案,使用:

第一个CTE(allTestsForEveryone)为您提供了一组所有人员在所有日期所需的所有测试。在第二个CTE(allMissingTests)中,我们减去使用
Exception
运算符进行的测试,并在插入它们时添加一个“0”来表示它们的未完成状态(您可以将其替换为“否”-当我运行此测试时,我使用了一个
列)。然后,我们将第二次CTE的结果插入
数据

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
   )
我忍不住发布了@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

谢谢,我会试试的,会让你知道的。很好地使用了EXCEPT。请注意,将0放入第二个CTE完全没有必要。只需在SELECT中将其用作文本。此外,我认为将第一个CTE的内容放入第二个CTE会更清晰。我实际上发现两个CTE的方法“更清晰”,所以。。。我猜是不同的中风但是我同意你的观点,只是把0放在“选择编辑”中!
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