选择使用CASE语句排名的记录。

huangapple go评论78阅读模式
英文:

Selecting ranked records with case statement

问题

select * 
from Sales
where RN = (case when (Product = 'TBD' and RN = 1) then 
                     (case when not exists (select 1 from Sales s2 where s2.Cust = Sales.Cust and s2.RN = 2) 
                           then 1 
                           else 2 
                     end) 
                else 1 
           end)
英文:

Table: Sales

Cust Product Cost RN
123 TBD 100 1
123 socks 67 2
123 games 34 3
456 mouse 100 1

The above Sales table is already ranked based on Cost in descending order.

I'd like to select each single Cust and their corresponding Product and Cost based on RN = 1 except if the RN = 1 has Product = TBD, then select the RN = 2 record per Cust. An additional condition is that if the Cust only has RN = 1and Product = TBD then that particular record should flow through.

I'm honestly not too sure how to condition my query due to the special condition.

I've tried:

select * 
from Sales
where RN = (case when (Product = 'TBD' and RN = 1 and Product <> 'TBD' and RN> 1) then 2 else 1 end)

This doesn't return the intended result as it always shows product = 'TBD'

I think I would need to apply aggregation at Cust level, apply filter to check if record RN = 1 has Product = 'TBD', then manually assign a lower rank number and in final output, select records where RN = 1.

Hoping someone can provide some guidance.

答案1

得分: 1

一种选择是使用窗口函数来识别每个组中的顶级记录;我们可以用一个case表达式来表示这个逻辑,如果第一条记录是TBD产品,则将其降低优先级。

select *
from (
    select s.*,
        row_number() over(
            partition by cust 
            order by case when rn = 1 and product = 'TBD' then 1 else 0 end, rn
        ) seq
    from sales s
) where seq = 1
英文:

One option uses window functions identify the top record per group; we can represent the logic with a case expression that de-prioritize the "first" record if it has the TBD product.

select *
from (
    select s.*,
        row_number() over(
            partition by cust 
            order by case when rn = 1 and product = 'TBD' then 1 else 0 end, rn
        ) seq
    from sales s
) where seq = 1

答案2

得分: 0

以下是您要翻译的内容:

select distinct
    Cust,
    first_value(Product) over (partition by Cust order by case when Product = 'TBD' then 1 else 0 end, RN) as Prod,
    first_value(Cost)    over (partition by Cust order by case when Product = 'TBD' then 1 else 0 end, RN) as Cost
from T;

这基本上与其他答案相同,尽管distinct操作可能会改变查询计划。

如果您可以保证前两行中确切包含您想要的内容:

with data as (
    select *,
        count(*) over (partition by Cust) as RowCnt
    from T
    where RN <= 2
)
select
from data
where RowCnt = 1 or Product <> 'TBD';

如果您没有分析函数可用:

select * from T t1
where RN = 1 and Product = 'TBD'
    or RN = (
        select min(RN) from T t2
        where t2.Cust = t1.Cust and Product <> 'TBD'
    );
英文:
select distinct
    Cust,
    first_value(Product) over (partition by Cust order by case when Product = &#39;TBD&#39; then 1 else 0 end, RN) as Prod,
    first_value(Cost)    over (partition by Cust order by case when Product = &#39;TBD&#39; then 1 else 0 end, RN) as Cost
from T;

This is essentially the same as the other answer though a distinct operation may change the query plan.

If you can guarantee that exactly one of the first two rows contains what you want:

with data as (
    select *,
        count(*) over (partition by Cust) as RowCnt
    from T
    where RN &lt;= 2
)
select
from data
where RowCnt = 1 or Product &lt;&gt; &#39;TBD&#39;;

If you don't have analytic functions available:

select * from T t1
where RN = 1 and Product = &#39;TBD&#39;
    or RN = (
        select min(RN) from T t2
        where t2.Cust = t1.Cust and Product &lt;&gt; &#39;TBD&#39;
    );

答案3

得分: 0

这个查询创建了一个子查询,根据现有的RN和Product = 'TBD' 且 RN = 1 的条件,为其分配一个新的排名号(NewRN)。然后在外部查询中,选择了新的排名号(NewRN)为1的记录。

英文:
SELECT *
FROM (
  SELECT 
    Cust,
    Product,
    Cost,
    CASE
      WHEN RN = 1 AND Product = &#39;TBD&#39; THEN 0  -- Assign a lower rank for Product = &#39;TBD&#39; with RN = 1
      ELSE RN
    END AS NewRN
  FROM Sales
) AS subquery
WHERE NewRN = 1;

This query creates a subquery that assigns a new rank number (NewRN) based on the existing RN and the condition for Product = 'TBD' with RN = 1. Then, in the outer query, it selects the records where the new rank number (NewRN) is 1.

答案4

得分: 0

我一直在调整逻辑,虽然它不是一个 SQL 查询,可能也不是最高效或最干净的,但我已经成功实现了预期的结果。欢迎提出改进意见,

-- 确定 product = 'TBD' 且 RN = 1 的客户

With ab as (
select distinct cust, RN from sales
where product = 'TBD' and RN = 1
),

-- 确定那些具有 product = 'TBD' 且 RN = 1 的客户中,有多于 1 个客户(意味着不只有一个 product = 'TBD')

bc as (
select cust, count(*) from sales
where cust = (select cust from ab)
group by 1 having count(*) > 1),

-- 从 sales 表中选择排除了 product = 'TBD' 且 RN = 1 的客户,并且客户数大于 1

final1 as (
select * from sales
where cust not in (select cust from bc)),

-- 从 sales 表中选择寻找 product = 'TBD' 且 RN = 1 的客户,但选择 RN = 2 的记录,以避免选择第一个 product = 'TBD' 且 RN = 1 的记录

final2 as (
select * from sales
where cust in (select cust from bc)
and RN = 2)

-- 将所有内容合并在一起

select * from final1
union
select * from final2
英文:

I've been tinkering with the logic and while it's not in one sql query and probably not the most efficient or clean I've been able to nail down the intended result. Open to suggestions on how I could improve upon this,

--identify cust where product = &#39;TBD&#39; and RN =1

With ab as (
select distinct cust, RN from sales
where product = &#39;TBD&#39; and RN = 1&#39;
),

--identify for those cust with product = &#39;TBD&#39; and RN =1, how many have more than 1 cust (meaning more than just product = &#39;TBD&#39;)

bc as (
select cust, count(*) from sales
where cust = (select cust from ab)
group by 1 having count(*)&gt;1),

--select from the sales table excluding cust which are product = &#39;TBD&#39; and RN =1 and have count of cust greater than 1

final1 as (
select * from sales
where cust not in (select cust from bc)),

--select from the sales table but look for the cust which are product = &#39;TBD&#39; and RN =1 BUT select the RN = 2 record so avoid selecting the first record with product = &#39;TBD&#39; and RN =1

final2 as (
select * from sales
where cust in (select cust from bc)
where RN = 2)

--combine everything together

select * from final1
union
select * from final2

huangapple
  • 本文由 发表于 2023年6月29日 07:24:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76577248.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定