工会与案例或其他替代方案
Posted
技术标签:
【中文标题】工会与案例或其他替代方案【英文标题】:Union versus Case or other alternative 【发布时间】:2021-03-25 21:52:54 【问题描述】:我有 2 个表,加入时会告诉我与特定产品关联的组织。每个组织都有一个状态,“活跃”或“传统”。我试图只返回“活动”组织,除非没有“活动”组织,然后我想要“传统”组织。如果没有联合,我无法弄清楚如何解决这个问题,我不想使用联合,因为我的一些查询很长而且很复杂。
我当前的方法是两个子查询:一个用于活动的,一个用于旧的,然后在 Excel 中手动组合它们。这是低效且烦人的。我希望也许 CASE 语句可以消除 UNION,但到目前为止我还没有运气。这是该问题的简化图:
组织机构表
|ORG_NAME |ORG_STATUS|PRODUCT_ID|
|--------------|----------|----------|
|Organization 1|Active |1 |
|Organization 2|Legacy |1 |
|Organization 3|Legacy |2 |
|Organization 4|Active |3 |
产品表
|ID|PRODUCT_NAME|
|--|------------|
|1 |Product 1 |
|2 |Product 2 |
|3 |Product 3 |
所需的输出:(我确实可以通过 UNION 获得,但我希望有一个不那么繁琐的解决方案。)
|PRODUCT_NAME|ORG_NAME |ORG_STATUS|
|------------|--------------|----------|
|Product 1 |Organization 1|Active |
|Product 2 |Organization 3|Legacy |
|Product 3 |Organization 4|Active |
如果我使用 UNION 以外的任何东西,我会得到下面的输出,但是当还有一个 Active org 时,我不想要 Legacy org。
|PRODUCT_NAME|ORG_NAME |ORG_STATUS|
|------------|--------------|----------|
|Product 1 |Organization 1|Active |
|Product 1 |Organization 2|Legacy |
|Product 2 |Organization 3|Legacy |
|Product 3 |Organization 4|Active |
我觉得应该有一种简单的方法来根据指定的标准选择填充哪个组织,但我无法找出正确的标准来使其工作。任何帮助将非常感激!提前致谢!
这是简化的联合查询:
SELECT PROD.PRODUCT_NAME, ORG.ORG_NAME
FROM products prod, organizations org
WHERE PROD.ID = ORG.PRODUCT_ID AND ORG.STATUS = 'Active'
UNION
SELECT PROD.PRODUCT_NAME, ORG.ORG_NAME
FROM products prod, organizations org
WHERE PROD.ID = ORG.PRODUCT_ID AND ORG.STATUS = 'Legacy'
AND ORG.PRODUCT_ID NOT IN (SELECT PROD.ID
FROM products prod, organizations org
WHERE ORG.STATUS = 'Active')
我在 select 和 where 语句中都尝试过 CASE,但无法正常工作。下面是其中一种尝试,但这并没有考虑到组织和产品之间的连接,只是给了我所有的组合。我尝试将 org 和 product 连接起来,为我提供一个可以使用的变量,但这也无济于事。可能做不到?
WHEN ORG.STATUS = 'Active' THEN ORG.ORG_NAME
ELSE ORG.ORG_NAME
END
【问题讨论】:
【参考方案1】:您可以使用分析函数row_number
来确定“最佳”行,然后选择该行。
select *
from (
select o.org_name, o.org_status, p.product_id, p.product_name,
row_number() over (partition by p.product_id
order by case when o.org_status = 'Active'
then 1
else 2
end asc) rn
from products p
join organizations o
on p.product_id = o.product_id
)
where rn = 1;
这是example from liveSQL
【讨论】:
我一直在关注你,直到我只选择第 1 行。我使用了你的 liveSQL 示例(语句 34),我可以得到完全相同的输出,但目标是消除 RN 2. 从您上面的查询中,我看到您在 from 语句中是如何做到的,但是当您像 liveSQL 中的语句一样纠正它时,我不知道您是如何做到的(这真的很好。) @ShandaFin - 在我发布的答案中,我使用谓词where rn = 1
将整个内容包裹在一个内联视图中。看起来我在运行那个版本的查询之前保存了我的 LiveSQL 会话,我只是把它放在我的答案中。【参考方案2】:
这是横向连接的一个很好的用例:
select p.*, o.org_name, o.order_status
from products p left join lateral
(select o.*
from organizations o
where o.product_name = p.product_name
order by o.order_status -- "Active" before "Legacy"
fetch first 1 row only
) o
on 1=1;
【讨论】:
我能够让它运行,但我仍然得到 4 行,而不是 3 行。实际上我的查询中涉及第三个表 - 一个连接产品和组织的表。我简化了问题中的表格,但也许这就是问题所在?这是我现在拥有的:select p.product_name, o.org_name, o.status from products p, product_pairs pp left join lateral (select o.* from organizations o where pp.ogn_id_established_to = o.ID order by o.STATUS fetch first 1 row only) o on 1=1 WHERE p.ID = pp.prod_id
【参考方案3】:
你应该可以做这样的事情:
SELECT PROD.PRODUCT_NAME, ORG.ORG_NAME, MIN(ORG.STATUS) as OrgStatus
FROM products prod, organizations org
WHERE PROD.ID = ORG.PRODUCT_ID
GROUP BY PROD.PRODUCT_NAME, ORG.ORG_NAME
这当然依赖于 Active 在 Legacy 之前排序的事实......
这也假设产品和组织之间存在1:1
关系。
【讨论】:
今日提示:切换到现代、明确的JOIN
语法。更容易编写(没有错误),更容易阅读(和维护),并且在需要时更容易转换为外连接。
这就是问题所在。我的一些产品与组织之间存在 1:2 的关系。不过,我喜欢这个简单的想法!以上是关于工会与案例或其他替代方案的主要内容,如果未能解决你的问题,请参考以下文章
关于路由交换设备接头物理层或协议层无法UP及其他情况案例分析