0

我的主查询 (COPD) 中有一组患者,而我的子查询 (CNC) 中有另一组患者。我想从主要查询结果中排除 CANC PAT_ID,但这似乎不起作用并且运行时间太长。有没有更好的方法来排除子查询结果?我尝试了 NOT EXISTS 和 NOT IN,但认为我做的不正确,因为应该被排除在外的患者仍然出现。

SELECT DISTINCT 
        pe.PAT_ENC_CSN_ID,
        pe.PAT_ID,
        pe.CONTACT_DATE,
        vp.PAT_MRN_ID,
        vp.PAT_NAME,
        vp.SEX_NAME,
        pat.BIRTH_DATE,
        vp.AGE_YEARS,
        vp.CUR_PCP_NAME
FROM PAT_ENC pe
    INNER JOIN V_PAT_FACT vp on pe.PAT_ID=vp.PAT_ID
    INNER JOIN PATIENT pat on vp.PAT_ID=pat.PAT_ID
    INNER JOIN CLARITY_ADT adt on pe.PAT_ENC_CSN_ID=adt.PAT_ENC_CSN_ID
    LEFT OUTER JOIN PAT_ENC_DX dx on pe.PAT_ID=dx.PAT_ID
    LEFT OUTER JOIN CLARITY_EDG edg on dx.DX_ID=edg.DX_ID
    INNER JOIN GROUPER_COMPILED_RECORDS gcr on edg.DX_ID=gcr.COMPILED_REC_LIST_VALUE

------- EXCLUSION CANCER
LEFT JOIN
    (
SELECT DISTINCT pl.PAT_ID
    FROM PROBLEM_LIST pl
        LEFT OUTER JOIN CLARITY_EDG edg on pl.DX_ID=edg.DX_ID
        INNER JOIN GROUPER_COMPILED_RECORDS rec on edg.DX_ID=rec.COMPILED_REC_LIST_VALUE
    WHERE rec.GROUPER_ID in ('2100000011')
    )cx on pe.PAT_ID=cx.PAT_ID

WHERE pe.CONTACT_DATE > '2016-07-01 00:00:00.000' 
    AND pe.WEIGHT>= '1587.3'  -- 45 kg or more
    AND vp.AGE_YEARS BETWEEN '40' AND '80'  
    AND vp.SEX_C in ('1','2') --FEMALE or MALE
    AND adt.PAT_CLASS_C in ('101','103','104')  ---IP, OBS or ED
    AND vp.IS_VALID_PAT_YN = 'Y'  -- NOT TEST
    AND pat.PAT_STATUS_C <>'2' --NOT DECEASED
    AND cx.PAT_ID IS NULL
4

3 回答 3

2

首先:DISTINCT通常是一个写得不好的查询的指标。在编写良好的查询中,很少需要从结果中删除重复项,这样一开始就可以避免产生重复项。在您的主查询中,您从表PAT_ENCV_PAT_FACT和中选择数据PATIENT。但是,您也连接了其他四个表,因此可能会重复行。也许您将这些表作为限制行的一种方式,即您只需要在这些表中匹配的行。但是,你为什么要尝试外部加入他们呢?外连接不代表限制。grouper_compiled_records(此外,无论如何,您的外部联接通过内部联接成为内部联接。)

至于排除部分:由于上述相同的原因,您的外部连接再次失败。您正在使用一个反连接,它总是有点难以阅读。我不知道为什么NOT EXISTSNOT IN对你失败了。它们比反连接更可取,因为它们更易于阅读和理解。

您的查询应该是这样的:

SELECT
  pe.pat_enc_csn_id,
  pe.pat_id,
  pe.contact_date,
  vp.pat_mrn_id,
  vp.pat_name,
  vp.sex_name,
  pat.birth_date,
  vp.age_years,
  vp.cur_pcp_name
FROM pat_enc pe
JOIN v_pat_fact vp ON pe.pat_id = vp.pat_id
JOIN patient pat ON vp.pat_id = pat.pat_id
WHERE pe.pat_enc_csn_id IN 
(
  SELECT pat_enc_csn_id 
  FROM clarity_adt
  WHERE pat_class_c IN (101, 103, 104) ---IP, OBS or ED
)
AND pe.pat_id IN
(
  SELECT dx.pat_id
  FROM pat_enc_dx dx 
  JOIN clarity_edg edg on dx.dx_id = edg.dx_id
  JOIN grouper_compiled_records gcr on edg.dx_id = gcr.compiled_rec_list_value
)
AND pe.contact_date > '2016-07-01' 
AND pe.weight >= 1587.3  -- 45 kg or more
AND vp.age_years BETWEEN 40 AND 80
AND vp.sex_c IN (1, 2) -- female or male
AND vp.is_valid_pat_yn = 'Y'  -- not test
AND pat.pat_status_c <> 2 --not deceased
AND pe.pat_id NOT IN -- exclude cancer patients
(
  SELECT pl.pat_id
  FROM problem_list pl
  JOIN clarity_edg edg ON pl.dx_id = edg.dx_id
  JOIN grouper_compiled_records rec ON edg.dx_id = rec.compiled_rec_list_value
  WHERE rec.grouper_id = 2100000011
);

(这假设它problem_list.pat_id可以为空,因为列表中的空值会失败。在列可以为空的不太可能的情况下,NOT IN您必须添加到子查询中。)AND pl.pat_id IS NOT NULL

不过,数据模型看起来有点奇怪。看来一个,可以有好几个,patient鉴定过的。但那你为什么要为每个病人创造他们所有的组合呢?或者是否存在 1:1 的关系,也许恰好是一个?但是为什么要分开表呢?当您知道生日时,为什么要存储年龄(每年都在变化)?pat_idpat_encv_pat_factv_pat_factpatient

我不能确定这正是您寻求的查询,但它应该接近并且您应该能够根据您的需要对其进行调整。

于 2017-07-13T06:28:06.273 回答
1

加盟条件

您的加入条件没有意义。具体来说:

FROM PROBLEM_LIST pl
        LEFT OUTER JOIN CLARITY_EDG edg on pl.DX_ID=edg.DX_ID
        INNER JOIN GROUPER_COMPILED_RECORDS rec on edg.DX_ID=rec.COMPILED_REC_LIST_VALUE

在上面你的LEFT JOINtoCLARITY_EDG表,然后INNER JOINto GROUPER_COMPILED_RECORDSINNER JOIN要求记录存在于左表和右表中,因此将前一个LEFT JOIN转换为INNER JOIN.

假设您需要连接中的所有表,您需要更改LEFT JOININNER JOIN.

主查询也需要修改。

更新(感谢@ThorstenKettner 指出问题):我删除了我的示例查询,因为它没有意义。

查询性能

DISTINCT- 对性能产生负面影响,因为 SQL Server 实际上必须对结果集进行自联接以检查重复项。检查结果,看看你是否真的需要它。如果您确实得到重复项,请找到JOIN产生它们的位置并添加更多连接条件。

WHERE- 指定常量时数据类型不匹配,例如, AND vp.AGE_YEARS BETWEEN '40' AND '80' 如果您的AGE_YEARS列是INT确保您的BETWEEN条件也指定INT了 s,例如BETWEEN 40 AND 80。如果数据类型不同,它会强制 SQL Server 进行类型转换,并且在上述情况下,它会将整个表列转换为字符串(而不是将常量转换为 int)以评估条件。对于大型表,它不会很快,它还会阻止 SQL Server 在此列上使用索引(如果有的话)。

于 2017-07-12T23:11:03.217 回答
0

因为我没有要检查的数据,所以我不假设您的左连接(排除连接)是正确的,尽管在它之后有一个左连接,然后是一个内连接,我将其更改为左连接。

   SELECT DISTINCT 
            pe.PAT_ENC_CSN_ID,
            pe.PAT_ID,
            pe.CONTACT_DATE,
            vp.PAT_MRN_ID,
            vp.PAT_NAME,
            vp.SEX_NAME,
            pat.BIRTH_DATE,
            vp.AGE_YEARS,
            vp.CUR_PCP_NAME
    FROM PAT_ENC pe
        INNER JOIN V_PAT_FACT vp on pe.PAT_ID=vp.PAT_ID
        INNER JOIN PATIENT pat on vp.PAT_ID=pat.PAT_ID
        INNER JOIN CLARITY_ADT adt on pe.PAT_ENC_CSN_ID=adt.PAT_ENC_CSN_ID
        LEFT OUTER JOIN PAT_ENC_DX dx on pe.PAT_ID=dx.PAT_ID
        LEFT OUTER JOIN CLARITY_EDG edg on dx.DX_ID=edg.DX_ID
        INNER JOIN GROUPER_COMPILED_RECORDS gcr on edg.DX_ID=gcr.COMPILED_REC_LIST_VALUE

    WHERE pe.CONTACT_DATE > '2016-07-01 00:00:00.000' 
        AND pe.WEIGHT>= '1587.3'  -- 45 kg or more
        AND vp.AGE_YEARS BETWEEN '40' AND '80'  
        AND vp.SEX_C in ('1','2') --FEMALE or MALE
        AND adt.PAT_CLASS_C in ('101','103','104')  ---IP, OBS or ED
        AND vp.IS_VALID_PAT_YN = 'Y'  -- NOT TEST
        AND pat.PAT_STATUS_C <>'2' --NOT DECEASED
        ------- EXCLUSION CANCER
        AND pe.PAT_ID not in 
                                (
                                SELECT  pl.PAT_ID
                                FROM PROBLEM_LIST pl
                                    LEFT OUTER JOIN CLARITY_EDG edg on pl.DX_ID=edg.DX_ID
                                    LEFT JOIN GROUPER_COMPILED_RECORDS rec on edg.DX_ID=rec.COMPILED_REC_LIST_VALUE 
                                              AND rec.GROUPER_ID in ('2100000011')
                                )
于 2017-07-12T23:18:53.997 回答