SQL WHERE 子句类似于 JOIN 查询

Posted

技术标签:

【中文标题】SQL WHERE 子句类似于 JOIN 查询【英文标题】:SQL WHERE clause like JOIN query 【发布时间】:2016-08-10 22:17:23 【问题描述】:

我有以下程序来获取每个月的预订数量和总价。

现在我需要将附加参数@HasObservation 作为附加参数传递。过滤的逻辑不仅仅是一个普通的字段过滤器。它必须通过加入其他表 PatientXObservation 来过滤。如果此表包含值 1、2、4 的条目,则仅过滤这些预订。

@HasObservation=1 表示,获取记录满足此条件

PatientXObservation O ON B.PatientId = O.PatientId
        AND O.ObservationId IN (1,2,4)

如何在下面的 SQL 中添加这个过滤器?我不确定如何在此处添加此内容

CREATE PROCEDURE [dbo].[GetDoctorOperationReportTest] 
( @IncludeVAT BIT = 0, @HasObservation BIT = 0 )
AS
BEGIN
    SET NOCOUNT ON     

    SELECT 
        YEAR(StartTime) [Year]
      , MONTH(StartTime) [Month]
      , COUNT(BookingId) [BookingCount]
      , SUM(CASE 
          WHEN IsVAT = 1 AND @IncludeVAT = 1
          THEN (Price / 100) * 80
          ELSE Price
          END) AS TotalPrice
      , C.CategoryId
      , CategoryName
    FROM Category c
    LEFT JOIN Booking B ON C.CategoryId = B.CategoryId
    WHERE
      C.IncludeReport = 1
    GROUP BY YEAR(StartTime), MONTH(StartTime), C.CategoryId, CategoryName
    ORDER BY 1, 2, CategoryName
END

我已尝试使用 TEMP 表,但查询运行非常非常慢。这里的另一个问题是如果@HasObservation 为0,我需要避免使用此过滤器,但不幸的是它选择了observation=0 :(

SELECT B.BookingId
    ,B.StartTime
    ,B.IsVAT
    ,B.Price
    ,c.CategoryId
    ,c.CategoryName
    ,c.IncludeReport
    ,observation = (
        CASE 
            WHEN isnull(o.PatientId, 0) = 0
                THEN 0
            ELSE 1
            END
        )
INTO #Temp
FROM Category c
LEFT JOIN Booking B ON C.CategoryId = B.CategoryId
LEFT JOIN PatientXObservation O ON B.PatientId = O.PatientId
    AND O.ObservationId IN (1,2,4)



SELECT YEAR(StartTime) [Year]
    ,MONTH(StartTime) [Month]
    ,COUNT(BookingId) [BookingCount]
    ,SUM(CASE 
            WHEN IsVAT = 1
                AND @IncludeVAT = 1
                THEN (Price / 100) * 80
            ELSE Price
            END) AS TotalPrice
    ,CategoryId
    ,CategoryName
FROM #Temp
WHERE IncludeReport = 1
    AND observation = @HasObservation
GROUP BY YEAR(StartTime)
    ,MONTH(StartTime)
    ,CategoryId
    ,CategoryName
ORDER BY 1
    ,2
    ,CategoryName

【问题讨论】:

考虑一个 SELECT 语句,您可以使用它来简单地返回您不感兴趣的所有 PatientId,作为一组键。然后,您可以使用外部连接来确保 B.PatientId 不在该列表中。 【参考方案1】:

仅当您的 @HasObservation 参数不为零时,您才可以使用 IN 子句进行过滤:

SELECT 
    YEAR(StartTime) [Year]
  , MONTH(StartTime) [Month]
  , COUNT(BookingId) [BookingCount]
  , SUM(CASE 
      WHEN IsVAT = 1 AND @IncludeVAT = 1
      THEN (Price / 100) * 80
      ELSE Price
      END) AS TotalPrice
  , C.CategoryId
  , CategoryName
FROM Category c
LEFT JOIN Booking B ON C.CategoryId = B.CategoryId
WHERE
  C.IncludeReport = 1
  and (@HasObservation=0 
        or B.PatientID in 
            (select PatientID 
            from PatientXObservation O 
            where ObservationId IN (1,2,4))
        )
GROUP BY YEAR(StartTime), MONTH(StartTime), C.CategoryId, CategoryName
ORDER BY 1, 2, CategoryName

【讨论】:

这几乎让我凌晨 1 点跑下楼去拿我的笔记本,但你抢了我!【参考方案2】:

您可以尝试使用IF 语句,如下所示。

CREATE PROCEDURE [dbo].[GetDoctorOperationReportTest] 
  ( @IncludeVAT BIT = 0, @HasObservation BIT = 0 )
AS
BEGIN
 SET NOCOUNT ON
 IF @HasObservation = 1 
  BEGIN
   SELECT 
       YEAR(StartTime) [Year]
     , MONTH(StartTime) [Month]
     , COUNT(BookingId) [BookingCount]
     , SUM(CASE 
         WHEN IsVAT = 1 AND @IncludeVAT = 1
         THEN (Price / 100) * 80
         ELSE Price
         END) AS TotalPrice
     , C.CategoryId
     , CategoryName
   FROM Category c
   LEFT JOIN Booking B ON C.CategoryId = B.CategoryId
   LEFT JOIN PatientXObservation O 
          ON B.PatientId = O.PatientId
         AND O.ObservationId IN (1,2,4)
   WHERE C.IncludeReport = 1
   GROUP BY YEAR(StartTime), MONTH(StartTime), C.CategoryId, CategoryName
   ORDER BY 1, 2, CategoryName
  END
 ELSE
  BEGIN
   SELECT 
       YEAR(StartTime) [Year]
     , MONTH(StartTime) [Month]
     , COUNT(BookingId) [BookingCount]
     , SUM(CASE 
         WHEN IsVAT = 1 AND @IncludeVAT = 1
         THEN (Price / 100) * 80
         ELSE Price
         END) AS TotalPrice
     , C.CategoryId
     , CategoryName
   FROM Category c
   LEFT JOIN Booking B ON C.CategoryId = B.CategoryId
   WHERE
     C.IncludeReport = 1
   GROUP BY YEAR(StartTime), MONTH(StartTime), C.CategoryId, CategoryName
   ORDER BY 1, 2, CategoryName
  END
END

【讨论】:

我看不到它们在哪里被过滤,你现在可能会得到重复。 它只是一个基于BIT运算符@HasObservation的IF/Else;它使用他的相同代码,加上他的加入条件。不知道这将如何返回 dups,除非他提供的代码会返回 dups?【参考方案3】:

更改您的 WHERE 以使 @HasObservation 的两个版本返回所需的内容。如果我理解您的问题,那么如果 @HasObservation = 1 那么还有一个过滤器。 SQL 如下:

CREATE PROCEDURE [dbo].[GetDoctorOperationReportTest] 
( @IncludeVAT BIT = 0, @HasObservation BIT = 0 )
AS
BEGIN
SET NOCOUNT ON     

SELECT 
    YEAR(StartTime) [Year]
  , MONTH(StartTime) [Month]
  , COUNT(BookingId) [BookingCount]
  , SUM(CASE 
      WHEN IsVAT = 1 AND @IncludeVAT = 1
      THEN (Price / 100) * 80
      ELSE Price
      END) AS TotalPrice
  , C.CategoryId
  , CategoryName
FROM Category c
LEFT JOIN Booking B ON C.CategoryId = B.CategoryId
LEFT JOIN PatientXObservation O 
    ON B.PatientId = O.PatientId
WHERE
  C.IncludeReport = 1
  and
  (
    (
        @HasObservation = 0         
    )
    or
    (
        @HasObservation = 1
        and O.ObservationId IN (1,2,4)
    )
)

GROUP BY YEAR(StartTime), MONTH(StartTime), C.CategoryId, CategoryName
ORDER BY 1, 2, CategoryName
END

如果需要,您的 @HasObservation = 0 可以有不同的过滤器;您只需要调整代码以包含一些排除逻辑。

【讨论】:

Total Rows 当前为 7233。添加此条件并离开加入后,如果 @HasObservation=1 正确,我将得到 83。 But getting 8400 for @HasObservation=0 is wrong. I should get 7233 only 尝试向“@HasObservation = 0”添加条件。查看额外的 1167 行,看看是否有一个公共变量,然后排除它。例如,您可以排除 O.ObservationId 是否为 NULL 或其他内容。 (@HasObservation = 0 并且 O.ObservationId 为 NULL)【参考方案4】:

您的加入应该是:

LEFT JOIN PatientXObservation O 
          ON B.PatientId = O.PatientId

然后添加谓词

WHERE  (@HasObservation = 1 AND O.ObservationId IN (1,2,4)) OR (@HasObservation = 0 AND O.ObservationId < 0)

【讨论】:

Total Rows 当前为 7233。添加此条件并离开加入后,如果 @HasObservation=1 正确,我将得到 83。 But getting 8400 for @HasObservation=0 is wrong. I should get 7233 only 我进行了编辑。我假设 O.ObservationId 永远不应小于 0。如果是这种情况,包括 O.ObservationId

以上是关于SQL WHERE 子句类似于 JOIN 查询的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL Server 查询的 WHERE 子句中引用或 INNER JOIN 一个 Pandas 数据帧值 [重复]

深入理解CQL中的Where子句

Spark SQL 中的 where 子句与 join 子句

SQL左连接与JOIN条件中的过滤器与WHERE子句中的过滤器[重复]

ClickHouse高级数据查询SQL: WITH/JOIN/IN/INTO OUTFILE/嵌套子查询/交并差计算等

将原生 SQL where 子句应用于实体的 Nhibernate 查询