如何在不使用 HAVING 子句的情况下仅选择不相关的行

发布于 2025-01-13 07:57:58 字数 833 浏览 0 评论 0原文

我的“序列号”表的数据如下:

序列号日期状态
A0001003.03.2022BAD
A0001004.03.2022GOOD
A0001105.03.2022BAD
A0001206.03.2022BAD

我只想选择那些实际状态不佳的序列号。 因此,我期望的结果只有 A00011 和 A00012。这是因为 A00010 最新(查看日期)状态为“良好”。 查询应该只返回不同的值(这里我使用按序列分组)。

我发现的唯一解决方案是使用 HAVING 子句:

SELECT [Serial], MAX([Date]),  MAX([Status])
FROM [Serials]
GROUP BY [Serial]
HAVING MAX([Status]) != 'GOOD'

我宁愿避免使用它,因为它使用更多资源(特别是在扫描更大的表时)。此外,表中的大多数序列无论如何都会将最新记录设置为“GOOD”,因此当前查询将拉取几乎整个表,然后 HAVING 将仅裁剪其中的大部分。对于大表来说,这会造成很大的资源浪费。 因此,如果有人可以帮助我找到执行相同操作但仅使用 WHERE 子句的查询。 谢谢。

I have table "Serials" with data as follow:

SerialDateStatus
A0001003.03.2022BAD
A0001004.03.2022GOOD
A0001105.03.2022BAD
A0001206.03.2022BAD

I would like to select only those serial number that their actual status is not GOOD.
So as result I expect only A00011 and A00012. This is because A00010 latest (look on Date) status is GOOD.
Query should return only DISTINCT values (Here I used grouping by Serial).

Only solution I've found is with HAVING clause:

SELECT [Serial], MAX([Date]),  MAX([Status])
FROM [Serials]
GROUP BY [Serial]
HAVING MAX([Status]) != 'GOOD'

I would prefer to avoid using it as it uses more resources (specially when bigger tables are scanned). Additionally, most of Serials in table will have latest record as GOOD anyway, so current Query will pull almost whole table and then HAVING will just crop most of it. For big table it would be big waste of resources.
So if someone could help me to find the query that will do the same but with WHERE clause only.
Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

纸伞微斜 2025-01-20 07:57:58

一种选择是使用 ROW_NUMBER() 查找每个序列的最后一行,然后过滤掉状态良好的那些行。

WITH
  sorted AS
(
  SELECT
    *,
    ROW_NUMBER() OVER (PARTITION BY Serial ORDER BY [date] DESC)   AS serial_row   
  FROM
    serials
)
SELECT
  *
FROM
  sorted
WHERE
      serial_row  = 1
  AND status     != 'GOOD'

One option is to use ROW_NUMBER() to find the last row for each Serial, and then filter out those rows with a Good Status.

WITH
  sorted AS
(
  SELECT
    *,
    ROW_NUMBER() OVER (PARTITION BY Serial ORDER BY [date] DESC)   AS serial_row   
  FROM
    serials
)
SELECT
  *
FROM
  sorted
WHERE
      serial_row  = 1
  AND status     != 'GOOD'
写给空气的情书 2025-01-20 07:57:58

试试这个:

Select Serial
From Serials s
Where s.Date = 
   (Select Max(Date) From Serials
        Where Serial = s.Serial) 
   And Status != 'Good'

如果表中可能存在多个具有相同序列号和日期的记录,则添加“不同”一词。

Select Distinct Serial
From Serials s
Where s.Date = 
    (Select Max(Date) From Serials
        Where Serial = s.Serial) 
   And Status != 'Good'

要在第三条注释中也解决您的请求(仅选择以前良好的序列号),只需将其添加为Where 子句的附加谓词:

Select Distinct Serial
From Serials s
Where s.Date = 
    (Select Max(Date) From Serials
        Where Serial = s.Serial) 
   And Status != 'Good'
   And exists                  -- This predicate ensures that only 
      (Select * from Serial x   -- previously 'GOOD' serials 
       Where serial = s.Serial  -- will appear
          and Date < (Select Max(Date) From Serials
                      Where Serial = s.Serial) 
          and status = 'GOOD')                        

基本上,您想要做的事情可以直接转换为 SQL:

您需要这些序列的 [distinct] 列表,这些序列是每个特定序列的最后时间记录的集合,经过过滤以仅包含不是好人。
因此,您创建一个子表,其中仅包含日期是该序列的最新日期的记录,然后按状态对其进行过滤以仅包含不好的记录,然后从该表中提取序列值。

根据表的大小,如果您在日期属性上有索引,这将非常有效(或更好)。

Try this:

Select Serial
From Serials s
Where s.Date = 
   (Select Max(Date) From Serials
        Where Serial = s.Serial) 
   And Status != 'Good'

If there can exist more than one record in the table with same Serial and Date, then add the word Distinct

Select Distinct Serial
From Serials s
Where s.Date = 
    (Select Max(Date) From Serials
        Where Serial = s.Serial) 
   And Status != 'Good'

To also address your request in third comment, (to only select Serials that have previously been Good), just add that as an additional predicate to Where clause:

Select Distinct Serial
From Serials s
Where s.Date = 
    (Select Max(Date) From Serials
        Where Serial = s.Serial) 
   And Status != 'Good'
   And exists                  -- This predicate ensures that only 
      (Select * from Serial x   -- previously 'GOOD' serials 
       Where serial = s.Serial  -- will appear
          and Date < (Select Max(Date) From Serials
                      Where Serial = s.Serial) 
          and status = 'GOOD')                        

Basically, what you want to do can be translated directly into SQL:

You want a [distinct] list of those Serials that are a set of the last chronological record of each specific serial, filtered to only include the Not Good ones.
So you create a sub table that only includes the records where the date is the latest date for that serial, then filter it by status to only include the not good ones, then extract the serial value from that table.

Depending on how large the table is, This will work very well (or better) if you have an index on the Date attribute.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文