2012-07-19 2 views
1

이 여기에 게시 더 복잡 하나에 대한 간단한 질문은 (RowIndex, ColumnIndex, MatrixValue) :재귀 SQL 문 (PostgreSQL을) 단순화 된 버전

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 alues는 다음과 같은 알고리즘을 사용하여 계산되어야한다 :

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); 

을 할 수 있습니까?

+0

예. (이것은 단지 나중에이 질문을 찾을 수있는 주석입니다.) – podiluska

+0

예상 출력에 오류가있는 것 같습니다 : M [4,4]는 2.75 (4.5 + 1)/2 = 5.5 = 2.75가됩니다. 게시하기 전에 내 솔루션이 올바른지 확인하고 싶습니다. –

+0

@podiluska : 세상에 알리지 않고도 같은 목적으로 "좋아하는"기능을 사용할 수 있습니다. –

답변

2

테스트 설정 : DO와 LOOP에서

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 $$ 
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; 
$$ 

참조 결과 : 이것은 하나의 SQL SELECT 문을 수행 할 수 있습니다

SELECT * FROM matrix order BY 1,2; 
1

, 재귀가 필요하지 않기 때문에. 해결책을 개략적으로 설명하겠습니다. 실제로 SQL 코드를 원하면 알려주십시오.

먼저 합계에 기여하는 항목은 대각선을 따라 있습니다. 이제 (1, 5)에서 값 "4"의 기여도를 따르면 4/2에서 (2,5)까지 및 4/4에서 (3,5)까지 및 4/8에서 (4,5)까지 기여합니다.). (a + b)/2는 (a/2 + b/2)이기 때문에 매번 기여도가 반으로 줄어 듭니다.

이것을 확장하면 파스칼의 삼각형과 비슷한 패턴을 보게됩니다. 사실, 값이있는 아래의 삼각형 행렬의 주어진 점에 대해 값에 기여하는 대각선 요소를 찾을 수 있습니다. 수직선을 대각선에 맞추고 수평선을 대각선에 맞 춥니 다. 그것들은 대각선 행의 기여자입니다.

그들은 얼마를 기여합니까? 음, 파스칼의 삼각형에 갈 수 있습니다. 아래에있는 첫 번째 대각선에 대한 값은 (1,1)/2입니다. 두 번째 대각선은 (1,2,1)/4입니다. 셋째, (1,3,3,1)/8. . . 등등.

다행히도 수식 (조합 규칙의 "선택"기능)을 사용하여 각 값의 기여도를 계산할 수 있습니다. 2의 힘은 쉽습니다. 그리고 주어진 세포가 대각선에서 얼마나 멀리 떨어져 있는지를 결정하는 것은 그렇게 어렵지 않습니다.

이 모든 것을 단일 Postgres SQL 문으로 결합 할 수 있습니다. 그러나 @ Erwin의 솔루션도 사용할 수 있습니다. 나는 그의 해결책이 당신의 필요를 충족시키지 못한다면 그 진술을 디버깅하는 데에만 노력하고 싶다.

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) 
+0

와우, 재귀 CTEism이 터미널 상태 일 때! :) 내 솔루션에서 ~ 15 줄의 코드를 비교하면이 코드는 다소 괴물처럼 보입니다. BTW, 그 결과가 올바르지 않습니다. –

+0

나는 명령형 코드를 싫어한다. 뭔가해야했다. 하지만 여전히 올바르지 않습니다 ... 재귀 CTE를 두 번 참조 할 수 없으며 집계를 사용할 수 없습니다. 나는 붙어있다. 좋은 시도, 그래도, -] BTW : 다른 방법은 먼저 파스칼의 삼각형을 작성한 다음 그것을 업데이트하는 것입니다. 순서가 중요합니다. – wildplasser

+0

알았습니다. 요점은 합계를 외부 쿼리로 끌어들이는 것이 었습니다. 지금 CTE-award를받을 수 있습니까? – wildplasser

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