带输入参数的存储过程 - 基于集合的新方法

时间:2012-12-10 21:09:03

标签: sql sql-server tsql

我在网上找到了以下脚本的改编版本:

CREATE TABLE alphaCodes
(personID INTEGER NOT NULL,
 codes CHAR(10) NOT NULL,
 );

INSERT INTO alphaCodes
VALUES (1, '12300'), (1, '23400'), (1, '45623'), 
       (2, '99900'), (2, '23411'), (2, '78900'), 
       (3, '12300'), (3, '23400'), (3, '45699');
go
CREATE PROCEDURE GetPeopleWithCodes 
(@d1 CHAR(10) = NULL, @d2 CHAR(10) = NULL, 
 @d3 CHAR(10) = NULL, @d4 CHAR(10) = NULL, 
 @d5 CHAR(10) = NULL)
AS BEGIN
--cte for the alphaCodes table
WITH Patient_Diagnosis (personID, codes)
AS (SELECT personID, codes FROM alphaCodes),

codeList (codePattern)
AS
--row constructor makes a table of the variables that will be passed into the stored procedure
(SELECT X.codePattern 
  FROM (VALUES (@d1), (@d2), (@d3), (@d4), (@d5))
        AS X(codePattern)
 WHERE X.codePattern IS NOT NULL)

SELECT DISTINCT personID 
 FROM Patient_Diagnosis AS PD1
 WHERE NOT EXISTS 
       (SELECT *
          FROM codeList
         WHERE NOT EXISTS 
              (SELECT *
                 FROM Patient_Diagnosis AS PD2
                WHERE PD1.personID = PD2.personID
                  AND PD2.codes LIKE codeList.codePattern));
END; 
--for whatever reason, the % wildcard does not and and the _ has to be used
exec dbo.GetPeopleWithCodes '123___'

此存储过程最多需要五个输入参数,并且基本上会返回您包含的许多参数的内部联接。所以,如果你运行

exec dbo.getpeoplewithcodes '234___' 

1,2,3将被退回。如果你运行

exec dbo.getpeoplewithCodes '234____','123___' 

将返回1,3。当我尝试这样做时,我使用动态SQL创建了一个包含各种连接到alphaCodes表的表。上面的方法比较快,但有一个问题:我不能为我的生活完全理解它。我喜欢上次连接中的like运算符,但我没有得到第一个where not exists子查询。谁能帮忙解释一下发生了什么?你怎么能只有两个引用alphaCodes表并让这个东西仍然有效?

1 个答案:

答案 0 :(得分:1)

如果我已正确理解,此代码旨在返回所有诊断代码与所有输入参数模式匹配的患者列表。

最后的SELECT语句是一个双重否定,表示相同的要求 - 它返回不在Patient_Diagnosis.Patient_Id行集合中的行中所有Patient_Diagnosis值的不同列表没有与输入参数列表匹配的代码。这是编写此查询的一种令人困惑的方式。

以下未经过严格测试,但只显示alphaCodes表的一次扫描,似乎返回相同的结果。我已经删除alphaCodes上的CTE,因为它是多余的:

ALTER PROCEDURE GetPeopleWithCodes 
(@d1 CHAR(10) = NULL, @d2 CHAR(10) = NULL, 
 @d3 CHAR(10) = NULL, @d4 CHAR(10) = NULL, 
 @d5 CHAR(10) = NULL)
AS BEGIN
WITH codeList (codePattern)
AS
(SELECT X.codePattern 
  FROM (VALUES (@d1), (@d2), (@d3), (@d4), (@d5))
        AS X(codePattern)
 WHERE X.codePattern IS NOT NULL
)
SELECT pd.PersonId 
FROM codeList cl
JOIN alphaCodes pd
ON pd.codes LIKE cl.codePattern
GROUP BY pd.personID
HAVING COUNT(*) = (SELECT COUNT(*) FROM codeList)
END
GO