PL/SQL: INSTR(), SUBSTR(), 如何从多选列表中提取值
Posted
技术标签:
【中文标题】PL/SQL: INSTR(), SUBSTR(), 如何从多选列表中提取值【英文标题】:PL/SQL: INSTR(), SUBSTR(), How to extract values from multi-select-list 【发布时间】:2017-03-11 12:52:35 【问题描述】:给出以下情况: 表 order o 和 products p 是通过多选列表连接的。
产品p:
主键 PRODUCT_ID 类似于“101” 商店购买价格如“9.25”下单:
主键 ORDER_ID 类似于“123456” 将所有包含的产品存储在一个名为 prod 的列中,例如“:101:199:250:999:” 将所有包含的单价存储在名为“:10.0:25.0:30.5:125.25:”的列中例如,订单 123456 包含四种产品。 id 101 的产品以10.0$
出售(而购买价格为9.25$
),id 199 的产品以25.0$
出售等等......
所以对我来说最具挑战性的部分是从多选列表中提取所需的值。
如何根据订购的产品提取价格以回答诸如“id = 999 的产品的平均销售价格是多少?”之类的问题
我已经尝试过类似的方法:
SELECT MOD(INSTR(o.products, ':999:'),3) FROM orders o;
返回值的位置。
由于我不是PL/SQL
程序员,我不知道如何继续处理这个问题......
欢迎提出想法。
【问题讨论】:
您首先不应该将多个分隔值存储在单个列中。阅读数据库规范化 是的,我知道这一点......使用带有 order_id 和 product_id 键的第三个表会更有效。尽管如此,解决方案应该基于多选列表......:-/ 这行不通。我确信这方面的聪明人可以提供一些可行的功能代码;但是一旦你尝试扩展系统,就会出现问题。所以真正的答案是修复设计。 请告诉我这是一项学校作业,而不是某个正在生产的系统 @APC 如果它在某处生产,它不会持续很长时间。 【参考方案1】:您可以在更大的查询中使用下面的查询。或者您可以使用它一劳永逸地规范您的数据。或者两者兼而有之。
您要为两个以冒号分隔的具有相同数量的标记等的字符串承担责任(这是首先拥有正常形式的表格的 100 多个原因之一)。
with
orders ( order_id, prod, prices ) as (
select 123456, ':101:99:250:999:', ':10.0:25.0:30.5:125.25:' from dual union all
select 1003 , ':101:999:' , ':9.95:130.40:' from dual
)
select order_id,
to_number(substr(prod, instr(prod, ':', 1, level) + 1,
instr(prod, ':', 1, level + 1) - instr(prod, ':', 1, level) - 1)) as prod_id,
to_number(substr(prices, instr(prices, ':', 1, level) + 1,
instr(prices, ':', 1, level + 1) - instr(prices, ':', 1, level) - 1)) as price
from orders
connect by level <= length(prod) - length(replace(prod, ':')) - 1
and prior order_id = order_id
and prior sys_guid() is not null
;
ORDER_ID PROD_ID PRICE
-------- ------- ------
1003 101 9.95
1003 999 30.4
123456 101 10
123456 99 25
123456 250 30.5
123456 999 125.25
【讨论】:
以上是关于PL/SQL: INSTR(), SUBSTR(), 如何从多选列表中提取值的主要内容,如果未能解决你的问题,请参考以下文章
PL SQL oracle instr function|异常行为
正则表达式 substr,起始位置位于字符串 PL/SQL 的末尾
超过 4000 个字符的 Substr 得到 ORA-06502: PL/SQL: numeric or value error