2011-02-07 3 views
0

유지 관리중인 프로그램에서 고객이 방대한 (~ 500 행) SQL 문을 받았습니다. 다른 대기업에 데이터를 전송하기 위해 고정 길이 레코드가 포함 된 플랫 파일을 생성하는 데 사용됩니다. 대용량의 플랫 파일이므로 관계형이 아니며 표준 표준 형식의 데이터가 무너집니다. 따라서 여러 코드가 연관 될 수있는 레코드가있는 경우 (이 경우 최대 19 개),이 모든 레코드는 단일 파일이지만 별도의 필드는 플랫 파일에 기록됩니다.여러 레코드로 단일 레코드로 다중 레코드 접기

참고 :이 예제는 단순화되었습니다.

데이터는 세 개의 테이블로, 다음과 같습니다

RECORDS 
record_id firstname lastname  
--------------------------------  
123   Bob   Schmidt 
324   George  Washington 
325   Ronald  Reagan 
290   George  Clooney 


CODE_TABLE 
code_id  code_cd  code_txt 
-------------------------------- 
5   3   President 
2   4   Actor  
3   7   Plumber 


CODES_FOR_RECORDS 
record_id code_cd 
------------------- 
123   7  
325   3 
290   4 
324   3 
325   4 
123   4 

이 같은 레코드를 생성 할 필요가 :

firstname lastname code1  code2  code3 
Bob   Schmidt  Actor  Plumber  NULL 
George  Washington President NULL  NULL 
Ronald  Reagon  Actor  President NULL 
George  Clooney  Actor  NULL  NULL 

우리는 다음과 같습니다에게 주어진 현재 쿼리의 일부를, 하지만 5 코드 대신 19 코드 열이 있습니다 :

select 
    x.record_id, 
    max(case when x.rankk = 1 then code_txt end) as CodeColumn1, 
    max(case when x.rankk = 2 then code_txt end) as CodeColumn2, 
    max(case when x.rankk = 3 then code_txt end) as CodeColumn3, 
    max(case when x.rankk = 4 then code_txt end) as CodeColumn4, 
    max(case when x.rankk = 5 then code_txt end) as CodeColumn5, 
from 
    (
     select 
      r.record_id, 
      ct.code_txt as ctag , 
      dense_rank() over (partition by r.record_id order by cfr.code_id) as rankk 
     from    
      records as r 
      codes_for_records as cfr, 
      code_table as ct 
     where 
      r.record_id = cfr.record_id 
      and ct.code_cd = cfr.code_cd 
      and cfr.code_cd is not null 
      and ct.code_txt not like '%V%' 
    ) as x 
where 
    x.record_id is not null 
group by 
    x.record_id 

I trimm 단순화를 위해 일들을 다룬다. 그러나 실제 문장은 내부 질의와 조인을 포함하고 더 많은 조건들이 있지만 아이디어는 그것을 가져야한다. 내 머리가 더 나은 방법이 있어야한다고 말하고 있지만 SQL 전문가는 아닙니다. 도움이된다면 DB2 v8을 사용하고 있습니다. 그리고 코드는 별도의 열에 있어야하므로 단일 문자열로 병합하지 않아도됩니다. 이보다 깨끗한 해결책이 있습니까?

업데이트 : 난 그냥 원래 쿼리를 refacorting 결국

, 그것은 창문 추악한 MAX() 비즈니스를 사용하지만 전체 쿼리 인해 다른 부분을 재 작업에 더 많은 읽을 수 있습니다. 가능한 솔루션

+0

데이터를 수동으로 변환하는 코드를 작성할 때 절차가 거의 1000 줄 미만입니다. 이 코드는 매우 간단하고 직관적입니다. – HLGEM

+0

어쩌면 SQL에 익숙하지 않을 수도 있습니다. 왜냐하면 저에게 그것은 다소 복잡하게 보입니다. 그리고 그 중 일부는 논리적 인 덩어리로 분리 될 때 1,000 줄입니다. SQL의 500 라인은 스파게티가 IMHO와 다른 것처럼 보입니다. – troutinator

답변

0

찾고있는 내용이 pivoting 인 것 같습니다.

WITH joined_table(firstname, lastname, code_txt, rankk) AS 
(
SELECT 
    r.firstname, 
    r.lastname, 
    ct.code_txt, 
    dense_rank() over (partition by r.record_id order by cfr.code_id) as rankk 
FROM 
    records r 
INNER JOIN 
    codes_for_records cfr 
    ON r.record_id = cfr.record_id 
INNER JOIN 
    codes_table ct 
    ON ct.code_cd = cfr.code_cd 
), 

decoded_table(firstname, lastname, 
    CodeColumn1, CodeColumn2, CodeColumn3, CodeColumn4, CodeColumn5) AS 
(
    SELECT 
    firstname, 
    lastname, 
    DECODE(rankk, 1, code_txt), 
    DECODE(rankk, 2, code_txt), 
    DECODE(rankk, 3, code_txt), 
    DECODE(rankk, 4, code_txt), 
    DECODE(rankk, 5, code_txt) 
    FROM 
    joined_table jt 
) 

SELECT 
    firstname, 
    lastname, 
    MAX(CodeColumn1), 
    MAX(CodeColumn2), 
    MAX(CodeColumn3), 
    MAX(CodeColumn4), 
    MAX(CodeColumn5) 
FROM 
    decoded_table dt 
GROUP BY 
    firstname, 
    lastname; 

이전에 본 적이 없으니 유의하십시오. 나는 참조 용으로 linked document에 의존하고있다.

중복 된 이름을 설명하기 위해 record_id를 포함해야 할 수도 있습니다.

편집 : GROUP BY를 추가했습니다.

+0

흥미 롭습니다. 나는 이것을 줄 것이다. – troutinator

+0

나는 여전히이 모든'MAX()'사업이 추악하다고 생각한다. – troutinator

0

하나는 재귀 쿼리의 사용 :

with recursive_view (record_id, rankk, final) as 
(
    select 
    record_id, 
    rankk, 
    cast (ctag as varchar (100)) 
    from inner_query t1 

    union all 

    select 
    t1.record_id, 
    t1.rankk, 
    /* all formatting here */ 
    cast (t2.final || ',' || t1.ctag as varchar (100)) 
    from 
    inner_query t1, 
    recursive_view t2 
    where 
    t2.rankk < t1.rankk 
    and t1.record_id = t2.record_id 
    and locate(t1.ctag, t2.final) = 0 
) 
select record_id, final from recursive_view; 

는 작동을 보장하지만 도움이 될 것입니다 희망 할 수 없습니다. 또 다른 방법은 맞춤 집계 함수를 사용하는 것입니다.

+0

제안 해 주셔서 감사합니다. 그러나 각 코드는 그 위에 그대로 있어야합니다. 하나의 거대한 문자열로 결합 될 수 없습니다. – troutinator

+0

열 묶음처럼 패딩하여 서식을 지정할 수 있습니다. 그렇지 않으면 피벗 및 동적 SQL없이 최대 (대문자) 중복 구문을 사용해야합니다. –

관련 문제