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 数据帧值 [重复]
Spark SQL 中的 where 子句与 join 子句
SQL左连接与JOIN条件中的过滤器与WHERE子句中的过滤器[重复]