Использование Oracle: Могу ли я использовать динамически создаваемую переменную в предложении pivot? - PullRequest
0 голосов
/ 06 июля 2018

Я пытаюсь создать предложение pivot, которое получает параметры из переменной.

У меня есть некоторый тестовый код, например:

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?

Дополнительную информацию об этой настройке (например, мои классы) можно найти в Использование Oracle объединяет три таблицы в одну с PIVOT

1 Ответ

0 голосов
/ 06 июля 2018

Для 12c и выше, вы можете использовать DBMS_SQL.RETURN_RESULT, открыв REFCURSOR для динамического запроса PIVOT.

Я удалил пресловутый синтаксис (+) для 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

enter image description here

...