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';
要查找以后没有撤回的所有出价(由同一用户对同一产品),您可以使用 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;
左连接版本
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'
以仅获得此产品。
您可以使用 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.
我已经启动了一个简单的拍卖系统,其中每一行都包含以下数据:
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';
要查找以后没有撤回的所有出价(由同一用户对同一产品),您可以使用 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;
左连接版本
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'
以仅获得此产品。
您可以使用 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.