错误:由子查询返回的多行用作表达式pgadmin

时间:2019-06-10 20:59:25

标签: sql postgresql

我的sql代码有一个小问题,更具体地说,是由触发器执行的函数中的问题。

我尝试在if中仅使用1个select(每个查询的if都不同),但是错误仍然相同。我完成的其他功能使用相同类型的查询,不会返回此问题。

CREATE OR REPLACE FUNCTION TIME_UPDATE() RETURNS TRIGGER AS $$
DECLARE IDPART INT;
DECLARE VENC INT;
DECLARE PERD INT;
BEGIN

SELECT INTO IDPART OLD.IDPARTIDAS FROM PARTIDAS WHERE OLD.IDPARTIDAS = NEW.IDPARTIDAS;
SELECT INTO VENC OLD.VENCEDOR FROM PARTIDAS WHERE OLD.IDPARTIDAS = NEW.IDPARTIDAS;
SELECT INTO PERD OLD.PERDEDOR FROM PARTIDAS WHERE OLD.IDPARTIDAS = NEW.IDPARTIDAS;

IF((VENC != (SELECT NEW.VENCEDOR FROM PARTIDAS WHERE IDPART = NEW.IDPARTIDAS))
AND (VENC = (SELECT NEW.PERDEDOR FROM PARTIDAS WHERE IDPART = NEW.IDPARTIDAS)))
THEN
    UPDATE TIME SET OLD.VITORIAS = COALESCE(VITORIAS, 0) - 1, PONTUACAO = COALESCE(PONTUACAO, 0) - 5
    WHERE IDTIME = VENC;
    UPDATE TIME SET DERROTAS = COALESCE(DERROTAS, 0) + 1, PONTUACAO = COALESCE(PONTUACAO, 0) - 2
    WHERE IDTIME = VENC; 
END IF;

IF((PERD != (SELECT NEW.PERDEDOR FROM PARTIDAS WHERE IDPART = NEW.IDPARTIDAS))
AND (PERD = (SELECT NEW.VENCEDOR FROM PARTIDAS WHERE IDPART = NEW.IDPARTIDAS)))
THEN
    UPDATE TIME SET OLD.VITORIAS = COALESCE(VITORIAS, 0) + 1, PONTUACAO = COALESCE(PONTUACAO, 0) + 5
    WHERE IDTIME = PERD;
    UPDATE TIME SET DERROTAS = COALESCE(DERROTAS, 0) - 1, PONTUACAO = COALESCE(PONTUACAO, 0) + 2
    WHERE IDTIME = PERD;
END IF;

    UPDATE TIME SET OLD.VITORIAS = COALESCE(VITORIAS, 0) - 1, PONTUACAO = COALESCE(PONTUACAO, 0) - 5
    WHERE IDTIME = VENC;
    UPDATE TIME SET OLD.VITORIAS = COALESCE(DERROTAS, 0) - 1, PONTUACAO = COALESCE(PONTUACAO, 0) + 2
    WHERE IDTIME = PERD;
RETURN NEW;

END;
$$ LANGUAGE PLPGSQL;

CREATE TRIGGER ATUALIZAR_PARTIDA AFTER UPDATE ON PARTIDAS FOR EACH ROW EXECUTE PROCEDURE TIME_UPDATE();

错误:

  

错误:子查询返回的多于一行用作表达式---------------上下文:SQL语句“ SELECT((VENC!=(SELECT NEW.VENCEDOR FROM PARTIDAS   IDPART = NEW.IDPARTIDAS))和                (VENC =(从PARTIDAS中选择​​NEW.PERDEDOR,IDPART = NEW.IDPARTIDAS)))----------------------   PL / pgSQL函数time_update()第11行位于IF --------------------------------------- --------------------   SQL状态:21000

2 个答案:

答案 0 :(得分:0)

此比较:

VENC != (SELECT NEW.VENCEDOR FROM PARTIDAS WHERE IDPART = NEW.IDPARTIDAS

和与此类似的其他记录,必须返回一条记录。 您可以手动运行所有这些查询,直到发现该查询返回多个记录为止。

答案 1 :(得分:0)

您的整个触发器代码在某些地方是复杂和错误的方法。

  1. 要从select语句分配变量,您需要使用select column_name into variable from ... select into variable ...

  2. 无需使用选择语句开始“复制”新记录或旧记录的值。实际上,根本不需要复制这些值。

  3. 如果要引用newold记录中的列,则不需要select语句。

  4. 您不需要两个update语句来更新两个列,这可以通过一个语句来完成。

  5. 您不能将old记录中的列用作UPDATE语句的目标列,SET OLD.VITORIAS = ...是无效的,令我惊讶的是它甚至可以编译。我认为您打算写set vitorias = ....

  6. 在IF语句中对vitorias列的更新被两个IF块之后的无条件更新覆盖。并且在最后一次UPDATE的情况下,其值也完全不同。

删除所有错误或不必要的代码,我想您正在寻找的是

CREATE OR REPLACE FUNCTION TIME_UPDATE() 
RETURNS TRIGGER 
AS 
$$
DECLARE 
  VENC INT;
  PERD INT;
BEGIN
    -- this is useless. All references to "venc" or "perd" can 
    -- directly be replaced with a reference to the old record.
    venc := old.vencedor;
    perd := old.perdedor;

    IF (new.vencedor <> old.vencedor)
    THEN
        UPDATE time 
            SET vitorias = coalesce(vitorias, 0) - 1, pontuacao = coalesce(pontuacao, 0) - 5,
                derrotas = coalesce(derrotas, 0) + 1, pontuacao = coalesce(pontuacao, 0) - 2
        WHERE idtime = venc; 
    END IF;

    IF (new.perdedor <> old.perdedor) 
    THEN
        UPDATE time 
            SET vitorias = coalesce(vitorias, 0) + 1, pontuacao = coalesce(pontuacao, 0) + 5,
                derrotas = coalesce(derrotas, 0) - 1, pontuacao = coalesce(pontuacao, 0) + 2
        WHERE idtime = perd;
    END IF;

    -- this overwrites the change done in the first IF block with the same value
    UPDATE TIME 
       SET vitorias = coalesce(vitorias, 0) - 1, pontuacao = coalesce(pontuacao, 0) - 5
    WHERE IDTIME = venc;

    -- this overwrites the change done in the second IF block with a different(!) value
    UPDATE TIME 
        SET vitorias = coalesce(derrotas, 0) - 1, pontuacao = coalesce(pontuacao, 0) + 2
    WHERE idtime = perd;

    RETURN NEW;
END;
$$ LANGUAGE PLPGSQL;