SQL 中的条件 return 值

Conditional return values in SQL

我已经启动了一个简单的拍卖系统,其中每一行都包含以下数据:

Type:= BID|WIT
ProductName := Str
User := Str
Value := Decimal
CreatedAt := datetime

*这里的 WIT 意思是 withdraw,也就是退出物品拍卖 *

用户自然可以发出多个出价请求,始终提高出价(这是在语言级别处理的)

我想列出所有用户的所有最高出价,但在一定条件下,前提是他们不在对给定项目的撤回请求之前。

例如,给定条目

BID,Doll,John,10,2021-11-26 10:10
BID,Ball,John,12,2021-11-26 10:11
BID,Doll,Mary,12,2021-11-26 10:12
BID,Doll,Alice,13,2021-11-26 10:13
BID,Doll,Mary,14,2021-11-26 10:14
BID,Doll,Alice,17,2021-11-26 10:14
BID,Ball,Mary,14,2021-11-26 10:14
WIT,Doll,John,00,2021-11-26 10:16
BID,Doll,Mary,20,2021-11-26 10:18
BID,Ball,John,15,2021-11-26 10:20

如果我magic_sql_query(Doll)我想得到

BID,Doll,Alice,17,2021-11-26 10:14
BID,Doll,Mary,20,2021-11-26 10:18

另外如果我magic_sql_query(Ball)我想得到:

BID,Ball,Mary,14,2021-11-26 10:14
BID,Ball,John,15,2021-11-26 10:20

如何在 SQL 语句中执行此操作?

你可以

  • 使用 row_number() 窗口函数在组内排名(a 组由用户名和产品定义);最新条目 获得排名 1
  • 删除排名 > 1 的所有条目(即用户对该产品有较晚的条目)
  • 删除类型为 'WIT'
  • 的所有条目
    with base as (select
      b.type, 
      b.productname, 
      b.username,
      b.value,
      b.createdat,
      row_number() over (partition by productname, username 
                         order by createdat desc) as rn
      from bids b
      order by productname, username, createdat
    )
    select * from base
    where rn = 1
    and type = 'BID';

SQL Fiddle

要查找以后没有撤回的所有出价(由同一用户对同一产品),您可以使用 NOT EXITS 条件:

select a1.*
where a1.product_name = 'Ball'
  and type = 'BID'
  and not exists (select *
                  from auction a2
                  where a2.product_name = a1.product_name
                    and a2.user_name = a1.user_name
                    and a2.type = 'WIT' 
                    and a2.created_at > a1.created_at)

现在我们需要过滤掉每个产品和用户的最高出价。这可以使用 dense_rank() 函数来完成。

select type, product_name, user_name, value, created_at
from (
  select a1.*, dense_rank() over (partition by product_name, user_name order by value desc) as rnk
  from auction a1
  where a1.product_name = 'Ball'
    and type = 'BID'
    and not exists (select *
                    from auction a2
                    where a2.product_name = a1.product_name
                      and a2.user_name = a1.user_name
                      and a2.type = 'WIT' 
                      and a2.created_at > a1.created_at)
) t
where rnk = 1
order by created_at;

Online example

左连接版本

select t.Type, product_name, t.User, Value, CreatedAt
from (
    select b.*
      , row_number() over(partition by b.product_name, b.user order by b.createdAt desc) rn
    from auction b
    left join auction w
    on w.type = 'WIT' 
       and b.product_name = w.product_name
       and b.user = w.user
       and w.createdAt > b.createdAt
    where b.type = 'BID' 
       and w.product_name is null
       -- and b.product_name = 'Ball'
) t
where rn=1
   -- and product_name = 'Ball'
order by product_name, CreatedAt;

取消注释其中一项 .. product_name = 'Ball' 以仅获得此产品。

db<>fidlle

您可以使用 MAX() window 函数为每个用户获取带有 type = 'BID' 的最后一个条目和带有 type = 'WIT' 的最后一个条目。
然后筛选结果:

SELECT type, productname, "user", value, createdat
FROM (
  SELECT *,
         MAX(CASE WHEN type = 'BID' THEN createdat END) OVER (PARTITION BY "user") last_bid,
         MAX(CASE WHEN type = 'WIT' THEN createdat END) OVER (PARTITION BY "user") last_wit
  FROM tablename
  WHERE productname = ?
) t
WHERE (last_wit IS NULL OR last_wit < last_bid) AND createdat = last_bid;

? 替换为您想要的产品名称。
参见 demo.