我的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
答案 0 :(得分:0)
此比较:
VENC != (SELECT NEW.VENCEDOR FROM PARTIDAS WHERE IDPART = NEW.IDPARTIDAS
和与此类似的其他记录,必须返回一条记录。 您可以手动运行所有这些查询,直到发现该查询返回多个记录为止。
答案 1 :(得分:0)
您的整个触发器代码在某些地方是复杂和错误的方法。
要从select语句分配变量,您需要使用select column_name into variable from ...
不 select into variable ...
无需使用选择语句开始“复制”新记录或旧记录的值。实际上,根本不需要复制这些值。
如果要引用new
或old
记录中的列,则不需要select语句。
您不需要两个update语句来更新两个列,这可以通过一个语句来完成。
您不能将old
记录中的列用作UPDATE语句的目标列,SET OLD.VITORIAS = ...
是无效的,令我惊讶的是它甚至可以编译。我认为您打算写set vitorias = ....
在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;