【问题标题】:Filter records in a table based on some columns根据某些列过滤表中的记录
【发布时间】:2021-06-07 03:45:23
【问题描述】:

我有一张桌子(比如,桌子名称是“items”),如下所示。

id timestamp name amount
100 16106800 pqr 10
100 16106800 pqr 0
100 16106400 pqr 15

如果有多个具有相同名称和相同时间戳的记录,那么我想排除一个数量为零的记录。例如 - 在上表中,我们有两条记录(第一条和第二条记录)具有相同的名称和相同的时间戳,所以我必须排除一条数量为零的记录。

预期结果如下:

id timestamp name amount
100 16106800 pqr 10
100 16106400 pqr 15

我写了一个类似下面的查询,但这并不完全有效。

SELECT *
FROM items w
WHERE EXISTS (
    SELECT *
    FROM items x  
    WHERE x.timestamp = w.timestamp AND x.name=w.name
) AND w.amount > 0

当所有时间戳都不同时,我的上述查询会失败。如果没有相同名称和相同时间戳的记录,则不会从 items 表中排除任何内容。

编辑:如果该表中只有一行金额为零,则不应排除。

【问题讨论】:

  • 如果该名称和时间戳只有一个 0 行怎么办?
  • 如果只有一行则不应排除。

标签: sql sql-server subquery exists


【解决方案1】:

为什么不只是聚合?

select id, timestamp, name, sum(amount) as amount
from items
group by id, timestamp, name;

这将返回每个id/timestamp/name 组合的一行,以及该组合的总金额。我怀疑这是你真正想要的。

但是,您也可以通过调整逻辑来修改查询:

SELECT i.*
FROM items i
WHERE i.amount > 0 OR
      NOT EXISTS (SELECT 1
                  FROM items i2
                  WHERE i2.timestamp = i.timestamp AND
                        i2.name = i.name AND
                        i2.amount > 0
                 );

即返回amount > 0 所在的所有行。然后还返回 timestamp/name 组合的所有行,其中没有 amount > 0 的行。

【讨论】:

    【解决方案2】:

    我的查询产生以下结果:

    如果你只有一个记录,尽管数量,它被显示

    如果您有多个记录,它将仅显示数量> 0的记录

    那么,试试这个:

    SELECT *
    FROM items t1
    WHERE NOT EXISTS 
        (SELECT 1 FROM items t2
        WHERE t1.id = t2.id 
        AND t1.timestamp = t2.timestamp 
        AND t1.name = t2.name
        AND t2.amount > 0)
    OR t1.amount > 0
    

    SQL Fiddle

    请注意:我使用不同的 DBMS 在 SQL Fiddle 上编写过,但使用的 SQL 是标准的,因此对于 SQL Server 也可以。

    【讨论】:

    • 如果该表中只有一行金额为零怎么办? , 无法打开 SQL Fiddle 链接。
    • @user3656231 如果您只有一行数量 = 0,您将显示它,作为您的问题
    • 因此,当只有一条数量为零的记录时,您的查询不会排除,对吗? .这是我在测试时发现的。
    • @user3656231 亲爱的,也许我不明白您的要求。我的查询是:如果您只有一条记录(金额 = 0 或金额 > 0)记录,如果您有多条记录,则只显示金额 > 0 的记录。这样就实现了你的目标?
    【解决方案3】:
    ;with a as (
    select distinct id,timestamp,name from items
    ),
    with b as (
    select * from items
    where amount > 0
    )
    select a.id,a.timestamp,a.name,isnull(b.amount,0) amount  
    from a join b on a.timestamp = b.timestamp and a.name = b.name
    

    【讨论】:

      【解决方案4】:

      您也可以使用count() over()

      SELECT id, timestamp, name, amount
      FROM (
          SELECT *, count(*) over(partition by id, timestamp, name) cnt
          FROM yourtable) t
      WHERE cnt = 1 OR amount > 0
      

      db<>Fiddle

      【讨论】:

        【解决方案5】:

        条件窗口聚合COUNT(CASE...) OVER... 可能是您最好的选择:

        SELECT id, timestamp, name, amount
        FROM (
            SELECT *,
                count(case when amount > 0 then 1 end)
                    over(partition by timestamp, name) CountNonZeroes
            FROM Table
        ) t
        WHERE CountNonZeroes = 0 OR amount > 0
        
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-09-09
          • 2015-09-03
          • 2018-12-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-26
          • 2021-05-31
          相关资源
          最近更新 更多