oracle - 减少 pl/sql 的过载
问题描述
我需要一个一个地匹配几个属性。我希望避免使用多个选择语句。下面是示例。
Table1
Col1|Price|Brand|size
-----------------------
A|10$|BRAND1|SIZE1
B|10$|BRAND1|SIZE1
C|30$|BRAND2|SIZE2
D|40$|BRAND2|SIZE4
Table2
Col1|Col2|Col3
--------------
B|XYZ|PQR
C|ZZZ|YYY
Table3
Col1|COL2|COL3|LIKECOL1|Price|brand|size
-----------------------------------------
B|XYZ|PQR|A|10$|BRAND1|SIZE1
C|ZZZ|YYY|D|NULL|BRAND2|NULL
在表 3 中,我需要通过检查以下条件从表 2 中插入数据。
- 查找表 2 中记录的匹配项,如果品牌和尺寸、价格匹配
- 如果未找到匹配项,则仅尝试品牌、尺寸
- 仍然找不到匹配项,仅尝试品牌
在上面的示例中,对于 table2 中的第一条记录,发现与所有 3 个属性匹配,因此插入到 table3 和第二条记录中,记录 'D' 匹配但只有 'Brand'。
我能想到的就是将 3 个不同的插入语句(如下所示)写入 oracle pl/sql 块。
insert into table3
select from tab2
where all 3 attributes are matching;
insert into table3
select from tab2
where brand and price are matching
and not exists in table3 (not exists is to avoid
inserting the same record which was already
inserted with all 3 attributes matched);
insert into table3
select from tab2
where Brand is matching and not exists in table3;
任何人都可以建议一种更好的方法来以更好的方式实现它,避免多次从 table2 中选择。
解决方案
这是一个案例OUTER APPLY
。
OUTER APPLY
是一种横向连接,允许您连接引用出现在您的FROM
子句前面的表的动态视图。使用该功能,您可以定义一个动态视图来查找所有匹配项,按照您指定的排序顺序对它们进行排序,然后使用FETCH FIRST 1 ROW ONLY
仅在结果中包含第一个匹配项。
UsingOUTER APPLY
意味着如果没有匹配,你仍然会得到表 B 的记录——只是所有的匹配列null
。如果你不想这样,你可以更改OUTER APPLY
为CROSS APPLY
.
这是一个工作示例(带有分步注释),无耻地从 Michael Piankov 的回答中窃取表创建脚本:
create table Table1 (Col1,Price,Brand,size1)
as select 'A','10','BRAND1','SIZE1' from dual union all
select 'B','10','BRAND1','SIZE1' from dual union all
select 'C','30','BRAND2','SIZE2' from dual union all
select 'D','40','BRAND2','SIZE4'from dual
create table Table2(Col1,Col2,Col3)
as select 'B','XYZ','PQR' from dual union all
select'C','ZZZ','YYY' from dual;
-- INSERT INTO table3
SELECT t2.col1, t2.col2, t2.col3,
t1.col1 likecol1,
decode(t1.price,t1_template.price,t1_template.price, null) price,
decode(t1.brand,t1_template.brand,t1_template.brand, null) brand,
decode(t1.size1,t1_template.size1,t1_template.size1, null) size1
FROM
-- Start with table2
table2 t2
-- Get the row from table1 matching on col1... this is our search template
inner join table1 t1_template on
t1_template.col1 = t2.col1
-- Get the best match from table1 for our search
-- template, excluding the search template itself
outer apply (
SELECT * FROM table1 t1
WHERE 1=1
-- Exclude search template itself
and t1.col1 != t2.col1
-- All matches include BRAND
and t1.brand = t1_template.brand
-- order by match strength based on price and size
order by case when t1.price = t1_template.price and t1.size1 = t1_template.size1 THEN 1
when t1.size1 = t1_template.size1 THEN 2
else 3 END
-- Only get the best match for each row in T2
FETCH FIRST 1 ROW ONLY) t1;
推荐阅读
- python - 为每个超过最大值的 X 堆叠“点”
- http - adding 1 user with htpasswd in 2 different servers using ssh connection
- ansible - 使用 Ansible 2.9.6 更改 VMware VM 端口组
- javascript - 应用“无返回等待”时,函数是否应该保持异步?
- sql - 如何在SQL中查找两次之间不存在的数据
- html - NavBar Bootstrap 4,如何不重复隐藏手机屏幕中的某些项目?
- android - 一个安卓应用程序在我打开时一直崩溃并显示“已停止工作”的消息
- node.js - 如何使用新的 NodeJS @azure/storage-queue 库连接到开发 Azure 存储(本地)?
- c# - 如何找到写在字符串之前的立即整数值?
- javascript - javascript中有多少种数组类型?