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

时间:2010-09-07 19:59:49

标签: sql sql-server-2005 insert

我需要以下帮助。我有2张桌子。第一个包含客户捕获的数据。示例

[数据]表

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

并且第二个表格包含需要测试的内容。

[参考]表

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

如果需要,可以创建第三个[results]表。 非常感谢所有帮助。

亲切的问候 雅克

5 个答案:

答案 0 :(得分:1)

我怀疑数据库设计是否需要这个(以及其他一些红色标志),但以下查询应该能满足您的要求:

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
    )

答案 1 :(得分:0)

我认为你需要一个只有personID的人员表,然后你可以用你的测试参考表进行交叉连接(完全外连接),以得出personID和预期测试的时间表。

然后,使用该计划集,使用在personID上执行的测试集进行外部联接,并期望空值而不是no。

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

答案 2 :(得分:0)

这可能不是最好的方法,但是......如果你要在[数据]表上创建主键怎么办,

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

答案 3 :(得分:0)

使用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;

第一个CTE(allTestsForEveryone)为您提供了一整套所有人需要的所有测试。在第二个CTE(allMissingTests)中,我们使用EXCEPT运算符减去已经采取的测试,并在插入它们时添加一个'0'来表示它们的未完成状态(您可以将其替换为“否” - 当我运行此测试时,我使用了bit列。然后,我们将第二个CTE的结果插入Data

答案 4 :(得分: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
   )

我无法抗拒发布@ 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