2012-04-11 31 views
5

如何使功能,将采取字符串或数组并返回一些长度的所有组合的Postgres?PostgreSQL的组合,而无需重复

例如你有ABC,你想用2个字符获得的组合,结果建议立即进行删除是:

AB AC BC

预先感谢您的帮助。

+0

你为什么会做,在一个DBMS的启发?你不能在应用程序级别上做到这一点吗? – 2012-04-11 18:11:17

+0

我可以在一个数独解算器;-) – wildplasser 2012-04-11 18:42:25

+0

使用我会在多个编程语言使用的,只是一个数据库PostgreSQL的,所以我想,这将是只是有这个一个地方最简单的方法。 这不必被连接串,我只是给sugestion应该如何工作。 – ffox003 2012-04-12 05:03:16

回答

9
set search_path='tmp'; 

WITH ztab AS (
SELECT idx as idx 
, substring ('WTF!' FROM idx FOR 1) as str 
FROM generate_series(1, char_length('WTF!')) idx 
) 
SELECT t1.str, t2.str 
FROM ztab t1 
JOIN ztab t2 ON t2.idx > t1.idx 
     ; 

结果:

str | str 
-----+----- 
W | T 
W | F 
W | ! 
T | F 
T | ! 
F | ! 
(6 rows) 

可惜我不能找到一种方法,以避免双重字符串常量。 (但是整个事情可以打包成一个函数)如果没有重复的字符(或者你想压制它们),你可以在str而不是idx上进行反连接。

UPDATE(提示从ypercube)看来,OP希望要连接字符串。这样吧::

WITH ztab AS (
SELECT idx as idx 
, substring ('WTF!' FROM idx FOR 1) as str 
FROM generate_series(1, char_length('WTF!')) idx 
) 
SELECT t1.str || t2.str AS results 
FROM ztab t1 
JOIN ztab t2 ON t2.idx > t1.idx 
     ; 

结果:

results 
--------- 
WT 
WF 
W! 
TF 
T! 
F! 
(6 rows) 

UPDATE2:(这里来了递归啄...)

WITH RECURSIVE xtab AS (
     WITH no_cte AS (
     SELECT 
     1::int AS len 
     , idx as idx 
     , substring ('WTF!' FROM idx FOR 1) as str 
     FROM generate_series(1, char_length('WTF!')) idx 
     ) 
     SELECT t0.len as len 
       , t0.idx 
       , t0.str 
     FROM no_cte t0 
     UNION SELECT 1+t1.len 
       , tc.idx 
       , t1.str || tc.str AS str 
     FROM xtab t1 
     JOIN no_cte tc ON tc.idx > t1.idx 
     ) 
SELECT * FROM xtab 
ORDER BY len, str 
-- WHERE len=2 
     ; 

结果3:

len | idx | str 
-----+-----+------ 
    1 | 4 | ! 
    1 | 3 | F 
    1 | 2 | T 
    1 | 1 | W 
    2 | 4 | F! 
    2 | 4 | T! 
    2 | 3 | TF 
    2 | 4 | W! 
    2 | 3 | WF 
    2 | 2 | WT 
    3 | 4 | TF! 
    3 | 4 | WF! 
    3 | 4 | WT! 
    3 | 3 | WTF 
    4 | 4 | WTF! 
(15 rows) 
+0

不错的解决方案! – 2012-04-11 18:44:23

+0

Tnx!我不认为generate_series()函数接受文本参数(我甚至没有看到),所以这个丑陋的黑客真的是一个解决方法。 – wildplasser 2012-04-11 18:47:13

+0

什么丑陋的黑客?! (哦,选择应该像'SELECT t1.str || t2.str AS结果'或'SELECT t1.str AS str1,t2.str AS str2') – 2012-04-11 18:51:53

1
with chars as (
    select unnest(regexp_split_to_array('ABC','')) as c 
) 
select c1.c||c2.c 
from chars c1 
    cross join chars c2 

要删除您的置换可以使用下列内容:

with chars as (
    select unnest(regexp_split_to_array('ABC','')) as c 
) 
select c1.c||c2.c 
from chars c1 
    cross join chars c2 
where c1.c < c2.c 
+0

这看起来很多比我更优雅;-(我说:我不喜欢串BTW它抑制排列 – wildplasser 2012-04-11 21:08:40

+0

@wildplasser:?你的意思是把AB和BA相似吗?我编辑了我的答案 – 2012-04-11 22:35:59

+0

这就是我的意思。类似的问题可能是字符串中的重复字符,例如“ABBA”。 (这在OP中没有解决) – wildplasser 2012-04-11 22:40:03

0

如何与多个单词的作品......从@wildplasser从这个源info

WITH RECURSIVE xtab AS (
    WITH no_cte AS (
    SELECT 
    1::int AS len 
    , idx as idx 
    , unnest(ARRAY['MY','POSTGRESQL','VERSION','9.6']) as str 
    FROM generate_series(1, array_length(ARRAY['MY','POSTGRESQL','VERSION','9.6'],1)) idx 
    ) 
    SELECT t0.len as len 
      , t0.idx 
      , t0.str 
    FROM no_cte t0 
    UNION SELECT 1+t1.len 
      , tc.idx 
      , t1.str ||','|| tc.str AS str 
    FROM xtab t1 
    JOIN no_cte tc ON tc.idx > t1.idx 
    ) 
    SELECT distinct 
    array_to_string(ARRAY(SELECT DISTINCT trim(x) FROM unnest(string_to_array(str,',')) x),', ') FROM xtab