以矩阵形式转换sql表

时间:2017-03-26 19:47:39

标签: sql oracle

我在oracle中有一个表,我想以矩阵形式转换它

表1:我有两种具有相应权重的用户

  User_name  M_User    Total
    user 1    user 2     7
    user 1    user 3     19
    user 1    user 7     5
    user 3    user 2     1
    user 2    user 7     1 

最终结果应该是这样的:用户1 - >用户2的权重为7,因此该值出现在该单元格中,依此类推

             user 1 user 2 user 3  user 7
user 1        0        7     19       5
user 3        0        1      0       0
user 2        0        0      0       1
user 7        0        0      0       0

经过一番研究后,我找到了Pivot功能并使用了它。

 SELECT *
FROM   (SELECT USER_NAME, M_USER, TOTAL
        FROM   TEST)
PIVOT  (MAX(TOTAL)  FOR (M_USER) IN ('user 2' AS User2, 'user 3' AS User3 , 'user7' AS User7))

第一个问题是它显示用户7'的空值。并且它不应该,第二个问题是我的文件中有很多数据(107k记录,包括重复数据),对于有限的数据,如上所述我可以在'user 2' AS User2, 'user 3' AS User3 , 'user7' AS User7命令之后使用IN这么大的数据怎么写这行?当然,我不能在IN

之后写出100k的记录

更新: 在sql developer中运行命令为"运行脚本"

Error starting at line 2 in command:
EXEC :rc := getusers;
Error report:
ORA-06550: line 1, column 13:
PLS-00905: object SYSTEM.GETUSERS is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.
*Action:
rc

1 个答案:

答案 0 :(得分:2)

这可能对您有所帮助。我使用CASE WHEN THEN END块来实现PIVOT

SELECT USERS.USER_NAME
  , MAX(COALESCE(TEST.USER1, 0)) USER1
  , MAX(COALESCE(TEST.USER2, 0)) USER2
  , MAX(COALESCE(TEST.USER3, 0)) USER3
  , MAX(COALESCE(TEST.USER7, 0)) USER7
FROM (
  SELECT DISTINCT USER_NAME 
  FROM (
      SELECT USER_NAME FROM TEST
      UNION ALL
      SELECT M_USER FROM TEST
    )
  ) USERS
    LEFT OUTER JOIN (
      SELECT
          USER_NAME
          , M_USER
          , CASE WHEN M_USER = 'user 1' THEN TOTAL ELSE 0 END AS USER1
          , CASE WHEN M_USER = 'user 2' THEN TOTAL ELSE 0 END AS USER2
          , CASE WHEN M_USER = 'user 3' THEN TOTAL ELSE 0 END AS USER3
          , CASE WHEN M_USER = 'user 7' THEN TOTAL ELSE 0 END AS USER7
      FROM TEST
    ) TEST ON USERS.USER_NAME = TEST.USER_NAME
GROUP BY USERS.USER_NAME
ORDER BY USERS.USER_NAME

<强>更新

我找不到在单个查询中写这个的方法。经过一些分析后,我找到了this

CREATE OR REPLACE FUNCTION GETUSERS RETURN SYS_REFCURSOR AS
  QUERY VARCHAR2(32767);
  RC SYS_REFCURSOR;
BEGIN

  QUERY := 'SELECT USERS.USER_NAME ';

  FOR TMP IN (SELECT DISTINCT UPPER(REPLACE(USER_NAME, ' ', '')) USER_NAME FROM (SELECT USER_NAME FROM TEST UNION ALL SELECT M_USER FROM TEST) ORDER BY USER_NAME)
  LOOP
    QUERY := QUERY || '  , MAX(COALESCE(TEST.' || TMP.USER_NAME || ' , 0)) ' || TMP.USER_NAME;
  END LOOP;

  QUERY := QUERY || ' FROM ( ';
  QUERY := QUERY || '  SELECT DISTINCT USER_NAME ';
  QUERY := QUERY || '  FROM ( ';
  QUERY := QUERY || '      SELECT USER_NAME FROM TEST ';
  QUERY := QUERY || '      UNION ALL ';
  QUERY := QUERY || '      SELECT M_USER FROM TEST ';
  QUERY := QUERY || '    ) ';
  QUERY := QUERY || '  ) USERS ';
  QUERY := QUERY || '    LEFT OUTER JOIN ( ';

  QUERY := QUERY || ' SELECT USER_NAME';
  FOR TMP IN (SELECT DISTINCT USER_NAME, REPLACE(USER_NAME, ' ', '') USER_COL_NM FROM (SELECT USER_NAME FROM TEST UNION ALL SELECT M_USER FROM TEST))
  LOOP
    QUERY := QUERY || ', CASE WHEN M_USER = ''' || TMP.USER_NAME
      || ''' THEN TOTAL ELSE 0 END AS ' || TMP.USER_COL_NM ;
  END LOOP;
  QUERY := QUERY || ' FROM TEST';

  QUERY := QUERY || '    ) TEST ON USERS.USER_NAME = TEST.USER_NAME ';
  QUERY := QUERY || 'GROUP BY USERS.USER_NAME ';
  QUERY := QUERY || 'ORDER BY USERS.USER_NAME';

  OPEN RC FOR QUERY;

  RETURN RC;
END;
/

创建的函数,动态创建SQL并返回SYS_REFCURSOR。这可以在SQL * Plus或SQL Developer中运行(使用&#39;作为脚本运行&#39;),

VAR RC REFCURSOR;
EXEC :RC := GETUSERS;
PRINT RC