【问题标题】:Why FIRST_VALUE and EXISTS statement in WHERE clause doesn't filter rows?为什么 WHERE 子句中的 FIRST_VALUE 和 EXISTS 语句不过滤行?
【发布时间】:2021-10-06 17:11:55
【问题描述】:

在下面示例的输出中,我希望看到 ControlNo = 2222 的单行。

但为什么它仍然给我带来 2 行?

测试数据

IF OBJECT_ID('tempdb..#pol') IS NOT NULL DROP TABLE #pol;
select 1111 as ControlNo, 'Policy1' as PolicyNumber, 'Cancelled' as CurrStatus, 0 as Premium
into #pol
union 
select 2222 as ControlNo, 'Policy1' as PolicyNumber, 'Bound' as CurrStatus, 100 as Premium
--select * from #pol

select *
from #pol a
where PolicyNumber = 'Policy1'
-- here I want to filter only  ControlNo 2222
and exists(
SELECT FIRST_VALUE(ControlNo) OVER (PARTITION BY PolicyNumber ORDER BY ControlNo DESC) 
FROM #pol p
WHERE p.ControlNo = a.ControlNo
)

输出:

ControlNo   PolicyNumber    CurrStatus  Premium
  1111     Policy1          Cancelled     0
  2222     Policy1           Bound       100

如果我只运行 FIRST_VALUE 语句,那么它会按预期工作。给我最后一个ControlNo,也就是2222。

SELECT FIRST_VALUE(ControlNo) OVER (PARTITION BY PolicyNumber ORDER BY ControlNo DESC) 
FROM #pol p

(No column name)
    2222
    2222

但如果我将此语句放在 EXISTS 子句中,那么它会给我带来ControlNo's

【问题讨论】:

  • EXISTS 中的 FIRST_VALUE 毫无意义,因为重要的是是否在 EXISTS 中返回了任何行。

标签: sql sql-server tsql exists


【解决方案1】:

对于 ControlNo 的每个非空值,您的 EXISTS 子查询都将评估为真。这是因为 WHERE 子句在 FRIST_VALUE() 之前被评估,还因为您的子查询在 PolicyNumber 上进行了分区,但在 PolicyNumber 上不相关。尝试以下方法之一以查看差异:

SELECT ControlNo, PolicyNumber, CurrStatus, Premium
FROM
(
SELECT FIRST_VALUE(ControlNo) OVER (PARTITION BY PolicyNumber ORDER BY ControlNo DESC) AS FirstControlNo, *
FROM #pol
) AS p
WHERE ControlNo = FirstControlNo;


SELECT ControlNo, PolicyNumber, CurrStatus, Premium
FROM #pol AS p
WHERE ControlNo = (SELECT MAX(q.ControlNo) FROM #pol AS q WHERE q.PolicyNumber = p.PolicyNumber);

【讨论】:

    【解决方案2】:

    您将获得 2 行,因为对于您在连接中使用的 a.ControlNo(1111 和 2222)的两个值,EXISTS 查询会返回一个结果。所以两者都是有效的:

    SELECT FIRST_VALUE(ControlNo) OVER (PARTITION BY PolicyNumber ORDER BY ControlNo DESC) 
    FROM #pol p
    WHERE p.ControlNo = 1111 -- Exists
    
    SELECT FIRST_VALUE(ControlNo) OVER (PARTITION BY PolicyNumber ORDER BY ControlNo DESC) 
    FROM #pol p
    WHERE p.ControlNo = 2222 -- Exists
    

    因此11112222 行都符合条件。

    如果您只想取出每个 PolicyNumber 的最新条目,这是正确的做法:

    ;WITH ControlNoPerPolicyDescCTE
    AS
    (
        SELECT ROW_NUMBER() OVER (PARTITION BY PolicyNumber ORDER BY ControlNo DESC) AS RowNumber,
            p.ControlNo,
            p.PolicyNumber,
            p.CurrStatus,
            p.Premium
        FROM #pol p
    )
    SELECT cpd.ControlNo,
           cpd.PolicyNumber,
           cpd.CurrStatus,
           cpd.Premium
    FROM ControlNoPerPolicyDescCTE AS cpd
    WHERE cpd.RowNumber = 1
    

    ROW_NUMBER1n 标记每一行,对于每个PolicyNumber(在我们的例子中是递减),并只选择带有ROW_NUMBER = 1 的行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-14
      • 1970-01-01
      • 1970-01-01
      • 2020-01-28
      • 2015-04-10
      • 2021-05-26
      • 1970-01-01
      • 2013-04-17
      相关资源
      最近更新 更多