【问题标题】:How to pass the value of NEW using dollar quoting?如何使用美元报价传递 NEW 的价值?
【发布时间】:2016-07-12 04:51:10
【问题描述】:

我无法访问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();

它返回此错误:

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

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

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

【问题讨论】:

  • 您实际上不需要crosstab()。并且使用插入 更新是矫枉过正的。这可以通过单个 insert 语句来完成(顺便说一句:serial 是保留字,不应用作列名)
  • @a_horse_with_no_name 谢谢伙计。是的,插入和更新有点过头了。我听从了你和 ErwinBrandstetter 的建议。

标签: sql postgresql plpgsql quotes postgresql-9.5


【解决方案1】:

错误消息的直接原因是您连接了字符串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; 
...

基础知识:

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

但还有更多问题:

  • newserial 未被声明也未被使用。
  • outputtb 是传递给crosstab() 的查询中的无意义噪音。
  • @a_horse commented 一样,您不需要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 表可防止在 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;

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

除此之外: “串行”是not a reserved word。但它是一种常见的伪数据类型的名称,所以我仍然不会使用它作为列名,以避免混淆错误情况。

【讨论】:

  • 嗨@ErwinBrandstetter。我认为交叉表只适用于我的,但你的很棒。感谢您的回答,您的简化代码有效。非常感谢。你是最棒的。
  • @tacticz03: crosstab() 非常快,但开销并不能从最大值支付单个结果行。 3 个输入行。
  • 嗨@erwinbrandstetter,我遇到了一些问题。我注意到我的两个表(详细信息和数据表)上的插入是异步执行的。首先在明细表上插入,然后在数据表上插入行。我的问题是您提供的答案无法获取数据表的行。你能帮帮我吗?
  • @tacticz03:显然,您需要先将INSERT 转换为data。或者你需要一种完全不同的方法......
猜你喜欢
  • 1970-01-01
  • 2019-08-30
  • 2018-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-13
相关资源
最近更新 更多