【问题标题】:Solving Query-Errors in Vertica [Vertica][VJDBC](4160) and [Vertica][VJDBC](4680)解决 Vertica [Vertica][VJDBC](4160) 和 [Vertica][VJDBC](4680) 中的查询错误
【发布时间】:2019-10-23 20:32:57
【问题描述】:

我在让 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 不允许在子查询中进行 =、 比较? See Vertica Documentation for Subquery Restrictions

所以我尝试使用 BETWEEN 来解决它:

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]Detail: 目标关系 “da592a51-45ee-4d3e-9983-e8a3e56fd852_2fd1ec98-bb71-4ad0-8d33-d751e209dcdd”.KOMM 也出现在 FROM 列表中

我找到了解决此问题的“解决方法”,将 "from KOMM X" 替换为 "from (select * from 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
;

First row of result Second row of result

不幸的是,我无法找到解决这些问题的方法,这就是为什么我希望你们能帮助我。 提前感谢您的帮助和建议!

最好的问候, 摩多

【问题讨论】:

  • 您能否指定NUM_UNH 应包含您指定的8 行数据样本的内容?
  • 我想我现在理解得更好了。我是否正确地认为您想要在示例中包含两行的报告,其中包含 NUM 行的 NAM 的值和 NAM 下一行的消息的最后 5 个字符“结束”?

标签: sql subquery vertica


【解决方案1】:

我了解您的问题,因此您希望在示例中报告两行,其中包含“START”的 nam 行的 NUM 值和带有 @987654322 的下一行消息的最后 5 个字符@'END'。我唯一想不通的是,您在新专栏unh_seg 中获得了字符串“GE”的输入...

我会尝试使用完全不同的方法。它涉及 GROUP-ing、OLAP 函数和嵌套查询。

我看到我们有两组行(如果我们按num 排序),在nam 列中有一个“START”、一个或多个其他内容和一个“END”的序列。

我们需要一个额外的列来区分这两个组。 Vertica 有一个非常独特的 OLAP 函数CONDITIONAL_TRUE_EVENT(),在这里非常方便。它从 0 开始,每次括号中的布尔表达式为真时递增 1。

让我们创建并使用我将使用的数据类型填充您的表:

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

【讨论】:

  • 哇,太酷了!首先,我担心不同的表定义会成为问题(因为我必须遵守上面的定义)。但是即使对于我的表,您的查询也可以正常工作。非常感谢@marcothesane!
【解决方案2】:

这是你想要的吗?

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;

【讨论】:

  • 感谢您的快速回答。不幸的是,查询导致另一个错误:执行错误:[Vertica][VJDBC](2783) 错误:不支持 select/gby/oby 中的相关子查询列
  • 执行第二个查询后,系统提示我需要在 X.MANDT 和 X.DOCNUM 上使用 GROUP BY。但是,当我现在执行查询 UPDATE KOMM E SET NUM_UNH = X.NUM FROM (SELECT MANDT, DOCNUM, MAX(CASE WHEN X.NUM
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-03
  • 1970-01-01
  • 2016-01-19
  • 1970-01-01
  • 2017-10-04
  • 2014-03-11
  • 1970-01-01
相关资源
最近更新 更多