【问题标题】:Using Oracle: Can I use 'dynamically' created variable in the pivot clause?使用 Oracle:我可以在 pivot 子句中使用“动态”创建的变量吗?
【发布时间】:2018-07-10 12:42:25
【问题描述】:

我正在尝试创建从变量中获取参数的数据透视子句。

我有一些测试代码,例如:

SELECT * FROM (
SELECT U.USER_ID, U.USER_NAME, E.EXAM_ID, EU.EXAM_DATE
FROM USERS U, EXAMS E, EXAM_USER EU
WHERE U.USER_ID = EU.USER_ID(+)
AND E.EXAM_ID(+) = EU.EXAM_ID
ORDER BY U.USER_ID
  )
  PIVOT (MAX(EXAM_DATE) FOR EXAM_ID IN ('3' AS "exam 3",'2' AS "exam 2",'1' AS "exam 1"))
  order by 1
;

这很好用。然后我将变量 EXAM_IDS 声明为:

DECLARE
  EXAM_IDS VARCHAR2 (255);
BEGIN
  SELECT LISTAGG('''' || EXAM_ID || ''' AS "' || EXAM_NAME || '"', ',')
  WITHIN GROUP (ORDER BY EXAM_ID DESC) 
  INTO EXAM_IDS
  FROM EXAMS;
END;

我很确定变量 EXAM_IDS 现在有一个字符串,用于枢轴子句(?),但我不知道如何将这两者结合起来:

DECLARE
  EXAM_IDS VARCHAR2 (255);
BEGIN
  SELECT LISTAGG('''' || EXAM_ID || ''' AS "' || EXAM_NAME || '"', ',')
  WITHIN GROUP (ORDER BY EXAM_ID DESC) 
  INTO EXAM_IDS
  FROM EXAMS;
END;

SELECT * FROM (
SELECT U.USER_ID, U.USER_NAME, E.EXAM_ID, EU.EXAM_DATE
FROM USERS U, EXAMS E, EXAM_USER EU
WHERE U.USER_ID = EU.USER_ID(+)
AND E.EXAM_ID(+) = EU.EXAM_ID
ORDER BY U.USER_ID
  )
  PIVOT (MAX(EXAM_DATE) FOR EXAM_ID IN (' || EXAM_IDS || '))
  order by 1
;

这不起作用。有没有办法做到这一点,或者我应该只运行两个单独的 SQL 查询?

可以从Using Oracle combine three tables to one with PIVOT找到有关此设置的更多信息(例如我的课程)

【问题讨论】:

    标签: oracle variables pivot


    【解决方案1】:

    对于 12c 及更高版本,您可以通过为动态 PIVOT 查询打开 REFCURSOR 来使用 DBMS_SQL.RETURN_RESULT

    我已经为 left join 删除了臭名昭著的 (+) 语法,始终使用 ANSI join 语法。

    DECLARE
        exam_ids   VARCHAR2(255);
        x          SYS_REFCURSOR;
    BEGIN
        SELECT
            LISTAGG(''''
                      || exam_id
                      || ''' AS "'
                      || exam_name
                      || '"',',') WITHIN GROUP(
                ORDER BY
                    exam_id DESC
            )
        INTO exam_ids
        FROM
            exam;
    
        OPEN x FOR 'SELECT
            *
                   FROM
            (
                SELECT
                    u.user_id,
                    u.user_name,
                    e.exam_id,
                    eu.exam_date
                FROM
                    users u
                    LEFT JOIN exam_user eu ON u.user_id = eu.user_id
                    LEFT JOIN exam e ON e.exam_id = eu.exam_id
                ORDER BY
                    u.user_id
            )
                PIVOT ( MAX ( exam_date )
                    FOR exam_id
                    IN ( ' || EXAM_IDS || ' )
                )
        ORDER BY
            1';
    
        dbms_sql.return_result(x);
    END;
    /
    

    对于 11g,您可以使用绑定变量和 print 命令(在 sqlplus 和 sql developer/Toad 作为脚本运行时工作 (F5))

    variable x REFCURSOR  -- bind variable declared.
    DECLARE
        ..   -- no need to declare sys_refcursor
    BEGIN
         ..
    
        OPEN :x FOR 'SELECT . --note the change with colon
            *
                   FROM
            (
                SELECT
                ..
    
    END;
    /
    
    
    print x
    

    【讨论】:

    • 谢谢。我有版本 11g 和 sql 开发者。由于某种原因,您的代码仅返回列 user_id 和 user_name。没有数据透视列。
    • @LauriArvilommi :我认为您在编写查询时犯了一个错误。它对我有用,并在您的链接问题stackoverflow.com/a/50362763/7998591 的答案中提供示例数据的输出,请参阅屏幕截图。
    • 再次感谢您。我确实通过查看结果犯了错误。输出窗口太窄,因此枢轴列打印在默认视图之外。我必须一直向右滚动才能看到枢轴列。所以看起来他们确实打印出来了。非常感谢。我将尝试转换我的真实数据库数据以适应这个测试用例,看看我是否能从那里得到正确的结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 2017-10-22
    • 1970-01-01
    相关资源
    最近更新 更多