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