我正在进行一项查询,我需要从某个吸烟或使用某种烟草的诊所中提取所有患者的清单。然后,我需要提供一个列表,显示在给定时间范围内已经进行过戒烟咨询的那些患者。
我认为我做得对,但我不确定。前端系统经常会出现不准确的数据(甚至不让我开始)。当我按照它的方式运行查询时,我得到一个我非常确定太低的数字,但是我不确定它是否与数据有关或者我的查询是否存在问题。这就是我所拥有的。
首先,这是我查询所有烟草使用者的查询。 “状态”列表示使用类型 - 您将在此处看到我正在过滤掉3,4和6,它们代表“前用户”,“从未使用过”和“未知”(I'我只是看那些肯定会使用烟草的人 - 每次患者就诊时,这些条目都会得到更新(如适用)。
SELECT DISTINCT sh.PatientID, sh.Description, sh.Category, sh.Status, pd.Physician, vi.VisitDate
FROM SocialHistory sh JOIN PatientDemographic pd ON sh.PatientID = pd.PatientID
JOIN VisitInfo vi ON vi.PatientID = pd.PatientID
WHERE sh.Description LIKE '%tobacco%'
AND sh.Status != 3
AND sh.Status != 4
AND sh.Status != 6
该查询给了我超过3000个结果,考虑到诊所的总患者人数,这似乎是正确的。
现在我需要从2016年1月1日到6月之间已经停止咨询的结果集(在程序代码 - 我将该字段添加到选择列表中)中拉出所有人30,2016。这就是我所拥有的:
SELECT DISTINCT sh.PatientID, vi.ProcedureCode, pd.Physician, vi.VisitDate
FROM
(SELECT DISTINCT sh.PatientID, sh.Description, sh.Category, sh.Status,
pd.Physician, vi.VisitDate, vi.ProcedureCode
FROM SocialHistory sh JOIN PatientDemographic pd ON sh.PatientID = pd.PatientID
JOIN VisitInfo vi ON vi.PatientID = pd.PatientID
WHERE sh.Description LIKE '%tobacco%'
AND sh.Status != 3
AND sh.Status != 4
AND sh.Status != 6
) VisitInfo
WHERE vi.ProcedureCode IN ('counseling1','counseling2','counseling3')
AND VisitDate BETWEEN '01/01/2016' AND '06/30/2016'
我只获得了大约190个结果,鉴于3000多名烟草使用者,这似乎非常低。但它可能是准确的。我只是想确保我的查询是正确的。嵌套的SELECT
语句是否正确结构化?
答案 0 :(得分:3)
我发现您的查询不正确,但正如Matt指出的那样,您不需要子查询。我会这样写,
SELECT DISTINCT sh.PatientID, vi.ProcedureCode, pd.Physician, vi.VisitDate
FROM SocialHistory as sh
JOIN PatientDemographic as pd ON sh.PatientID = pd.PatientID
JOIN VisitInfo as vi ON vi.PatientID = pd.PatientID
WHERE
sh.Description LIKE '%tobacco%'
AND sh.Status not in (3, 4, 6)
AND vi.ProcedureCode IN ('counseling1','counseling2','counseling3')
AND VisitDate BETWEEN '01/01/2016' AND '06/30/2016'
因为它仅用于匹配条件JOIN
,而WHERE
用于限制。 (我相信SQL Server将为这两个查询显示相同的查询计划,也可能为您的查询计划。)
当您使用子查询时,请在其中避开DISTINCT
,除非它具有语义上的重要性。在您的查询中,您将获得不同的患者,然后是一组独特的那些患者。只需要一个。查询计划程序应该找到一个快捷方式,但可能不会,并且任何阅读SQL的人都会看到更多的噪音。
关于问题排查,您可以尝试这样的操作来查看您正在处理的内容:
select count(distinct PatientID) as N, M, Y
from (
SELECT sh.PatientID, vi.ProcedureCode, pd.Physician, vi.VisitDate
, year(vi.VisitDate) as Y
, month(vi.VisitDate) as M
FROM SocialHistory as sh
JOIN PatientDemographic as pd ON sh.PatientID = pd.PatientID
JOIN VisitInfo as vi ON vi.PatientID = pd.PatientID
WHERE
sh.Description LIKE '%tobacco%'
AND sh.Status not in (3, 4, 6)
AND vi.ProcedureCode IN ('counseling1','counseling2','counseling3')
--- VisitDate BETWEEN '01/01/2016' AND '06/30/2016'
) as V
group by M, Y
如果要查看的内容过多,请仅选择Y,或者where M = 1
。
答案 1 :(得分:1)
这是另一种编写查询的方法,它更具可读性并且不需要子选择。
SELECT DISTINCT
sh.PatientID
,vi.ProcedureCode
,pd.Physician
,vi.VisitDate
FROM
SocialHistory sh
INNER JOIN PatientDemographic pd
ON sh.PatientID = pd.PatientID
INNER JOIN VisitInfo vi
ON vi.PatientID = pd.PatientID
AND vi.ProcedureCode IN ('counseling1','counseling2','counseling3')
AND VisitDate BETWEEN '01/01/2016' AND '06/30/2016'
WHERE
sh.Description LIKE '%tobacco%'
AND sh.Status NOT IN (3,4,6)
6个月更可能是为什么你的记录数量较少,扩展时间范围或完全评论该行以测试你的结果集是什么,看看它是否符合你认为结果应该是什么。如果是这样,那么你知道这是6个月。
答案 2 :(得分:1)
在这里,请尝试以下。由于您只需要咨询的患者,这将返回患者和提供者数据。如果您想要那些也没有得到咨询的患者,只需注明IsCounselledStatus > 0
部分和每个人的“0&0”。没有劝告。
declare @StartDate datetime = '1/1/'+cast(datepart(YEAR,getdate()) as varchar(4));
declare @EndDate datetime = '6/30/'+cast(datepart(YEAR,getdate()) as varchar(4));
;with cte as
(
select sh.PatientID, sh.Description, sh.Category, sh.Status, pd.Physician, vi.VisitDate, vi.ProcedureCode,
case when (sh. status not in (3,4,6)
and sh.Description LIKE '%tobacco%'
and VisitDate BETWEEN @StartDate AND @EndDate
and vi.ProcedureCode IN ('counseling1','counseling2','counseling3')
) then 1 else 0 end as IsCounselled
from SocialHistory sh JOIN PatientDemographic pd ON sh.PatientID = pd.PatientID
join VisitInfo vi ON vi.PatientID = pd.PatientID
)
select PatientID, Physician, sum(IsCounselled) IsCounselledStatus
from cte c
where IsCounselledStatus > 0
group by PatientID, Physician
另外,正如大卫指出的那样,如果你在桌子上有参考物品会更好。
答案 3 :(得分:0)
只是建议改进您的编码。计算机擅长记忆事物的代码;人不是。必须输入' 2'对于前吸烟者'或者' 5'为了生活在明尼苏达州'太荒谬了。应该有一个表将代码与实际状态联系起来,因此如果需要,您可以查看。要么是这样,要么使用短字符串代码,例如FSM'对于前吸烟者'或者' LMN'对于明尼苏达州的生活:那种事。