在Oracle中生成连接字符串的快速方法
当邪恶的编码再次出现时,我们难道不讨厌吗?
前段时间,我需要生成一个字符串,连接一些字段,以便稍后进行更多处理。我认为直接在查询中执行是一个好主意,并使用 SO 的帮助来获取它。它起作用了。有一段时间......
桌子变得很大,现在这个技巧(我知道这是非常低效的)并不完全可行。这就是我正在做的事情:
with my_tabe as
(
select 'user1' as usrid, '1' as prodcode from dual union
select 'user1' as usrid, '2' as prodcode from dual union
select 'user1' as usrid, '3' as prodcode from dual union
select 'user2' as usrid, '2' as prodcode from dual union
select 'user2' as usrid, '3' as prodcode from dual union
select 'user2' as usrid, '4' as prodcode from dual
)
select
usrid,
ltrim(sys_connect_by_path(prodcode, '|'), '|') as prodcode
from
(
select distinct prodcode, usrid,count(1)
over (partition by usrid) as cnt,
row_number() over (partition by usrid order by prodcode) as rn
from my_tabe
)
where
rn = cnt
start with rn = 1
connect by prior rn + 1 = rn
and prior usrid = usrid
这很好地产生了:
USRID PRODCODE
user1 1|2|3
user2 2|3|4
正如您可能已经注意到的,这里的邪恶之处是 where rn = cnt
,如果您删除它,您将看到所有工作(我假设)Oracle确实在做:
USRID PRODCODE
user1 1
user1 1|2
user1 1|2|3
user2 2
user2 2|3
user2 2|3|4
我实际上在很多我没有那么多记录的地方使用了这个。大约50万条记录就足够了。
最近我在一个有大约 15Mi 记录的表中尝试了同样的方法,但是......不好。
问题:有没有一种方法可以在 Oracle 上更有效地完成此操作,或者是时候将其转化为实际代码了? 这不是真正的核心问题,所以我仍然可以负担得起拼凑,只要它很快...... 值得一提的是,我正在使用的“usrid”列有一个索引。
干杯,
Don't we hate when evil coding comes back to haunt?
Some time ago I needed to generate a string concatenating some fields for some more processing later. I thought it would be a good idea to do if straight in the query, and used SO's help to get it. It worked. For a while...
The table got to big and now that trick (which I know is super inefficient) is not exactly viable. This what I'm doing:
with my_tabe as
(
select 'user1' as usrid, '1' as prodcode from dual union
select 'user1' as usrid, '2' as prodcode from dual union
select 'user1' as usrid, '3' as prodcode from dual union
select 'user2' as usrid, '2' as prodcode from dual union
select 'user2' as usrid, '3' as prodcode from dual union
select 'user2' as usrid, '4' as prodcode from dual
)
select
usrid,
ltrim(sys_connect_by_path(prodcode, '|'), '|') as prodcode
from
(
select distinct prodcode, usrid,count(1)
over (partition by usrid) as cnt,
row_number() over (partition by usrid order by prodcode) as rn
from my_tabe
)
where
rn = cnt
start with rn = 1
connect by prior rn + 1 = rn
and prior usrid = usrid
Which nicely yields:
USRID PRODCODE
user1 1|2|3
user2 2|3|4
The evil thing in here, as you might have noticed, is the where rn = cnt
, which if you remove you'll see all the work (I suppose) Oracle is really doing:
USRID PRODCODE
user1 1
user1 1|2
user1 1|2|3
user2 2
user2 2|3
user2 2|3|4
I'm actually using this in many places where I have not so many records. It is quite fine up to about a half million records.
Recently I tried the same in a table with ~15Mi records, and well... no good.
Question: is there a way to do this more efficiently on Oracle or is it time bring it down to the actual code?
This is not actual core issue, so I can still afford kludging, as long as it's fast...
Worth mentioning there's a index for the column "usrid" I'm using.
cheers,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
汤姆·凯特 提供了一种非常方便的方法来做到这一点,它从 Oracle 9i 开始工作,具有自定义聚合函数。它用逗号聚合,但您可以修改管道的函数体。
从 Oracle 11g 开始,您可以执行以下操作:
此网页提供了其他方法包括你列出的那个,它确实效率不高。
Tom Kyte provides a very convenient way to do that, and it works from Oracle 9i, with a custom aggregation function. It aggregates with commas, but you can modify the function body for pipes.
Starting with Oracle 11g, you can do:
This web page provides additional methods including the one that you listed and which is indeed not really efficient.