我有一个场景,需要将单行中的数据查询为多列,
表格格式如下,
SAMPLE_TABLE[ID,REF_TAB_A,REF_TAB_B,REF_TAB_C]
我需要一列中的REF_TAB_A、REF_TAB_B和REF_TAB_C值。我所做的是使用UNION ALL如下,
SELECT REF_TAB_A FROM SAMPLE_TABLE
UNION ALL
SELECT REF_TAB_B FROM SAMPLE_TABLE
UNION ALL
SELECT REF_TAB_C FROM SAMPLE_TABLE
有别的办法吗??处理这种情况最有效的方法是什么??
(我使用的是oracle11g)
提前感谢..:D
使用union all
通常会对表进行三次扫描。另一种方法有点混乱,但应该只有一次扫描:
SELECT (case when which = 'A' then REF_TAB_A
when which = 'B' then REF_TAB_B
when which = 'C' then REF_TAB_C
end)
FROM SAMPLE_TABLE cross join
(select 'A' as which from dual union all select 'B' from dual union all select 'C' from dual
) iter
您可以将列别名为:
SELECT REF_TAB_A tab FROM SAMPLE_TABLE
UNION ALL
SELECT REF_TAB_B tab FROM SAMPLE_TABLE
UNION ALL
SELECT REF_TAB_C tab FROM SAMPLE_TABLE
然而,您真正需要做的是规范化您的数据库。每当您的列具有重复名称(如name1、name2、name3、namea、nameb和namec)时,这表明您想要另一个表以及它们之间的1位关系。
CREATE TABLE tabs (
tab_id NUMBER PRIMARY KEY,
sample_table_id NUMBER,
tab VARCHAR2(255),
CONSTRAINT FK_sample_table
FOREIGN KEY(sample_table_id)
REFERENCES SAMPLE_TABLE(sample_table_id)
)
现在,您的查询涉及一个简单的JOIN
。
SELECT
tab
FROM tabs t
JOIN SAMPLE_TABLE st ON t.sample_table_id = st.sample_table_id
WHERE
...
作为Gordon的CROSS JOIN技巧的替代方案,Oracle在SELECT语句中有专门针对这种情况的UNPIVOT子句。
假设此表:
create table tmp_test ( a number, b number, c number );
insert all
into tmp_test values (1,2,3)
into tmp_test values (4,5,6)
select * from dual;
以下查询可以满足您的要求:
select col
from tmp_test
unpivot ( col for i in (a,b,c) );
COL
----------
1
2
3
4
5
6
6 rows selected.
对于这个小例子,一个解释计划表明,使用内置功能会更有效,但要测试这两种选项,看看有什么更好。