Устранение ошибок запросов в Vertica [Vertica] [VJDBC] (4160) и [Vertica] [VJDBC] (4680) - PullRequest
0 голосов
/ 23 октября 2019

У меня возникли проблемы с корректной работой моего запроса Vertica. Давайте предположим, что у меня есть отношение, которое определяется следующим образом:

CREATE TABLE KOMM (
   MANDT         VARCHAR(3),
   DOCNUM        VARCHAR(16),
   COUNTER       VARCHAR(3),
   NUM           VARCHAR(6),
   NAM           VARCHAR(30), 
   INNUM         VARCHAR(6),
   KOMMLEVEL     VARCHAR(2),  
   MSG           VARCHAR(1000),
   NUM_UNH       VARCHAR(6)
);

и вставляем несколько примеров значений:

insert into KOMM values ('200','45320824','000','000003','START','000002','02','START OF MESSAGE');
insert into KOMM values ('200','45320824','000','000004','INTERMED','000003','03','EXAMPLEEXAMPLEEXAMPLE');
insert into KOMM values ('200','45320824','000','000005','ADV_01','000003','03','TESTADV1');
insert into KOMM values ('200','45320824','000','000011','END','000010','04','01234567');
...
insert into KOMM values ('200','45320824','000','000022','START','000002','02','CONTINUE START OF MESSAGE');
insert into KOMM values ('200','45320824','000','000023','INTERMED','000003','03','SECONDEXAMPLEEXAMPLEEXAMPLE');
insert into KOMM values ('200','45320824','000','000024','ADV_01','000003','03','SECONDTESTADV1');
insert into KOMM values ('200','45320824','000','000030','END','000010','04','01234567');

Теперь я хотел бы запросить отношение с помощью следующего запроса:

UPDATE KOMM E
SET NUM_UNH = (SELECT MAX(X.NUM)
                     FROM KOMM X
                    WHERE X.NAM IN ('START')
                      AND X.MANDT = E.MANDT
                      AND X.DOCNUM = E.DOCNUM
                      AND X.NUM <= E.NUM
                  )
FROM KOMM X
WHERE E.MANDT = X.MANDT AND E.DOCNUM = X.DOCNUM
;

Однако в этом запросе выдается следующая ошибка:

Ошибка выполнения: [Vertica] VJDBC ОШИБКА: выражение подзапроса, не связанное с равенством, не поддерживается

Я думаю, это потому, что Vertica не допускает сравнения <=,> =, <и> внутри подзапросов? См. Документацию Vertica для ограничений подзапроса.

Поэтому я попытался решить ее с помощью МЕЖДУ :

UPDATE KOMM E
SET NUM_UNH = (SELECT max(X.NUM)
                     FROM KOMM X
                    WHERE X.NAM IN ('START')
                      AND X.MANDT = E.MANDT
                      AND X.DOCNUM = E.DOCNUM
                      AND X.NUM BETWEEN '000000' AND (E.NUM)
                  )
from KOMM X
where E.MANDT = X.MANDT and E.DOCNUM = X.DOCNUM
;

Это приводит к той же ошибке:

Ошибка выполнения: [Vertica] VJDBC ОШИБКА: выражение подзапроса, не связанное с неравенством, не поддерживается

Поэтому я попытался проигнорировать условие и столкнулся с другой проблемой после выполненияследующий запрос:

UPDATE KOMM E
   SET NUM_UNH = (SELECT max(X.NUM)
                         FROM KOMM X
                        WHERE X.NAM IN ('START')
                          AND X.MANDT = E.MANDT
                          AND X.DOCNUM = E.DOCNUM
                      )
from KOMM X
where E.MANDT = X.MANDT and E.DOCNUM = X.DOCNUM
;

В результате возникла следующая ошибка:

Ошибка выполнения: [Vertica] VJDBC ОШИБКА: самостоятельные объединения в выражениях UPDATE недопустимы [Vertica] [VJDBC] Подробности: целевое отношение "da592a51-45ee-4d3e-9983-e8a3e56fd852_2fd1ec98-bb71-4ad0-8d33-d751e209dcdd". KOMM также появляется в списке FROM

Я нашел эту "работу"выдайте, заменив "из KOMM X" на "из (выберите * из KOMM) X" . Этот запрос выполняется, но не так, как хотелось бы (как вы можете себе представить). Цель состоит в том, чтобы обновить таблицу со значением NUM, пока в таблице не появится следующее более высокое значение NUM, так что таблица может быть окончательно агрегирована только путем отображения строк, в которых NAM имеет значение «START»:

SELECT
M.MANDT, M.DOCNUM, M.NUM_UNH,
max(case
  when M.NAM = 'START' then substring(cast(M.MSG as varchar(99)),15,6)
end) as UNH_SEG,
max(case
    when M.NAM = 'END'
    then substring(cast(M.MSG as varchar(36)),4,33)
end) as PMSG
from KOMM M
group by M.MANDT, M.DOCNUM, NUM_UNH
;

Первая строка результата Вторая строка результата

К сожалению, я не могу найти решение этих проблем, поэтому я надеюсь, что выребята могут помочь мне. Заранее благодарю за помощь и предложения!

С наилучшими пожеланиями, MoDo

Ответы [ 2 ]

0 голосов
/ 24 октября 2019

Я понимаю ваш вопрос, поэтому вам нужен отчет из двух строк в вашем примере, содержащий значение NUM для строки с nam для 'START' и последние 5 символов сообщения следующей строки с nam из «КОНЕЦ». Единственное, что я не мог понять, это то, где в мире вы получили ввод для строки «GE» в вашем новом столбце unh_seg ...

Я бы попытался использовать совершенно другой подход. Он включает в себя группирование, функции OLAP и вложенные запросы.

Я вижу, что у нас есть две группы строк (если мы упорядочим по num), которые имеют последовательность из одного 'START', одного или несколькихчто-то еще, и один 'END' в столбце nam.

Нам нужен дополнительный столбец, чтобы различать две группы. А у Vertica есть совершенно уникальная функция OLAP CONDITIONAL_TRUE_EVENT(), которая здесь очень удобна. Он начинается с 0 и увеличивается на 1 каждый раз, когда логическое выражение в скобках имеет значение true.

Давайте создадим и заполним вашу таблицу типами данных так, как я бы их использовал:

DROP TABLE IF EXISTS komm ;
-- note that I use numbers, especially integers, wherever I can
CREATE TABLE KOMM (
   mandt         INT,
   docnum        INT,
   counter       INT,
   num           INT,
   nam           VARCHAR(30), 
   innum         INT,
   kommlevel     INT,  
   msg           VARCHAR(64)
);

INSERT INTO KOMM
          SELECT 200,45320824,000,000003,'START',    2,2,'START OF MESSAGE'
UNION ALL SELECT 200,45320824,000,000004,'INTERMED', 3,3,'EXAMPLEEXAMPLEEXAMPLE'
UNION ALL SELECT 200,45320824,000,000005,'ADV_01',   3,3,'TESTADV1'
UNION ALL SELECT 200,45320824,000,000011,'END',      0,4,'01234567'
UNION ALL SELECT 200,45320824,000,000022,'START',    2,2,'CONTINUE START OF MESSAGE'
UNION ALL SELECT 200,45320824,000,000023,'INTERMED', 3,3,'SECONDEXAMPLEEXAMPLEEXAMPLE'
UNION ALL SELECT 200,45320824,000,000024,'ADV_01',   3,3,'SECONDTESTADV1'
UNION ALL SELECT 200,45320824,000,000030,'END',     10,4,'01234567'
;
COMMIT;
SELECT * FROM komm;
-- out  mandt |  docnum  | counter | num |   nam    | innum | kommlevel |             msg             
-- out -------+----------+---------+-----+----------+-------+-----------+-----------------------------
-- out    200 | 45320824 |       0 |   3 | START    |     2 |         2 | START OF MESSAGE
-- out    200 | 45320824 |       0 |   4 | INTERMED |     3 |         3 | EXAMPLEEXAMPLEEXAMPLE
-- out    200 | 45320824 |       0 |   5 | ADV_01   |     3 |         3 | TESTADV1
-- out    200 | 45320824 |       0 |  11 | END      |     0 |         4 | 01234567
-- out    200 | 45320824 |       0 |  22 | START    |     2 |         2 | CONTINUE START OF MESSAGE
-- out    200 | 45320824 |       0 |  23 | INTERMED |     3 |         3 | SECONDEXAMPLEEXAMPLEEXAMPLE
-- out    200 | 45320824 |       0 |  24 | ADV_01   |     3 |         3 | SECONDTESTADV1
-- out    200 | 45320824 |       0 |  30 | END      |    10 |         4 | 01234567
-- out (8 rows)

С таблицей, построенной так, я запускаю запрос ниже.

WITH
-- need a column to distinguish the two groups between 'START' and 'END'
-- hence a nested query to generate a "session id" ..
w_sess_id AS (
  SELECT
    CONDITIONAL_TRUE_EVENT(nam='START') OVER (
     ORDER BY num
    ) AS sess_id
  , *
  FROM komm
) 
SELECT
  mandt
, docnum
, MAX(CASE nam WHEN 'START' THEN num END) AS num_unh
    --^-- this returns NULL if nam is not 'START'
, 'GE' AS unh_seg -- I have no idea where you could get this from, so I put in a constant
, MAX(CASE nam WHEN 'END'   THEN  RIGHT(msg,5) END) AS msg
FROM w_sess_id
GROUP BY 
  sess_id
, mandt
, docnum;
-- out  mandt |  docnum  | num_unh | unh_seg |  msg  
-- out -------+----------+---------+---------+-------
-- out    200 | 45320824 |       3 | GE      | 34567
-- out    200 | 45320824 |      22 | GE      | 34567
-- out (2 rows)
-- out 
-- out Time: First fetch (2 rows): 46.210 ms. All rows formatted: 46.301 ms
0 голосов
/ 23 октября 2019

Делает ли это то, что вы хотите?

UPDATE KOMM E
SET NUM_UNH = (SELECT MAX(CASE WHEN X.NUM <= E.NUM THEN X.NUM END)
               FROM KOMM X
               WHERE X.NAM IN ('START') AND
                     X.MANDT = E.MANDT AND
                     X.DOCNUM = E.DOCNUM
              );

Я не знаком с ограничениями на обновления Vertica, но это более простой запрос, и он может работать.

РЕДАКТИРОВАТЬ:

Это работает?

UPDATE KOMM E
    SET NUM_UNH = X.NUM
FROM (SELECT MANDT, DOCNUM, MAX(CASE WHEN X.NUM <= E.NUM THEN X.NUM END) as NUM
      FROM KOMM X
      WHERE X.NAM IN ('START')  
      GROUP BY MANDT, DOCNUM                     
     ) X
WHERE X.MANDT= E.MANDT AND X.DOCNUM = E.DOCNUM;
...