在我正在维护的程序中,客户给出了大量(~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
我为了简单起见而删减了一些东西,但实际的判断包括一个内部查询和一个连接以及更多条件,但这应该得到了解决方案。我的大脑告诉我必须有更好的方法,但我不是SQL专家。如果有帮助,我们正在使用DB2 v8。并且代码必须在单独的列中,因此没有合并到单个字符串中。有比这更清洁的解决方案吗?
更新
我最终只是重新调整原始查询,它使用丑陋的MAX()业务,但总体来说,由于重新处理其他部分,查询更具可读性。
答案 0 :(得分: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;
不能保证它有效,但希望它会有所帮助。另一种方法是使用自定义聚合函数。
答案 1 :(得分: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。