You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求无游标实现新患者统计报表的高效SQL方案

高效统计新患者就诊数量的无游标实现方案求助

我需要生成一份报表,统计特定月份的新患者就诊数量。新患者定义为两类:

  • 从未就诊过的患者
  • 曾就诊但上次就诊距今超3年的患者

目前我通过游标调用表值函数fnNewPatientsByVisitDate实现统计,该游标遍历近6年的就诊日期,执行时间超过35秒,效率极低。现寻求无游标的高效实现思路。


现有游标逻辑

DECLARE @BEGINYEAR  INT;
SET @BEGINYEAR = YEAR(GETDATE()) - 6;

DECLARE @TBLNewPts  TABLE(
VisitDate   SMALLDATETIME,
NewPtCount  INT
)

DECLARE @VisitDate  SMALLDATETIME

DECLARE TblCursor   CURSOR 
FAST_FORWARD

FOR
    SELECT DISTINCT VisitDate
    FROM dbo.Visits
    WHERE YEAR(VisitDate) > @BEGINYEAR 
    
OPEN TblCursor
FETCH NEXT FROM TblCursor INTO @VisitDate
WHILE @@FETCH_STATUS = 0

BEGIN

    INSERT @TBLNewPts 
    SELECT
    @VisitDate, 
    ISNULL(NewPts, 0)
            
    FROM dbo.fnNewPatientsByVisitDate(@VisitDate) 
    
FETCH NEXT FROM TblCursor INTO @VisitDate

END

CLOSE   TblCursor
DEALLOCATE TblCursor;

表值函数fnNewPatientsByVisitDate定义

CREATE FUNCTION [dbo].[fnNewPatientsByVisitDate]
(
@VisitDate  SMALLDATETIME
)
RETURNS 
@tbl TABLE 
(
NewPts  INT
)
WITH SCHEMABINDING

AS
BEGIN
    DECLARE @TBLNewPts  TABLE(
    VisitDate   SMALLDATETIME,
    PtID    INT
    )

    INSERT @TBLNewPts 
    --从未在@VISITDATE之前就诊过的患者
    SELECT 
    @VisitDate,
    PtID
    FROM dbo.vwKeptVisits 
    
    WHERE (VisitDate = @VisitDate)
          AND
          (PtID NOT IN 
                (SELECT PtID
                FROM dbo.vwKeptVisits
                WHERE VisitDate < @VisitDate)
                )   

    UNION

    --曾就诊但上次就诊距@VISITDATE超过3年的患者
    SELECT 
    @VisitDate,
    PtID    
    FROM dbo.vwKeptVisits 
    
    WHERE (VisitDate = @VisitDate)
          AND
          (PtID NOT IN 
                (SELECT PREVIOUS.PtID
                FROM dbo.vwKeptVisits AS PREVIOUS INNER JOIN
                    dbo.vwKeptVisits AS CURRNT ON
                    CURRNT.PtID = PREVIOUS.PtID AND
                    CURRNT.VisitNumber > PREVIOUS.VisitNumber 
                WHERE (PREVIOUS.VisitDate > DATEADD(YEAR,-3,@VisitDate)) 
                ));           

    INSERT @tbl
    SELECT
    COUNT(PtID)
    FROM @TBLNewPts ;

    RETURN 

END

索引视图vwKeptVisits定义及索引

/****** Object:  View [dbo].[vwKeptVisits]    Script Date: 6/18/2024 8:31:05 PM ******/

CREATE VIEW [dbo].[vwKeptVisits]
WITH SCHEMABINDING
AS
SELECT 
COUNT_BIG(*) AS ServiceCount,
V.VisitNumber,
V.PtID,
V.VisitDate,
V.MDID,
V.ApptID,
V.DX1,
V.DX2,
v.DX3,
v.DX4,
V.DX5,
V.POS 
FROM DBO.Visits V INNER JOIN
     dbo.[Visit Details] VD ON 
     V.VisitNumber = VD.VisitNumber
WHERE (V.Void = 0) AND 
(VD.[CPT CODE] <> 'No Show' AND
  VD.[CPT CODE] <> 'MD Cancel' AND
  VD.[CPT CODE] <> 'Pt Cancel') AND
  (V.ApptID IS NOT NULL)
GROUP BY V.VisitNumber, v.PtID , v.VisitDate, V.MDID, V.ApptID,
V.DX1, V.DX2, v.DX3, v.DX4, V.DX5, V.POS
GO

GRANT SELECT ON [dbo].[vwKeptVisits] TO [db_PracManUserRole] AS [dbo]
GO

SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET NUMERIC_ROUNDABORT OFF
GO

/****** Object:  Index [PK_vwKeptVisits]    Script Date: 6/18/2024 8:31:05 PM ******/
CREATE UNIQUE CLUSTERED INDEX [PK_vwKeptVisits] ON [dbo].[vwKeptVisits]
(
    [VisitNumber] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = ON, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 95, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [INDICESGROUP]
GO

SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET NUMERIC_ROUNDABORT OFF
GO

/****** Object:  Index [IX_vwKeptVisits_MDID]    Script Date: 6/18/2024 8:31:05 PM ******/
CREATE NONCLUSTERED INDEX [IX_vwKeptVisits_MDID] ON [dbo].[vwKeptVisits]
(
    [MDID] ASC
)
INCLUDE([PtID],[VisitDate]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = ON, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 95, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [INDICESGROUP]
GO

SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET NUMERIC_ROUNDABORT OFF
GO

/****** Object:  Index [IX_vwKeptVisits_PtID_VisitDate]    Script Date: 6/18/2024 8:31:05 PM ******/
CREATE NONCLUSTERED INDEX [IX_vwKeptVisits_PtID_VisitDate] ON [dbo].[vwKeptVisits]
(
    [PtID] ASC,
    [VisitDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = ON, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 96, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [INDICESGROUP]
GO

示例查询结果

VisitDate   NewPtCount
2019-01-02 00:00:00 0
2019-01-03 00:00:00 0
2019-01-04 00:00:00 0
2019-01-07 00:00:00 2
2019-01-08 00:00:00 3
2019-01-09 00:00:00 0
2019-01-10 00:00:00 4
2019-01-11 00:00:00 5
2019-01-14 00:00:00 1
2019-01-15 00:00:00 0
2019-01-16 00:00:00 0
2019-01-17 00:00:00 0
2019-01-18 00:00:00 0
2019-01-21 00:00:00 0
2019-01-22 00:00:00 1

当前查询耗时超过35秒,急需更高效的无游标实现方式。


内容的提问来源于stack exchange,提问作者JohnT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 01:35:55