oracle 行列转换问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle 行列转换问题相关的知识,希望对你有一定的参考价值。

现在数据库里的数据是这样的。

一厂 指标1 20
二厂 指标1 34
一厂 指标2 33
二厂 指标2 22
我这么能在数据库里把他查出来成这样的。

指标名 一厂 二厂
指标1 20 34
指标2 33 22
求大神指点

方法一:最好理解

select t.指标名
      ,sum(decode(t.工厂,'一厂',t.指标值,0)) 一厂
      ,sum(decode(t.工厂,'二厂',t.指标值,0)) 二厂
   from 数据表 t
   group by t.指标名

方法二:用oracle11g新特性Pivot,也很好理解

select 指标名,"一厂","二厂"
   from 数据表 t
   pivot (sum(t.指标值) for "工厂" in ('一厂' as "一厂",'二厂' as "二厂"))

  

追问

你说的方法很对,但是这里的工厂有几个是不固定的.我就不知道怎么整了?
求继续指教呀....

追答

若工厂不固定,得用存储过程了,在存储过程中以动态SQL实现。给你个例子如下:

declare
   L_sql long;
   L_plants long;
   type CSR_RST is ref cursor;
   L_csr_rst CSR_RST;
begin
select WMSYS.WM_CONCAT(''''||t.工厂||''' as "'||t.工厂||'"') 
      into L_plants
      from (select distinct t.工厂 from 数据表 t order by t.工厂) t;
   L_sql := 
      'select *'||chr(10)
      ||'   from 数据表 t'||chr(10)
      ||'   pivot (sum(t.指标值) for "工厂" in ('||L_plants||'))'
      ;
   open L_csr_rst for L_sql;
   //TODO...
   close L_csr_rst;
end;

参考技术A 你的数据里面,

一厂 二厂 是固定的? 也就是具体有几个厂, 写 SQL 查询之前,已经能明确了。
如果是 已明确的情况,那答案就像 ribone 回答的那个样子了。

还是动态的? 也就是写 SQL 之前, 具体有几个厂, 是不明确的。
如果是不明确的, 估计普通的 SQL 语句写起来有点难度了。 要写存储过程之类的代码了。追问

是动态的.我要怎么写?用动态sql语句么?我是oracle的新手,以前都只是用些简单的语句.多数都在程序里处理了.这次情况有点特殊.求继续执教..感谢.感谢

追答CREATE TABLE work_table(
    fact    varchar(10),
    Flag    varchar(10),
    value   INT
);

INSERT INTO work_table VALUES('一厂',  '指标1',  20);
-- 字数不够了,就只贴一行了。


CREATE OR REPLACE  FUNCTION Get_Work_Data
RETURN SYS_REFCURSOR
IS
  return_cursor SYS_REFCURSOR;
  -- 主 SQL.
  v_MainSql  varchar(2000);
  -- 产生动态列的 SQL.
  v_ColumnSql  varchar(1000);
BEGIN
  -- 拼动态列的 sql
  SELECT
    string_agg('SUM(CASE WHEN fact = ''' || fact || ''' THEN value ELSE 0 END) AS ' || fact )  INTO  v_ColumnSql
  FROM
    (select fact from work_table group by fact) t;
  -- 主sql.
  v_MainSql := 'SELECT Flag, ' || v_ColumnSql || ' FROM work_table GROUP BY Flag';
  OPEN return_cursor FOR v_MainSql;
  RETURN return_cursor;
END;
/


SQL> SELECT Get_Work_Data() FROM dual;

GET_WORK_DATA()
--------------------
CURSOR STATEMENT : 1

CURSOR STATEMENT : 1

FLAG                       二厂       一厂
-------------------- ---------- ----------
指标1                        34         20
指标2                        22         33



那个  string_agg 代码字数有点长, 字数不够了。

追问

大概明白你的意思 了 但是string_agg 这是什么意思呀?

追答

string_agg 就是 相当于 WMSYS.WM_CONCAT 函数的功能。

Oracle明确声明,WMSYS.WM_CONCAT 这个函数是个undocument 的 function,是Workspace Manager组件中的一个内部适用的函数,不建议客户使用,因为根据需要,oracle开发人员会内部更改这个函数,并且不会通知也没有义务通知客户。
变通的办法, 自己写一个函数参考:http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php

本回答被提问者采纳
参考技术B 选择a.form_id,a.form_name,b.att_value标题,c.att_value
从t_form一个,t_att B,t_att

其中a.form_id = b.form_id

和a.form_id = c.form_id

和b.att ='标题'

和c.att ='按键'

该查询需要确保在相应的表t_form t_att每个记录表两条记录,与外界否则相连。追问

可以更具我的数据结构说的更详细些么?谢谢了

参考技术C select t.指标名
,sum(decode(t.工厂,'一厂',t.指标值,0)) 一厂
,sum(decode(t.工厂,'二厂',t.指标值,0)) 二厂
from 数据表 t
group by t.指标名

推荐追问

你说的方法很对,但是这里的工厂有几个是不固定的.我就不知道怎么整了?
求继续指教呀....

参考技术D sum(decode ,,,) + group by

Oracle11g 行列转换函数PIVOT and UNPIVOT

作为Oracle开发工程师,推荐大伙看看

PIVOT and UNPIVOT Operators in Oracle Database 11g Release 1

This article shows how to use the new PIVOT and UNPIVOT operators in 11g, as well as giving a pre-11g solution to the same problems.

Related articles.

PIVOT

The PIVOT operator takes data in separate rows, aggregates it and converts it into columns. To see the PIVOT operator in action we need to create a test table.

CREATE TABLE pivot_test (

  id            NUMBER,

  customer_id   NUMBER,

  product_code  VARCHAR2(5),

  quantity      NUMBER

);

 

INSERT INTO pivot_test VALUES (1, 1, ‘A‘, 10);

INSERT INTO pivot_test VALUES (2, 1, ‘B‘, 20);

INSERT INTO pivot_test VALUES (3, 1, ‘C‘, 30);

INSERT INTO pivot_test VALUES (4, 2, ‘A‘, 40);

INSERT INTO pivot_test VALUES (5, 2, ‘C‘, 50);

INSERT INTO pivot_test VALUES (6, 3, ‘A‘, 60);

INSERT INTO pivot_test VALUES (7, 3, ‘B‘, 70);

INSERT INTO pivot_test VALUES (8, 3, ‘C‘, 80);

INSERT INTO pivot_test VALUES (9, 3, ‘D‘, 90);

INSERT INTO pivot_test VALUES (10, 4, ‘A‘, 100);

COMMIT;

So our test data starts off looking like this.

SELECT * FROM pivot_test;

 

        ID CUSTOMER_ID PRODU   QUANTITY

---------- ----------- ----- ----------

         1           1 A             10

         2           1 B             20

         3           1 C             30

         4           2 A             40

         5           2 C             50

         6           3 A             60

         7           3 B             70

         8           3 C             80

         9           3 D             90

        10           4 A            100

 

10 rows selected.

 

SQL>

In its basic form the PIVOT operator is quite limited. We are forced to list the required values to PIVOT using the IN clause.

SELECT *

FROM   (SELECT product_code, quantity

        FROM   pivot_test)

PIVOT  (SUM(quantity) AS sum_quantity FOR (product_code) IN (‘A‘ AS a, ‘B‘ AS b, ‘C‘ AS c));

 

A_SUM_QUANTITY B_SUM_QUANTITY C_SUM_QUANTITY

-------------- -------------- --------------

           210             90            160

 

1 row selected.

 

SQL>

If we want to break it down by customer, we simply include the CUSTOMER_ID column in the initial select list.

SELECT *

FROM   (SELECT customer_id, product_code, quantity

        FROM   pivot_test)

PIVOT  (SUM(quantity) AS sum_quantity FOR (product_code) IN (‘A‘ AS a, ‘B‘ AS b, ‘C‘ AS c))

ORDER BY customer_id;

 

CUSTOMER_ID A_SUM_QUANTITY B_SUM_QUANTITY C_SUM_QUANTITY

----------- -------------- -------------- --------------

          1             10             20             30

          2             40                            50

          3             60             70             80

          4            100

 

4 rows selected.

 

SQL>

Prior to 11g we could accomplish a similar result using the DECODE function combined with aggregate functions.

SELECT SUM(DECODE(product_code, ‘A‘, quantity, 0)) AS a_sum_quantity,

       SUM(DECODE(product_code, ‘B‘, quantity, 0)) AS b_sum_quantity,

       SUM(DECODE(product_code, ‘C‘, quantity, 0)) AS c_sum_quantity

FROM   pivot_test

ORDER BY customer_id;

 

A_SUM_QUANTITY B_SUM_QUANTITY C_SUM_QUANTITY

-------------- -------------- --------------

           210             90            160

 

1 row selected.

 

SQL>

 

SELECT customer_id,

       SUM(DECODE(product_code, ‘A‘, quantity, 0)) AS a_sum_quantity,

       SUM(DECODE(product_code, ‘B‘, quantity, 0)) AS b_sum_quantity,

       SUM(DECODE(product_code, ‘C‘, quantity, 0)) AS c_sum_quantity

FROM   pivot_test

GROUP BY customer_id

ORDER BY customer_id;

 

CUSTOMER_ID A_SUM_QUANTITY B_SUM_QUANTITY C_SUM_QUANTITY

----------- -------------- -------------- --------------

          1             10             20             30

          2             40              0             50

          3             60             70             80

          4            100              0              0

 

4 rows selected.

 

SQL>

Adding the XML keyword to the PIVOT operator allows us to convert the generated pivot results to XML format. It also makes the PIVOT a little more flexible, allowing us to replace the hard coded IN clause with a subquery, or the ANY wildcard.

SET LONG 10000

 

SELECT *

FROM   (SELECT product_code, quantity

        FROM   pivot_test)

PIVOT XML (SUM(quantity) AS sum_quantity FOR (product_code) IN (SELECT DISTINCT product_code

                                                                FROM   pivot_test

                                                                WHERE  id < 10));

 

product_code_XML

----------------------------------------------------------------------------------------------------

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">210</column></

item><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY">90</column></item><

item><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY">160</column></item><item>

<column name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY">90</column></item></PivotSet>

 

1 row selected.

 

SQL>

 

SELECT *

FROM   (SELECT product_code, quantity

        FROM   pivot_test)

PIVOT XML (SUM(quantity) AS sum_quantity FOR (product_code) IN (ANY));

 

product_code_XML

----------------------------------------------------------------------------------------------------

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">210</column></

item><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY">90</column></item><

item><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY">160</column></item><item>

<column name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY">90</column></item></PivotSet>

 

1 row selected.

 

SQL>

Once again, the results can be broken down by customer, with each customers XML presented as a separate row.

SET LONG 10000

 

SELECT *

FROM   (SELECT customer_id, product_code, quantity

        FROM   pivot_test)

PIVOT XML (SUM(quantity) AS sum_quantity FOR (product_code) IN (SELECT DISTINCT product_code

                                                                FROM   pivot_test));

 

CUSTOMER_ID

-----------

PRODUCT_CODE_XML

----------------------------------------------------------------------------------------------------

          1

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">10</column></i

tem><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY">20</column></item><i

tem><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY">30</column></item><item><c

olumn name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY"></column></item></PivotSet>

 

          2

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">40</column></i

tem><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY"></column></item><ite

 

CUSTOMER_ID

-----------

PRODUCT_CODE_XML

----------------------------------------------------------------------------------------------------

m><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY">50</column></item><item><col

umn name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY"></column></item></PivotSet>

 

          3

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">60</column></i

tem><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY">70</column></item><i

tem><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY">80</column></item><item><c

olumn name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY">90</column></item></PivotSet>

 

 

CUSTOMER_ID

-----------

PRODUCT_CODE_XML

----------------------------------------------------------------------------------------------------

          4

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">100</column></

item><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY"></column></item><it

em><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY"></column></item><item><colu

mn name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY"></column></item></PivotSet>

 

 

4 rows selected.

 

SQL>

UNPIVOT

The UNPIVOT operator converts column-based data into separate rows. To see the UNPIVOT operator in action we need to create a test table.

CREATE TABLE unpivot_test (

  id              NUMBER,

  customer_id     NUMBER,

  product_code_a  NUMBER,

  product_code_b  NUMBER,

  product_code_c  NUMBER,

  product_code_d  NUMBER

);

 

INSERT INTO unpivot_test VALUES (1, 101, 10, 20, 30, NULL);

INSERT INTO unpivot_test VALUES (2, 102, 40, NULL, 50, NULL);

INSERT INTO unpivot_test VALUES (3, 103, 60, 70, 80, 90);

INSERT INTO unpivot_test VALUES (4, 104, 100, NULL, NULL, NULL);

COMMIT;

So our test data starts off looking like this.

SELECT * FROM unpivot_test;

 

        ID CUSTOMER_ID PRODUCT_CODE_A PRODUCT_CODE_B PRODUCT_CODE_C PRODUCT_CODE_D

---------- ----------- -------------- -------------- -------------- --------------

         1         101             10             20             30

         2         102             40                            50

         3         103             60             70             80             90

         4         104            100

 

4 rows selected.

 

SQL>

The UNPIVOT operator converts this column-based data into individual rows.

SELECT *

FROM   unpivot_test

UNPIVOT (quantity FOR product_code IN (product_code_a AS ‘A‘, product_code_b AS ‘B‘, product_code_c AS ‘C‘, product_code_d AS ‘D‘));

 

        ID CUSTOMER_ID P   QUANTITY

---------- ----------- - ----------

         1         101 A         10

         1         101 B         20

         1         101 C         30

         2         102 A         40

         2         102 C         50

         3         103 A         60

         3         103 B         70

         3         103 C         80

         3         103 D         90

         4         104 A        100

 

10 rows selected.

 

SQL>

There are several things to note about the query:

  • The required column names, in this case QUANTITY and PRODUCT_CODE, are define in the UNPIVOT clause. These can be set to any name not currently in the driving table.
  • The columns to be unpivoted must be named in the IN clause.
  • The PRODUCT_CODE value will match the column name it is derived from, unless you alias it to another value.
  • By default the EXCLUDE NULLS clause is used. To override the default behaviour use the INCLUDE NULLS clause.

The following query shows the inclusion of the INCLUDE NULLS clause.

SELECT *

FROM   unpivot_test

UNPIVOT INCLUDE NULLS (quantity FOR product_code IN (product_code_a AS ‘A‘, product_code_b AS ‘B‘, product_code_c AS ‘C‘, product_code_d AS ‘D‘));

 

        ID CUSTOMER_ID P   QUANTITY

---------- ----------- - ----------

         1         101 A         10

         1         101 B         20

         1         101 C         30

         1         101 D

         2         102 A         40

         2         102 B

         2         102 C         50

         2         102 D

         3         103 A         60

         3         103 B         70

         3         103 C         80

 

        ID CUSTOMER_ID P   QUANTITY

---------- ----------- - ----------

         3         103 D         90

         4         104 A        100

         4         104 B

         4         104 C

         4         104 D

 

16 rows selected.

 

SQL>

Prior to 11g, we can get the same result using the DECODE function and a pivot table with the correct number of rows. In the following example we use the CONNECT BY clause in a query from dual to generate the correct number of rows for the unpivot operation.

SELECT id,

       customer_id,

       DECODE(unpivot_row, 1, ‘A‘,

                           2, ‘B‘,

                           3, ‘C‘,

                           4, ‘D‘,

                           ‘N/A‘) AS product_code,

       DECODE(unpivot_row, 1, product_code_a,

                           2, product_code_b,

                           3, product_code_c,

                           4, product_code_d,

                           ‘N/A‘) AS quantity

FROM   unpivot_test,

       (SELECT level AS unpivot_row FROM dual CONNECT BY level <= 4)

ORDER BY 1,2,3;

 

        ID CUSTOMER_ID PRO   QUANTITY

---------- ----------- --- ----------

         1         101 A           10

         1         101 B           20

         1         101 C           30

         1         101 D

         2         102 A           40

         2         102 B

         2         102 C           50

         2         102 D

         3         103 A           60

         3         103 B           70

         3         103 C           80

 

        ID CUSTOMER_ID PRO   QUANTITY

---------- ----------- --- ----------

         3         103 D           90

         4         104 A          100

         4         104 B

         4         104 C

         4         104 D

 

16 rows selected.

 

SQL>

 

以上是关于oracle 行列转换问题的主要内容,如果未能解决你的问题,请参考以下文章

求oracle大神帮忙解决下面这个行列转换问题,谢谢!

oracle中一个表的行列转换

SQL 行列转换问题,请高手指点。

oracle查询结果怎么行列转换

在oracle中将多行列转换为一行列

Oracle 表格行列转换,高手请进