我正在寻找一个按字母顺序对varchar2中的字符进行排序的函数。
我可以使用oracle中内置的东西,还是需要在PL / SQL中创建自定义?
答案 0 :(得分:1)
从http://forums.oracle.com/forums/thread.jspa?messageID=1791550的答案可能会有效,但是没有10g可以测试......
SELECT MIN(permutations)
FROM (SELECT REPLACE (SYS_CONNECT_BY_PATH (n, ','), ',') permutations
FROM (SELECT LEVEL l, SUBSTR ('&col', LEVEL, 1) n
FROM DUAL
CONNECT BY LEVEL <= LENGTH ('&col')) yourtable
CONNECT BY NOCYCLE l != PRIOR l)
WHERE LENGTH (permutations) = LENGTH ('&col')
在示例中col
是在SQL * Plus中定义的,但是如果你将它作为一个函数你可以传入它,或者可以重新编写它以直接取一个表列。我想。
我认为这是一个起点,而不是解决方案;最初的问题是关于字谜,因此它旨在找到所有排列,所以类似但简化的东西可能是可能的。我怀疑对于较大的值,这不能很好地扩展。
答案 1 :(得分:1)
你应该记住,没有“按字母顺序”表示什么的共同协议。这一切都取决于它是哪个国家,谁在查看您的数据以及它所处的背景。
例如在DK中,有大量不同的分类a,aa,b,c,æ,ø,å
查看http://www.siao2.com/2006/04/27/584439.aspx了解详情。对于这些问题,这也恰好是一个很棒的博客。
答案 2 :(得分:1)
所以我最终选择了PL / SQL路由,因为在搜索了一段时间之后我意识到没有可以使用的内置函数。
这是我想出的。它基于关联数组的未来,即Oracle按键排序顺序。
create or replace function sort_chars(p_string in varchar2) return varchar deterministic
as
rv varchar2(4000);
ch varchar2(1);
type vcArray is table of varchar(4000) index by varchar2(1);
sorted vcArray;
key varchar2(1);
begin
for i in 1 .. length(p_string)
loop
ch := substr(p_string, i, 1);
if (sorted.exists(ch))
then
sorted(ch) := sorted(ch) || ch;
else
sorted(ch) := ch;
end if;
end loop;
rv := '';
key := sorted.FIRST;
WHILE key IS NOT NULL LOOP
rv := rv || sorted(key);
key := sorted.NEXT(key);
END LOOP;
return rv;
end;
简单的性能测试:
set timing on;
create table test_sort_fn as
select t1.object_name || rownum as test from user_objects t1, user_objects t2;
select count(distinct test) from test_sort_fn;
select count (*) from (select sort_chars(test) from test_sort_fn);
Table created.
Elapsed: 00:00:01.32
COUNT(DISTINCTTEST)
-------------------
384400
1 row selected.
Elapsed: 00:00:00.57
COUNT(*)
----------
384400
1 row selected.
Elapsed: 00:00:00.06
答案 3 :(得分:0)
假设你不介意每行返回1个字符:
select substr(str, r, 1) X from (
select 'CAB' str,
rownum r
from dual connect by level <= 4000
) where r <= length(str) order by X;
X
=
A
B
C
答案 4 :(得分:0)
您可以使用以下查询:
select listagg(letter)
within group (order by UPPER(letter), ASCII(letter) DESC)
from
(
select regexp_substr('gfedcbaGFEDCBA', '.', level) as letter from dual
connect by regexp_substr('gfedcbaGFEDCBA', '.', level) is not null
);
子查询使用 regexp_substr 将字符串拆分为记录(每个字符为单个字符),外部查询在对它们进行排序后,使用 listagg 将记录合并为一个字符串。
在这里你应该小心,因为按字母顺序排序取决于你的数据库配置,如Cine指出的那样。
在上面的例子中,字母按升序排序&#34;字母顺序排列&#34;并且通过ascii代码降序,在我的例子中,结果是&#34; aAbBcCdDeEfFgG&#34;。 您的案例结果可能会有所不同。
您也可以使用 nlssort 对字母进行排序 - 它可以让您更好地控制排序顺序,因为您可以独立于数据库配置。
select listagg(letter)
within group (order by nlssort(letter, 'nls_sort=german')
from
(
select regexp_substr('gfedcbaGFEDCBA', '.', level) as letter from dual
connect by regexp_substr('gfedcbaGFEDCBA', '.', level) is not null
);
上面的查询也会给你&#34; aAbBcCdDeEfFgG&#34;但如果你改变了&#34;德国&#34;西班牙语&#34;你会得到&#34; AaBbCcDdEeFfGg&#34;代替。
答案 5 :(得分:0)
对于使用Oracle 10g的人,import optuna
def objective(trial: optuna.Trial):
# Sample parameters.
x = trial.suggest_int('x', 0, 10)
y = trial.suggest_categorical('y', [-10, -5, 0, 5, 10])
# Check duplication and skip if it's detected.
for t in trial.study.trials:
if t.state != optuna.structs.TrialState.COMPLETE:
continue
if t.params == trial.params:
return t.value # Return the previous value without re-evaluating it.
# # Note that if duplicate parameter sets are suggested too frequently,
# # you can use the pruning mechanism of Optuna to mitigate the problem.
# # By raising `TrialPruned` instead of just returning the previous value,
# # the sampler is more likely to avoid sampling the parameters in the succeeding trials.
#
# raise optuna.structs.TrialPruned('Duplicate parameter set')
# Evaluate parameters.
return x + y
# Start study.
study = optuna.create_study()
unique_trials = 20
while unique_trials > len(set(str(t.params) for t in study.trials)):
study.optimize(objective, n_trials=1)
不起作用。可接受的答案确实有效,但是它会生成输入字符串的所有可能排列,从而导致糟糕的性能-我的Oracle数据库在输入字符串只有10个字符的情况下苦苦挣扎。
这是适用于Oracle 10g的另一种替代方法。类似于Jeffrey Kemp's answer,只是结果不拆分成行:
select listagg within group
select replace(wm_concat(ch), ',', '') from (
select substr('CAB', level, 1) ch from dual
connect by level <= length('CAB')
order by ch
);
-- output: 'ABC'
只需将逗号之间的分隔符将不同行中的记录连接成一个字符串(这就是我们稍后还要进行替换的原因)。
请注意,如果您输入的字符串中包含逗号,则它们将丢失。此外,wm_concat
是一个未记录的功能,according to this answer在Oracle 12c中已被删除。仅当您坚持使用10g且没有更好的选择时才使用它(例如wm_concat
,如果可以使用11g,则可以使用它。)