1

これは、ここに投稿されたより複雑な質問の簡略化された質問です。

再帰SQLステートメント(PostgreSQL 9.1.4)

簡単な質問

上三角行列が3つの列(RowIndex、ColumnIndex、MatrixValue)に格納されている場合:

   ColumnIndex       
    1   2   3   4   5
1   2   2   3   3   4
2   4   4   5   6   X
3   3   2   2   X   X
4   2   1   X   X   X
5   1   X   X   X   X

X値は、次のアルゴリズムを使用して計算されます。

M[i,j] = (M[i-1,j]+M[i,j-1])/2
(i= rows, j = columns, M=matrix)

Example:
M[3,4] = (M[2,4]+M[3,3])/2
M[3,5] = (m[2,5]+M[3,4])/2

必要な完全な結果は次のとおりです。

   ColumnIndex       
    1   2   3    4      5
1   2   2   3    3      4
2   4   4   5    6      5
3   3   2   2    4      4.5
4   2   1   1.5  2.75   3.625
5   1   1   1.25 2.00   2.8125

サンプルデータ:

create table matrix_data (
    RowIndex integer,
    ColumnIndex integer,
    MatrixValue numeric);

    insert into matrix_data values (1,1,2);
    insert into matrix_data values (1,2,2);
    insert into matrix_data values (1,3,3);
    insert into matrix_data values (1,4,3);
    insert into matrix_data values (1,5,4);
    insert into matrix_data values (2,1,4);
    insert into matrix_data values (2,2,4);
    insert into matrix_data values (2,3,5);
    insert into matrix_data values (2,4,6);
    insert into matrix_data values (3,1,3);
    insert into matrix_data values (3,2,2);
    insert into matrix_data values (3,3,2);
    insert into matrix_data values (4,1,2);
    insert into matrix_data values (4,2,1);
    insert into matrix_data values (5,1,1);

これはできますか?

4

4 に答える 4

2

テスト設定:

CREATE TEMP TABLE matrix (
    rowindex integer,
    columnindex integer,
    matrixvalue numeric);

INSERT INTO matrix VALUES
 (1,1,2),(1,2,2),(1,3,3),(1,4,3),(1,5,4)
,(2,1,4),(2,2,4),(2,3,5),(2,4,6)
,(3,1,3),(3,2,2),(3,3,2)
,(4,1,2),(4,2,1)
,(5,1,1);

DO:を使用してLOOPでINSERTを実行します。

DO $$
BEGIN

FOR i IN 2 .. 5 LOOP
   FOR j IN 7-i .. 5 LOOP
      INSERT INTO matrix
      VALUES (i,j, (
         SELECT sum(matrixvalue)/2
         FROM   matrix
         WHERE  (rowindex, columnindex) IN ((i-1, j),(i, j-1))
         ));
   END LOOP;
END LOOP;

END;
$$

結果を参照してください:

SELECT * FROM matrix order BY 1,2;
于 2012-07-19T17:27:43.570 に答える
1

これは、単一のSQL selectステートメントで実行できますが、再帰が必要ないためです。ソリューションの概要を説明します。実際にSQLコードが必要な場合は、お知らせください。

まず、合計に寄与する唯一のアイテムが対角線に沿っていることに注意してください。ここで、(1、5)の値「4」の寄与に従うと、(2,5)に4/2、(3,5)に4/4、(4,5)に4/8が寄与します。 )。(a + b)/ 2は(a / 2 + b / 2)であるため、毎回、寄与は半分に削減されます。

これを拡張すると、パスカルの三角形に似たパターンが見え始めます。実際、下三角行列の任意の点(値がある場所の下)について、値に寄与する対角要素を見つけることができます。垂直線を上に伸ばして対角線を打ち、水平線を伸ばして対角線を打ちます。それらは対角線の列からの貢献者です。

彼らはいくら貢献しますか?そのために、パスカルの三角形に行くことができます。値がある下の最初の対角線の場合、寄与は(1,1)/2です。2番目の対角線の場合、(1,2,1)/4。3番目の場合、(1,3,3,1)/8。。。等々。

幸い、式(組み合わせ論からの「選択」関数)を使用して、各値の寄与を計算できます。2の力は簡単です。また、特定のセルが対角線からどれだけ離れているかを判断するのはそれほど難しくありません。

これらすべてを組み合わせて、単一のPostgresSQLステートメントにすることができます。ただし、@Erwinのソリューションも機能します。彼の解決策があなたのニーズを満たさない場合にのみ、ステートメントのデバッグに力を入れたいと思います。

于 2012-07-19T18:43:37.590 に答える
1

...そしてここに複数のCTE(tm)が埋め込まれた再帰CTEがあります:

DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;

CREATE TABLE matrix_data (
    yyy integer,
    xxx integer,
    val numeric);

    insert into matrix_data (yyy,xxx,val) values
      (1,1,2) , (1,2,2) , (1,3,3) , (1,4,3) , (1,5,4)
    , (2,1,4) , (2,2,4) , (2,3,5) , (2,4,6)
    , (3,1,3) , (3,2,2) , (3,3,2)
    , (4,1,2) , (4,2,1)
    , (5,1,1)
        ;

WITH RECURSIVE rr AS (
        WITH xx AS (
                SELECT MIN(xxx) AS x0
                , MAX(xxx) AS x1
                FROM matrix_data
                )
        , mimax AS (
                SELECT generate_series(xx.x0,xx.x1) AS xxx
                FROM xx
                )
        , yy AS (
                SELECT MIN(yyy) AS y0
                , MAX(yyy) AS y1
                FROM matrix_data
                )
        , mimay AS (
                SELECT generate_series(yy.y0,yy.y1) AS yyy
                FROM yy
                )
        , cart AS (
                SELECT * FROM mimax mm
                JOIN mimay my ON (1=1)
                )
        , empty AS (
                SELECT * FROM cart ca
                WHERE NOT EXISTS (
                        SELECT *
                        FROM matrix_data nx
                        WHERE nx.xxx = ca.xxx
                        AND nx.yyy = ca.yyy
                        )
                )
        , hot AS (
                SELECT * FROM empty emp
                WHERE EXISTS (
                        SELECT *
                        FROM matrix_data ex
                        WHERE ex.xxx = emp.xxx -1
                        AND ex.yyy = emp.yyy
                        )
                AND EXISTS (
                        SELECT *
                        FROM matrix_data ex
                        WHERE ex.xxx = emp.xxx
                        AND ex.yyy = emp.yyy -1
                        )
                    )
        -- UPDATE from here:
        SELECT h.xxx,h.yyy, md.val / 2 AS val
        FROM hot h
        JOIN matrix_data md ON
                (md.yyy = h.yyy AND md.xxx = h.xxx-1)
                OR (md.yyy = h.yyy-1 AND md.xxx = h.xxx)
        UNION ALL
        SELECT e.xxx,e.yyy, r.val / 2 AS val
        FROM empty e
        JOIN rr r ON ( e.xxx = r.xxx+1 AND e.yyy = r.yyy)
                OR ( e.xxx = r.xxx AND e.yyy = r.yyy+1 )
        )
INSERT INTO matrix_data(yyy,xxx,val)
SELECT DISTINCT yyy,xxx
        ,SUM(val)
FROM rr
GROUP BY yyy,xxx
        ;

SELECT * FROM matrix_data
        ;

新しい結果:

NOTICE:  drop cascades to table tmp.matrix_data
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 15
INSERT 0 10
 yyy | xxx |          val           
-----+-----+------------------------
   1 |   1 |                      2
   1 |   2 |                      2
   1 |   3 |                      3
   1 |   4 |                      3
   1 |   5 |                      4
   2 |   1 |                      4
   2 |   2 |                      4
   2 |   3 |                      5
   2 |   4 |                      6
   3 |   1 |                      3
   3 |   2 |                      2
   3 |   3 |                      2
   4 |   1 |                      2
   4 |   2 |                      1
   5 |   1 |                      1
   2 |   5 |     5.0000000000000000
   5 |   5 | 2.81250000000000000000
   4 |   3 | 1.50000000000000000000
   3 |   5 | 4.50000000000000000000
   5 |   2 | 1.00000000000000000000
   3 |   4 | 4.00000000000000000000
   5 |   3 | 1.25000000000000000000
   4 |   5 | 3.62500000000000000000
   4 |   4 | 2.75000000000000000000
   5 |   4 | 2.00000000000000000000
(25 rows)
于 2012-07-19T18:45:03.130 に答える
0
 while (select max(ColumnIndex+RowIndex) from matrix_data)<10
 begin
      insert matrix_data
      select c1.RowIndex, c1.ColumnIndex+1, (c1.MatrixValue+c2.MatrixValue)/2 
      from matrix_data c1
           inner join
           matrix_data c2 
           on c1.ColumnIndex+1=c2.ColumnIndex and c1.RowIndex-1 = c2.RowIndex   
      where c1.RowIndex+c1.ColumnIndex=(select max(RowIndex+ColumnIndex) from matrix_data) 
      and c1.ColumnIndex<5
 end
于 2012-07-19T19:11:41.677 に答える