2011-02-07 93 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 

我们得到这个样子的当前查询的一部分,但以19组的列,而不是5:

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 

我TRIMM为简单起见而编辑了一些事情,但实际的表述包括内部查询和联接等,而条件则应该包含这个概念。我的大脑告诉我必须有更好的方法,但我不是SQL专家。如果有帮助,我们正在使用DB2 v8。代码必须在单独的列中,所以不要将事物合并成单个字符串。有没有比这更清洁的解决方案?

更新:

我最终只是refacorting原始查询,它窗台采用了丑MAX()的企业,但总体而言,查询更可读因返工等部位。

+0

当我编写手动转换数据的代码时,该过程很少少于1000行。这段代码对我来说看起来很简单直接。 – HLGEM 2011-02-07 18:19:31

+0

也许是因为我对SQL并不熟悉,因为对我来说这似乎有些复杂。其中一部分是1000行,当分成逻辑块时不会太差。 IMHO的500行SQL如此相互联系,看起来像意大利面是另一回事。 – troutinator 2011-02-07 20:14:45

回答

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

一个可能的解决方案是使用递归查询:

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 2011-02-07 20:15:30