如何使用美元报价传递 NEW 的价值?

How to pass the value of NEW using dollar quoting?

我无法访问 crosstab() 查询字符串中 NEW 行的值。

CREATE OR REPLACE FUNCTION insert_fx()
  RETURNS TRIGGER AS
$BODY$ 
BEGIN
    INSERT INTO outputtb (serial,date, judge)
    VALUES (NEW.serial, NEW.date, NEW.tjudge) RETURNING serial INTO newserial;

    UPDATE outputtb
    SET (reading1,
         reading2,
         reading3) =
      (SELECT ct."reading1",
              ct."reading2",
              ct."reading3"
       FROM crosstab( $$
               SELECT tb2. serial,tb2. readings,tb2. value
               FROM DATA AS tb2
               INNER JOIN outputtb AS tb1 USING (serial)
               WHERE tb2.serial = $$||NEW.serno||$$
               ORDER BY 1 ASC $$, $$
               VALUES ('reading1'),('reading2'),('reading3')$$ 
               ) ct ("Serial" VARCHAR(50),"Reading1" FLOAT8, "Reading2" FLOAT8, "Reading3" FLOAT8))
    WHERE sn = NEW.serno; 
    RETURN NEW; 
END; 
$BODY$ 
LANGUAGE plpgsql VOLATILE;

CREATE TRIGGER insert_tg
BEFORE INSERT ON details
FOR EACH ROW EXECUTE PROCEDURE insert_fx();

它returns这个错误:

ERROR: syntax error at or near "CC1027HCA0GESKN00CC000FT0000" 
LINE 6: tb2. serial = 043611007853619CC1027HCA0GESKN00CC000FT... 

我认为它不接受字符,它只接受整数。也许引用需要一些修改,我对 pgsql 引用不太熟悉。

我需要帮助来完成我的项目。我卡在这部分了。

错误消息的直接原因是您连接了字符串 NEW.serno 而没有引用它。要安全修复,请使用 format() or quote_literal() or quote_nullable().

...
   UPDATE outputtb
   SET           (reading1,    reading2,    reading3)
     = (SELECT ct.reading1, ct.reading2, ct.reading3
        FROM   crosstab(
           'SELECT serial, t2.readings, t2.value
            FROM   data     t2
            JOIN   outputtb t1 USING (serial)
            WHERE  serial = ' || quote_nullable(NEW.serno) || '
            ORDER  BY 1'
          , $$VALUES ('reading1'),('reading2'),('reading3')$$
            ) ct (serial text, reading1 float8, reading2 float8, reading3 float8))
   WHERE  sn = NEW.serno; 
...

基础知识:

  • Insert text with single quotes in PostgreSQL

顺便说一下,我还修正了您不正确的混合大小写标识符:

  • Are PostgreSQL column names case-sensitive?

但是问题比较多:

  • newserial 尚未声明,也未使用。
  • outputtb 是传递给 crosstab().
  • 的查询中毫无意义的噪音
  • ,你不应该需要一个INSERT 一个UPDATE,而且crosstab()似乎也像矫枉过正。

这真是一团糟。


走出去,我有根据的猜测是你想要这个:

CREATE OR REPLACE FUNCTION insert_fx()
  RETURNS TRIGGER AS
$func$
BEGIN
   INSERT INTO outputtb (serial, date, judge, reading1, reading2, reading3)
   SELECT NEW.serial, NEW.date, NEW.tjudge, ct.*
   FROM  (SELECT 1) dummy
   LEFT   JOIN crosstab (
     'SELECT serial, readings, value
      FROM   data
      WHERE  serial = ' || quote_nullable(NEW.serno) || '
      ORDER  BY 1'
    , $$VALUES ('reading1'),('reading2'),('reading3')$$
      ) ct (serial text, reading1 float8, reading2 float8, reading3 float8) ON true;

   RETURN NEW; 
END
$func$  LANGUAGE plpgsql;

LEFT JOINdummy table 防止在 crosstab() 出现空时丢失 INSERT

可以简化为:

CREATE OR REPLACE FUNCTION insert_fx()
  RETURNS TRIGGER AS
$func$
BEGIN
   INSERT INTO outputtb (serial, date, judge, reading1, reading2, reading3)
   SELECT NEW.serial, NEW.date, NEW.tjudge
          min(value) FILTER (WHERE readings = 'reading1')
          min(value) FILTER (WHERE readings = 'reading2')
          min(value) FILTER (WHERE readings = 'reading3')
   FROM   data
   WHERE  serial = NEW.serno;

   RETURN NEW; 
END
$func$  LANGUAGE plpgsql;

由于我们现在聚合,结果行是有保证的,我们不必担心丢失它。

旁白: "serial" 是 not a reserved word。但它是一种常见的伪数据类型的名称,所以我仍然不会将它用作列名以避免混淆错误情况。