Преобразовать MAX () KEEP (DENSE_RANK LAST ORDER BY TIMESTAMP) OVER (PARTITION BY) в MySql - PullRequest
2 голосов
/ 23 апреля 2020

Мне нужно конвертировать несколько представлений из Oracle в mySql. Мне удалось преобразовать все, кроме одного:

CREATE or replace VIEW BPMS_POC_ACC_LATEST_ANSWERS_V (PROCESS_ID, QUESTION_ID, QUESTION_GRP, ANSWER, VERSION, TYPE, AUTHOR, TIMESTAMP, PKEY) AS
WITH t2 AS
(
SELECT BPMS_POC_ACC_ANSWER.*, MAX(TIMESTAMP) KEEP (DENSE_RANK LAST ORDER BY TIMESTAMP ) OVER( PARTITION BY QUESTION_GRP, QUESTION_ID , PROCESS_ID ) 
            AS highest
  FROM BPMS_POC_ACC_ANSWER

)
SELECT PROCESS_ID, QUESTION_ID, QUESTION_GRP, ANSWER, VERSION, TYPE, AUTHOR, TIMESTAMP, CONCAT(CONCAT(PROCESS_ID,QUESTION_GRP),QUESTION_ID) AS PKEY
  FROM t2
 WHERE highest = TIMESTAMP 

Я считаю, что проблема в: MAX () KEEP (DENSE_RANK LAST ORDER BY TIMESTAMP) OVER (PARTITION BY)

Кто-нибудь знает простой способ конвертировать его?

Ответы [ 2 ]

1 голос
/ 23 апреля 2020

Что касается этого запроса, вы получите самую последнюю запись для каждого (QUESTION_GRP, QUESTION_ID , PROCESS_ID) кортежа, упорядоченного по TIMESTAMP.

. Вы можете просто использовать коррелированный подзапрос для этого:

CREATE or replace VIEW BPMS_POC_ACC_LATEST_ANSWERS_V 
    (PROCESS_ID, QUESTION_ID, QUESTION_GRP, ANSWER, VERSION, TYPE, AUTHOR, TIMESTAMP, PKEY) AS
SELECT 
    PROCESS_ID, 
    QUESTION_ID, 
    QUESTION_GRP, 
    ANSWER, 
    VERSION, 
    TYPE, 
    AUTHOR, 
    TIMESTAMP, 
    CONCAT(CONCAT(PROCESS_ID,QUESTION_GRP),QUESTION_ID) AS PKEY
FROM BPMS_POC_ACC_ANSWER a
WHERE a.TIMESTAMP = (
    SELECT MAX(a1.TIMESTAMP)
    FROM BPMS_POC_ACC_ANSWER a1
    WHERE 
        a1.QUESTION_GRP = a.QUESTION_GRP
        AND a1.QUESTION_ID = a.QUESTION_ID
        AND a1.PROCESS_ID = a.PROCESS_ID
)

Преимуществом этого подхода является то, что он будет работать на всех версиях MySQL, даже в версиях 5.x, которые не поддерживают оконные функции.

В MySQL 8.0 вы также можете использовать RANK():

CREATE or replace VIEW BPMS_POC_ACC_LATEST_ANSWERS_V 
    (PROCESS_ID, QUESTION_ID, QUESTION_GRP, ANSWER, VERSION, TYPE, AUTHOR, TIMESTAMP, PKEY) AS
SELECT 
    PROCESS_ID, 
    QUESTION_ID, 
    QUESTION_GRP, 
    ANSWER, 
    VERSION, 
    TYPE, 
    AUTHOR, 
    TIMESTAMP, 
    CONCAT(CONCAT(PROCESS_ID,QUESTION_GRP),QUESTION_ID) AS PKEY
FROM (
    SELECT 
        a.*,
        RANK() OVER(PARTITION BY QUESTION_GRP, QUESTION_ID, PROCESS_ID ORDER BY TIMESTAMP DESC) rn
    FROM BPMS_POC_ACC_ANSWER a
) a
WHERE rn = 1
0 голосов
/ 23 апреля 2020

MAX(TIMESTAMP) KEEP (DENSE_RANK LAST ORDER BY TIMESTAMP) не имеет смысла. Он говорит: дайте мне максимальную временную метку, а в случае связей дайте мне их максимум. Вы также можете просто написать MAX(TIMESTAMP).

CONCAT(CONCAT(process_id, question_grp), question_id) тоже странно. Это просто process_id || question_grp || question_id.

Итак, у нас на самом деле есть

WITH t2 AS
(
  SELECT 
    bpms_poc_acc_answer.*,
    MAX(timestamp) OVER (PARTITION BY question_grp, question_id, process_id) AS highest
  FROM bpms_poc_acc_answer
)
SELECT
  process_id, question_id, question_grp, answer, version, type, author, timestamp,
  process_id || question_grp || question_id AS pkey
FROM t2
WHERE highest = timestamp;

Это стандарт SQL, но конкатенация строк может опираться на пустую строку, и нулевое значение одинаково в Oracle. В MySQL вы можете использовать CONCAT_WS для этого:

WITH t2 AS
(
  SELECT 
    bpms_poc_acc_answer.*,
    MAX(timestamp) OVER (PARTITION BY question_grp, question_id, process_id) AS highest
  FROM bpms_poc_acc_answer
)
SELECT
  process_id, question_id, question_grp, answer, version, type, author, timestamp,
  CONCAT_WS('', process_id || question_grp || question_id) AS pkey
FROM t2
WHERE highest = timestamp;

Это должно работать с MySQL 8. Более ранние версии не содержат CTE и оконные функции, и вы должны написать вместо этого:

SELECT
  process_id, question_id, question_grp, answer, version, type, author, timestamp,
  CONCAT_WS('', process_id || question_grp || question_id) AS pkey
FROM bpms_poc_acc_answer
WHERE (question_grp, question_id, process_id, timestamp) IN
(
  SELECT question_grp, question_id, process_id, MAX(timestamp)
  FROM bpms_poc_acc_answer
  GROUP BY question_grp, question_id, process_id
);
...