【问题标题】:What is the Alternative way of SQL Subquery?SQL子查询的替代方式是什么?
【发布时间】:2018-10-08 10:47:38
【问题描述】:

我需要在第一个约会日期显示所有患者的信息。在这里,我附上了我所需信息的图像。请看:

我解决了它,但我想更有效地做到这一点。这是我的解决方案:

SELECT ROW_NUMBER() OVER(ORDER BY p.Name) SINo,
       or1.PatientID                RegNo,
       p.Name                       PatientName,
       or1.DataHead                 Diagnosis,
       or1.AppointmentDate,
       'First Appointment Date' = (
           SELECT or2.AppointmentDate
           FROM   OPDConsultancyRepository AS or2
           WHERE  or2.OPDConsultancyRepositoryID = (
                      (
                          SELECT MIN(or3.OPDConsultancyRepositoryID)
                          FROM   OPDConsultancyRepository AS or3
                          WHERE  or3.DataType = 3
                                 AND or3.DoctorID = 2139 AND or3.PatientID=or1.PatientID
                          GROUP BY
                                 or3.PatientID
                      )
                  )
       )
FROM   OPDConsultancyRepository  AS or1
       INNER JOIN Patient        AS p
            ON  p.PatientID = or1.PatientID
WHERE  or1.DataType = 3
       AND or1.DoctorID = 2139
ORDER BY
       p.Name

执行计划:

Above query needs 6 sec to produce output.那么有什么建议我如何优化它?

【问题讨论】:

  • 样本数据最好使用DDL + DML。请edit您的问题包括它,您当前的尝试和您想要的结果。更多详情,read this.
  • 索引对性能非常重要。将该 DDL 包含在 @ZoharPeled 请求的信息中。
  • 执行计划是开始的地方。请参阅paste the plan,了解在您的问题中包含执行计划的方法。

标签: sql sql-server tsql sql-server-2014


【解决方案1】:

我想你想要一个窗口函数:

min(or1.AppointmentDate) over (partition by doctorid, datetype, patientid) as first_appointment_date

【讨论】:

    【解决方案2】:

    试试这样的:

    SELECT 
      ...
      [First Appointment Date] = 
        min(iif(or1.DataType = 3 and or1.DoctorID = 2139, or1.AppointmentDate, null))
          over(partition by or1.PatientID) 
      ...
    

    虽然我想知道 DoctorID,但试图保持你的逻辑

    删除这部分看起来很诱人

    and or1.DoctorID = 2139

    【讨论】:

      【解决方案3】:

      这可能对您有用 - 您需要在内部查询中使用 Lead() 和 Lag() 函数。

      https://blog.sqlauthority.com/2011/11/15/sql-server-introduction-to-lead-and-lag-analytic-functions-introduced-in-sql-server-2012/

      选项 - 2

      如果您使用 Self Join 并使用 CTE,则可以实现相同的性能显着性查询。

      【讨论】:

        【解决方案4】:

        如果没有 DDL 和执行计划,就不可能确切地说出是什么让您放慢了速度。肯定会减慢您速度的一件事是相关子查询。注意这篇文章:Hidden RBAR: Triangular Joins 第二 - 输掉最后的ORDER BY p.name 你不需要那个。如果出于显示目的必须对输出进行排序,则让应用程序处理它。最后,您应该检查最昂贵的执行计划并在需要时添加索引。

        我将构建此查询的方式是首先将其设置为您拥有所有列的位置,包括所有相关的患者 ID 和约会日期记录。

        DECLARE @table TABLE (patientId INT, appointmentDate DATE);
        INSERT  @table VALUES (1,GETDATE()),(1,GETDATE()-3),(2,GETDATE()-10),(2,GETDATE()-20),
                              (3,GETDATE()-30),(4,GETDATE()-3),(4,GETDATE()),(4,GETDATE()-100);
        
        SELECT t.patientId, t.appointmentDate FROM @table AS t;
        

        您可以将逻辑转换为索引视图,其中 UNIQUE CLUSTERED INDEX 位于 PatientID 和 AppointmentDate 上。然后将该查询转换为子查询,您有几个选择:

        DECLARE @table TABLE (patientId INT, appointmentDate DATE);
        INSERT  @table VALUES (1,GETDATE()),(1,GETDATE()-3),(2,GETDATE()-10),(2,GETDATE()-20),
                              (3,GETDATE()-30),(4,GETDATE()-3),(4,GETDATE()),(4,GETDATE()-100);
        
        -- Option #1  -- GROUP BY + MIN
        SELECT   t.patientId, MIN(t.appointmentDate)
        FROM     @table AS t
        GROUP BY t.patientId;
        
        -- Option #2  -- Partitioned ROW_NUMBER() filtered for WHERE rn=1 in subquery
        SELECT 
          d.patientId,
          d.appointmentDate
        FROM 
        (
          SELECT 
            t.patientId, 
            t.appointmentDate, 
            rn = ROW_NUMBER() OVER (PARTITION BY t.patientId ORDER BY appointmentDate)
          FROM @table AS t
        ) AS d
        WHERE d.rn = 1;
        
        -- Option #3  -- TOP (1) WITH TIES + ROW_NUMBER()
        SELECT   TOP (1) WITH TIES t.*
        FROM     @table AS t
        ORDER BY ROW_NUMBER() OVER (PARTITION BY t.patientId ORDER BY appointmentDate);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-08-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-10
          • 2017-03-26
          • 1970-01-01
          相关资源
          最近更新 更多