sql - 以有效的方式从数组元素中获取所有可能的组合

标签 sql postgresql combinations postgresql-9.6

数组中最多有 5 个元素,例如给定:{1,2,3,4,5},我需要从这个数组中获取所有可能的唯一组合,预期结果是:

 {1}
 {1,2}
 {1,2,3}
 {1,2,3,4}
 {1,2,3,4,5}
 {1,2,3,5}
 {1,2,4}
 {1,2,4,5}
 {1,2,5}
 {1,3}
 {1,3,4}
 {1,3,4,5}
 {1,3,5}
 {1,4}
 {1,4,5}
 {1,5}
 {2}
 {2,3}
 {2,3,4}
 {2,3,4,5}
 {2,3,5}
 {2,4}
 {2,4,5}
 {2,5}
 {3}
 {3,4}
 {3,4,5}
 {3,5}
 {4}
 {4,5}
 {5}

我有这个解决方案:

create table temp_all_possible_cards (
    card_ids int[]
);

create or replace function test(cards_in_hands INT[] )
returns void
as $$
begin 
    with all_possible_cards(ids) as(
        select ARRAY_APPEND('{}'::int[], t1.card_ids)||ARRAY_APPEND('{}'::int[], t2.card_ids)||ARRAY_APPEND('{}'::int[], t3.card_ids)||ARRAY_APPEND('{}'::int[], t4.card_ids)||ARRAY_APPEND('{}'::int[], t5.card_ids)
        from (
            select unnest(cards_in_hands) as card_ids
        ) t1
        cross join (
            select unnest(cards_in_hands) as card_ids
        ) t2
        cross join (
            select unnest(cards_in_hands) as card_ids
        ) t3
        cross join (
            select unnest(cards_in_hands) as card_ids
        ) t4
        cross join (
            select unnest(cards_in_hands) as card_ids
        ) t5
    )
    INSERT INTO temp_all_possible_cards
    SELECT DISTINCT uniq( sort(ids) ) from all_possible_cards;  
end;
$$ language plpgsql

这行得通,但有一个大问题,有时我需要运行这个函数 5000 次

do $$
begin
    for i in 1..5000 loop
        perform test('{1,2,3,4,5}');
    end loop;
end;
$$ language plpgsql

循环的执行时间为 55-60 秒。

问题:如何高效地从数组中获取所有可能的唯一组合?如何优化此解决方案,以便即使调用 5000 次也比 60 秒快得多?

最佳答案

;WITH NOS AS (SELECT 1 aval 
             UNION ALL
             SELECT aval + 1 FROM NOS WHERE aval < 2 * 2 * 2 * 2 * 2 - 1
             )
    SELECT LEFT(IQ.x, LEN(IQ.x) - 1) + '}' FROM (
            SELECT RTRIM('{' 
                                + CASE WHEN aval & 1 != 0 THEN '1, ' ELSE '' END        
                                + CASE WHEN aval & 2 != 0 THEN '2, ' ELSE '' END        
                                + CASE WHEN aval & 4 != 0 THEN '3, ' ELSE '' END        
                                + CASE WHEN aval & 8 != 0 THEN '4, ' ELSE '' END        
                                + CASE WHEN aval & 16 != 0 THEN '5, ' ELSE '' END) AS X     
                        FROM NOS) IQ

显示基准

create table #test (x nvarchar(50))

declare @i int = 0; 

    declare @s datetime2 = sysutcdatetime();

    while @i < 5000
    begin

    ;WITH NOS AS (SELECT 1 aval 
                 UNION ALL
                 SELECT aval + 1 FROM NOS WHERE aval < 2 * 2 * 2 * 2 * 2 - 1
                 )
        insert #test SELECT LEFT(IQ.x, LEN(IQ.x) - 1) + '}' FROM (
                SELECT RTRIM('{' 
                                    + CASE WHEN aval & 1 != 0 THEN '1, ' ELSE '' END        
                                    + CASE WHEN aval & 2 != 0 THEN '2, ' ELSE '' END        
                                    + CASE WHEN aval & 4 != 0 THEN '3, ' ELSE '' END        
                                    + CASE WHEN aval & 8 != 0 THEN '4, ' ELSE '' END        
                                    + CASE WHEN aval & 16 != 0 THEN '5, ' ELSE '' END) AS X     
                            FROM NOS) IQ


        set @i = @i + 1;

        end 

        DECLARe @usTiming BIGINT = datediff(MICROSECOND, @s ,sysutcdatetime())

        select CAST(@usTiming as nvarchar(19)) + 'us = ' + CAST(CAST(@usTiming/1000000.000000000000 as dec(10,3)) as nvarchar(20)) + ' seconds';

        drop table #test

我有 2.5 秒

关于sql - 以有效的方式从数组元素中获取所有可能的组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51495180/

相关文章:

python - 通过python的Postgresql ssl连接

php - 用php消除select中的重复项

sql - 如何编写 sql 以在 Postgres 中生成每个客户的累计月销售额

sql - 通过在 where 子句中使用术语来排序

postgresql - 通过事件获得最大的连续连胜

java - 在Java中使用组合键

sql - 如何从sql表中获取每日利润

sql - 使用嵌套 JSON 数组上的过滤器进行选择

c++ - 如何在 C++ 中创建没有硬编码循环的多个 vector 的组合?

Python:如何获取子集的排列列表?