在oracle中将行拆分为列

时间:2015-12-24 05:46:19

标签: sql oracle pivot

我在表格中有数据,如下所示:

enter image description here

我想分割它的数据,并通过Oracle中的SQL查询使其看起来如下所示(不使用数据透视):

enter image description here

怎么办?没有使用数据透镜,还有其他方法吗?

5 个答案:

答案 0 :(得分:3)

您需要在此处使用数据透视查询来获取所需的输出:

SELECT Name,
       MIN(CASE WHEN ID_Type = 'PAN'      THEN ID_No ELSE NULL END) AS PAN,
       MIN(CASE WHEN ID_Type = 'DL'       THEN ID_No ELSE NULL END) AS DL,
       MIN(CASE WHEN ID_Type = 'Passport' THEN ID_No ELSE NULL END) AS Passport
FROM yourTable
GROUP BY Name

如果您运行的是11g或更高版本,也可以尝试使用Oracle内置的PIVOT()函数。

答案 1 :(得分:2)

由于您提到不使用PIVOT功能,您可以尝试 在组内使用SQL将行移动到一行,使用listagg在单个列中显示多个列值。

在Oracle 11g中,我们可以使用 listagg 内置函数:

select
    deptno,
    listagg (ename, ',') 
    WITHIN GROUP 
    (ORDER BY ename) enames
FROM 
 emp
GROUP BY 
 deptno

哪个应该给你以下结果:

DEPTNO ENAMES                                            
------ --------------------------------------------------
    10 CLARK,KING,MILLER                                 
    20 ADAMS,FORD,JONES,SCOTT,SMITH                
    30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD     

您可以在此处找到此问题的所有解决方案: http://www.dba-oracle.com/t_converting_rows_columns.htm

答案 2 :(得分:1)

对于Oracle 11g及更高版本,您可以使用 PIVOT

对于11g之前的版本,您可以使用 MAX CASE

A common misconception,在性能方面比PIVOTMAX的旧方式更好DECODE。但是,引擎盖 PIVOT MAX + CASE 相同。您可以在12c中将Oracle EXPAND_SQL_TEXT 程序添加到 DBMS_UTILITY 程序包中进行检查。

例如,

SQL> variable c clob
SQL> begin
  2      dbms_utility.expand_sql_text(Q'[with choice_tbl as (
  3                      select 'Jones' person,1 choice_nbr,'Yellow' color from dual union all
  4                      select 'Jones',2,'Green' from dual union all
  5                      select 'Jones',3,'Blue' from dual union all
  6                      select 'Smith',1,'Orange' from dual
  7                     )
  8  select  *
  9    from  choice_tbl
 10    pivot(
 11          max(color)
 12          for choice_nbr in (1 choice_nbr1,2 choice_nbr2,3 choice_nbr3)
 13         )]',:c);
 14  end;
 15  /

PL/SQL procedure successfully completed.

现在让我们看看Oracle内部实际做了什么:

SQL> set long 100000
SQL> print c

C
--------------------------------------------------------------------------------
SELECT  "A1"."PERSON" "PERSON",
        "A1"."CHOICE_NBR1" "CHOICE_NBR1",
        "A1"."CHOICE_NBR2" "CHOICE_NBR2",
        "A1"."CHOICE_NBR3" "CHOICE_NBR3"
  FROM  (
         SELECT  "A2"."PERSON" "PERSON",
                 MAX(CASE  WHEN ("A2"."CHOICE_NBR"=1) THEN "A2"."COLOR" END ) "CHOICE_NBR1",
                 MAX(CASE  WHEN ("A2"."CHOICE_NBR"=2) THEN "A2"."COLOR" END ) "CHOICE_NBR2",
                 MAX(CASE  WHEN ("A2"."CHOICE_NBR"=3) THEN "A2"."COLOR" END ) "CHOICE_NBR3"
          FROM  (
                 (SELECT 'Jones' "PERSON",1 "CHOICE_NBR",'Yellow' "COLOR" FROM "SYS"."DUAL" "A7") UNION ALL
                 (SELECT 'Jones' "'JONES'",2 "2",'Green' "'GREEN'" FROM "SYS"."DUAL" "A6") UNION ALL
                 (SELECT 'Jones' "'JONES'",3 "3",'Blue' "'BLUE'" FROM "SYS"."DUAL" "A5") UNION ALL
                 (SELECT 'Smith' "'SMITH'",1 "1",'Orange' "'ORANGE'" FROM "SYS"."DUAL" "A4")
                ) "A2"
          GROUP BY "A2"."PERSON"
       ) "A1"
SQL>

Oracle在内部将 PIVOT 解释为 MAX + CASE

答案 3 :(得分:1)

您可以通过了解透视查询的功能来创建非透视查询:

select *
from yourTable
pivot
(
  max (id_no)
  for (id_type) in ('PAN' as pan, 'DL' as dl, 'Passport' as passport)
)

透视图所做的是GROUP BY未在PIVOT子句中指定的所有列(实际上只是名称列),以子查询方式选择新列基于FOR子句中指定的每个值的IN子句之前的聚合,并丢弃PIVOT子句中指定的那些列。

当我说"子查询时尚"我引用了一种方法来实现PIVOT获得的结果。实际上,我不知道这是如何在幕后工作的。这个子查询的方式是这样的:

select <aggregation>
from <yourTable>
where 1=1 
  and <FORclauseColumns> = <INclauseValue>
  and <subqueryTableColumns> = <PIVOTgroupedColumns>

现在,您已确定如何在不使用PIVOT子句的情况下创建查询:

select 
  name,
  (select max(id_no) from yourTable where name = t.name and id_type = 'PAN') as pan,
  (select max(id_no) from yourTable where name = t.name and id_type = 'DL') as dl,
  (select max(id_no) from yourTable where name = t.name and id_type = 'Passport') as passport
from yourTable t
group by name

答案 4 :(得分:0)

您可以使用CTE打破数据,然后将它们重新组合在一起以获得您想要的内容:

WITH NAMES AS (SELECT DISTINCT NAME
                 FROM YOURTABLE),
     PAN AS (SELECT NAME, ID_NO AS PAN
               FROM YOURTABLE
               WHERE ID_TYPE = 'PAN'),
     DL AS (SELECT NAME, ID_NO AS DL
              FROM YOURTABLE
              WHERE ID_TYPE = 'DL'),
     PASSPORT AS (SELECT NAME, ID_NO AS "Passport"
                    FROM YOURTABLE
                    WHERE ID_TYPE = 'Passport')
SELECT n.NAME, p.PAN, d.DL, t."Passport"
  FROM NAMES n
  LEFT OUTER JOIN PAN p
    ON p.NAME = n.NAME
  LEFT OUTER JOIN DL d
    ON d.NAME = p.NAME
  LEFT OUTER JOIN PASSPORT t
    ON t.NAME = p.NAME'

YOURTABLE替换为您感兴趣的表格的实际名称。

祝你好运。