SQL(Postgres)中的教科书MergeSort实现

时间:2019-03-18 14:43:34

标签: sql postgresql algorithm sorting

我正在尝试在SQL中实现Mergesort的教科书版本,并尝试不使用plpgsql。我只想使用SQL。我使用Postgres作为数据库系统。我已经尝试了一切,但是很遗憾,我无法再继续了。

到目前为止,我的Mergesort函数看起来像这样:

CREATE OR REPLACE FUNCTION mergesort(A double precision[], p integer, r integer)
RETURNS double precision[] AS $$
    SELECT 
        CASE WHEN p < r THEN mergesort(A,p,floor((p+r)/2)::integer) 
             WHEN p < r THEN mergesort(A,floor((p+r)/2)::integer+1,r)
             WHEN p < r THEN merge(A,p,floor((p+r)/2)::integer,r)
             ELSE A
    END;
$$ LANGUAGE SQL;

我正在尝试获得类似的可执行文件并正常工作(我知道在我的代码示例中CASE不会执行所有必需的三个调用,但我还没有找到解决方案,很遗憾,我没有找到解决方案。不知道如何在递归调用中将Mergesort的结果分配给变量A)。

有人知道我如何解决这个问题吗?

仅供参考: 合并功能已在plpgsql中实现并可执行。 (也许我下一步尝试用SQL重写它)。

CREATE FUNCTION merge(A double precision[], p integer, q integer, r integer) 
RETURNS double precision[] AS $$
DECLARE
 n1 integer := q-p+1;
 n2 integer := r-q;
 L double precision[]; 
 Ri double precision[];
 g integer;
 h integer; 
BEGIN
 L = ARRAY[n1+1]; 
 Ri = ARRAY[n2+1];
 FOR i in 1..(n1+1) LOOP
    L[i] = A[p+i-1];
 END LOOP;
 FOR j in 1..n2+1 LOOP
    Ri[j] = A[q+j];
 END LOOP;
 L[n1+1] = 'Infinity';
 Ri[n2+1] = 'Infinity';
 g = 1;
 h = 1;
 FOR k in p..r LOOP
    IF L[g] <= Ri[h] THEN
        A[k] = L[g];
        g = g + 1;
    ELSE
        A[k] = Ri[h];
        h = h + 1; 
    END IF;
 END LOOP;
 RETURN A;
END;
$$ LANGUAGE plpgsql;

1 个答案:

答案 0 :(得分:0)

我现在已经发现了,想与您分享解决方案。 我现在选择了一种函数算法,该算法比命令式算法更容易在SQL中实现。

合并排序:

CREATE OR REPLACE FUNCTION mergesort(A double precision[]) 
RETURNS double precision[] AS $$
    SELECT 
        CASE WHEN 1 < array_length(A,1) 
              THEN merge(mergesort(A[1:floor((1+array_length(A,1))/2)::integer]),
                         mergesort(A[floor((1+array_length(A,1))/2)::integer+1:array_length(A,1)]),
                         1,
                         1,
                         ARRAY[]::double precision[])
             ELSE A
        END;
$$ LANGUAGE SQL;

合并:

CREATE OR REPLACE FUNCTION merge(A1 double precision[],A2 double precision[], i integer, j integer,acc double precision[]) 
RETURNS double precision[] AS $$
    SELECT 
        CASE WHEN (i > array_length(A1,1) and j > array_length(A2,1)) THEN acc
             WHEN i > array_length(A1,1) THEN merge(A1,A2,i,j+1,array_append(acc,A2[j]))
             WHEN j > array_length(A2,1) THEN merge(A1,A2,i+1,j,array_append(acc,A1[i]))
             WHEN A1[i] <  A2[j] THEN merge(A1,A2,i+1,j,array_append(acc, A1[i]))
             WHEN A1[i] >= A2[j] THEN merge(A1,A2,i,j+1,array_append(acc, A2[j]))                
        END;
$$ LANGUAGE SQL;