【问题标题】:Create Dynamic Pivot - multiple rows into fields based on 2 common fields创建动态数据透视 - 基于 2 个公共字段的多行字段
【发布时间】:2016-02-29 23:49:12
【问题描述】:

如何将 PONT_LOC 字段转换为每个值的单独字段,从而为每个 SECTION 和 SURVEY_DATE 组合创建一行,行数将始终非常基于 SECTION 和 SURVEY_DATE,有人可以帮忙吗? Oracle11g

SELECT * FROM (SELECT STATE_CODE||SHRP_ID AS SECTION, SURVEY_DATE, POINT_LOC
FROM (SELECT * FROM MON_DIS_JPCC_FAULT ORDER BY STATE_CODE, SHRP_ID, SURVEY_DATE, POINT_LOC)
WHERE STATE_CODE=55
AND SHRP_ID LIKE '0213'
AND CRACK_OR_JOINT='J'
AND SURVEY_DATE='04/27/1998');

+---------+-------------+-----------+
| SECTION | SURVEY_DATE | POINT_LOC |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 3.2       |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 7.9       |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 12.5      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 17.1      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 21.7      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 26.2      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 30.7      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 35.2      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 39.8      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 44.4      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 48.9      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 53.5      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 58        |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 62.8      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 67.1      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 71.7      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 76.5      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 81.2      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 85.6      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 90.2      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 94.7      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 99.4      |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 103.9     |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 108.3     |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 114       |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 117.7     |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 122.1     |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 126.7     |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 131.3     |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 136       |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 140.5     |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 144.9     |
+---------+-------------+-----------+
| 550213  | 04/27/1998  | 149.4     |
+---------+-------------+-----------+

这是一些示例数据:

CREATE TABLE MON_DIS_JPCC_FAULT
(SECTION VARCHAR(255),
SURVEY_DATE VARCHAR(255),
POINT_LOC DECIMAL(3,1));

INSERT INTO MON_DIS_JPCC_FAULT
VALUES ('550213', '04/27/1998', 3.2);

INSERT INTO MON_DIS_JPCC_FAULT
VALUES ('550213', '04/27/1998', 7.9);

INSERT INTO MON_DIS_JPCC_FAULT
VALUES ('550213', '04/27/1998', 12.5);

INSERT INTO MON_DIS_JPCC_FAULT
VALUES ('550213', '04/27/1998', 17.1);

INSERT INTO MON_DIS_JPCC_FAULT
VALUES ('550213', '04/27/1998', 21.7);

我不知道我的解释是否正确...这是我正在寻找的输出示例:

+---------+-------------+-------------+-------------+-------------+-------------+-------------+
| SECTION | SURVEY_DATE | POINT_LOC_1 | POINT_LOC_2 | POINT_LOC_3 | POINT_LOC_4 | POINT_LOC_5 |...6, 7, 8, etc...
+---------+-------------+-------------+-------------+-------------+-------------+-------------+
| 550213  | 04/27/1998  | 3.2         | 7.9         | 12.5        | 17.1        | 21.7        |
+---------+-------------+-------------+-------------+-------------+-------------+-------------+

另外,POINT_LOC 的数量总是不同的。

我希望这是有道理的,非常感谢任何帮助!


好的,这就是我目前所拥有的:

SELECT * FROM (
SELECT STATE_CODE||SHRP_ID AS SECTION, SURVEY_DATE, ROW_NUMBER() OVER (PARTITION BY STATE_CODE, SHRP_ID, SURVEY_DATE ORDER BY STATE_CODE, SHRP_ID, SURVEY_DATE, POINT_LOC) AS "JOINT_NO", POINT_LOC
FROM MON_DIS_JPCC_FAULT
WHERE STATE_CODE=55
AND SHRP_ID IN ('0215','0216')
AND CRACK_OR_JOINT='J')

PIVOT (MAX("POINT_LOC") FOR JOINT_NO IN (1,2,3,4,5,34,35,36))

ORDER BY "SECTION", SURVEY_DATE

这是一个示例结果:

+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| SECTION | SURVEY_DATE | 1   | 2   | 3    | 4    | 5    | 34    | 35    | 36 |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550215  | 04/28/1998  | 3.1 | 7.9 | 12.5 | 17.1 | 21.7 | -     | -     | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550215  | 06/08/2000  | 3.1 | 7.9 | 12.5 | 17.1 | 21.7 | -     | -     | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550215  | 04/22/2002  | 3.1 | 7.9 | 12.5 | 17.1 | 21.7 | -     | -     | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550215  | 08/15/2005  | 3.1 | 7.9 | 12.5 | 17.1 | 21.7 | -     | -     | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550215  | 05/12/2010  | 3.1 | 7.9 | 12.5 | 17.1 | 21.7 | -     | -     | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550215  | 07/31/2012  | 3.1 | 7.9 | 12.5 | 17.1 | 21.7 | -     | -     | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550216  | 04/24/1998  | 3   | 7.5 | 12   | 16.6 | 21.1 | 148   | 152.4 | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550216  | 06/06/2000  | 3   | 7.5 | 12   | 16.6 | 21.1 | 148   | 152.4 | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550216  | 04/16/2002  | 3   | 7.5 | 12   | 16.6 | 21.1 | 148   | 152.4 | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550216  | 08/12/2005  | 3   | 7.5 | 12   | 16.6 | 21.1 | 148   | 152.4 | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550216  | 05/05/2010  | 3   | 7.5 | 12   | 16.6 | 21.1 | 152.3 | 152.4 | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+
| 550216  | 07/30/2012  | 3   | 7.5 | 12   | 16.6 | 21.1 | 148   | 152.4 | -  |
+---------+-------------+-----+-----+------+------+------+-------+-------+----+

问题是每个 SECTION 的 POINT_LOC 的数量会有所不同,所以我需要 SQL 的“IN (1,2,3,4,5,34,35,36)”部分来首先确定行数,并且只包括那些。我试图添加一个子查询,但我不断收到“缺少表达式”错误,请帮助:-(

【问题讨论】:

    标签: sql oracle oracle11g


    【解决方案1】:

    如果我的理解是正确的,您希望 POINT_LOC 在每个 SECTION & SURVEY_DATE 的一行中。

    对于这种情况,您可以使用命令 LISTAGG。

    SELECT SECTION
           , SURVEY_DATE
           , LISTAGG(POINT_LOC) WITHIN GROUP (ORDER BY SECTION) POINT_LOC
      FROM ...
    GROUP BY SECTION, SURVEY_DATE;
    

    希望这会有所帮助。


    编辑

    方法:字符串连接

    CREATE OR REPLACE PROCEDURE PVT (
        CUR_PIVOT   OUT SYS_REFCURSOR
    )
    AS
        V_SQL       VARCHAR2(4000);
        V_ROW       VARCHAR2(4000);
    
    BEGIN    
        SELECT LISTAGG(RN, ',') WITHIN GROUP (ORDER BY RN)
          INTO V_ROW
          FROM (SELECT DISTINCT ROW_NUMBER() OVER (PARTITION BY SECTION, SURVEY_DATE ORDER BY SECTION, SURVEY_DATE, POINT_LOC) RN
                  FROM MON_DIS_JPCC_FAULT);
    
        V_SQL := 'SELECT * FROM (' ||
                 'SELECT SECTION, SURVEY_DATE, ROW_NUMBER() OVER (PARTITION BY SECTION, SURVEY_DATE ORDER BY SECTION, SURVEY_DATE, POINT_LOC) AS JOINT_NO, POINT_LOC FROM MON_DIS_JPCC_FAULT' ||
                 ') PIVOT (' ||
                 'MAX(POINT_LOC)' ||
                 'FOR JOINT_NO IN (' || V_ROW || '))';
    
        DBMS_OUTPUT.PUT_LINE(V_SQL);
    
        OPEN CUR_PIVOT FOR V_SQL;
    END PVT;
    

    您可以通过以下方式调用然后获取结果:

    VARIABLE DT REFCURSOR;
    EXEC PVT(:X);
    PRINT X;
    

    但是,字符串长度有限制。

    【讨论】:

    • LISTAGG 只会在一个字段中给出 POINT_LOC,我希望在单独的字段中获取值。请帮忙:-)
    • 不确定要对数据做什么。但要实现您的目标,您可以查看PIVOT。但是,PIVOT 不是动态的,它需要一个特定的数据集列表。对于动态,可以查看PIVOT XML
    • 我尝试使用 PIVOT XML,但无法弄清楚如何获得我所需要的。你能看看我上面的更新并提出建议/例子吗?提前致谢!
    • 对于PIVOT XML,你必须格式化上下文,你可以看到stackoverflow.com/a/19302540/2163646。但是,您仍然需要提前知道您将拥有的列数。另一种方法是使用string concatenation。我的观点,如果你的数据要在 Excel 中进一步处理,LISTAGG 会是一个更快的方法,你可以很容易地通过 TAB 字符来格式化数据。祝你好运..
    猜你喜欢
    • 2018-08-06
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 1970-01-01
    • 2021-12-06
    • 2015-11-30
    • 2020-12-17
    • 1970-01-01
    相关资源
    最近更新 更多