" IF EXISTS"在PostgreSQL中 - 如果存在则创建更新记录的查询,如果不存在则插入

时间:2016-08-27 16:22:23

标签: sql postgresql

我想进行查询"如果该秒内的记录和此sensor_id存在,请使用提供的新值更新它,否则使用该值创建记录,sensor_id和时间"。

我设法创建了这个查询:

DO
$do$
BEGIN
IF EXISTS (
   SELECT
      1  
   FROM
      public.measurement_pm2_5  
   WHERE
      measurement_time >= TO_TIMESTAMP('06.07.2016 23:28:43', 'DD.MM.YYYY HH24:MI:SS')  
      AND    measurement_time <  TO_TIMESTAMP('06.07.2016 23:28:44', 'DD.MM.YYYY HH24:MI:SS')  
      AND    sensor_id = 2
) THEN UPDATE
   public.measurement_pm2_5   
SET
   measurement_value = 27  
WHERE
   measurement_time >= TO_TIMESTAMP('06.07.2016 23:28:43', 'DD.MM.YYYY HH24:MI:SS')  
   AND    measurement_time <  TO_TIMESTAMP('06.07.2016 23:28:44', 'DD.MM.YYYY HH24:MI:SS')  
   AND    sensor_id = 2;  
   ELSE INSERT 
   INTO
      public.measurement_pm2_5
      (    sensor_id,    measurement_time,    measurement_value  )  
   VALUES
      (    2,    TO_TIMESTAMP('06.07.2016 23:28:43', 'DD.MM.YYYY HH24:MI:SS'),    27  );  
   END IF;
END;
$do$
LANGUAGE plpgsql;

但它没有按预期工作。

Query OK, 0 rows affected (execution time: 62 ms; total time: 62 ms)

虽然这个查询:

SELECT
      1  
   FROM
      public.measurement_pm2_5  
   WHERE
      measurement_time >= TO_TIMESTAMP('06.07.2016 23:28:43', 'DD.MM.YYYY HH24:MI:SS')  
      AND    measurement_time <  TO_TIMESTAMP('06.07.2016 23:28:44', 'DD.MM.YYYY HH24:MI:SS')  
      AND    sensor_id = 2

返回一条记录,第一个查询的UPDATE部分看起来不会被执行。

我正在使用PostgreSQL 9.5。

我做错了什么?

编辑:

measurement_pm2_5表:

CREATE TABLE public.measurement_pm2_5 (
  sensor_id SERIAL,
  measurement_time TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  measurement_value NUMERIC(6,2) NOT NULL,
  CONSTRAINT measurement_pm2_5_sensor_id_fkey FOREIGN KEY (sensor_id)
    REFERENCES public.sensor(id)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION
    NOT DEFERRABLE
) 
WITH (oids = false);

1 个答案:

答案 0 :(得分:1)

从您的SQL代码中可以很容易地看出您在过程编程语言方面经验丰富。 PL / pgSQL需要不同的思维方式。仔细阅读the docs on PL/pgSQL programming并开始思考成功或失败的集合和操作。这根本不是要贬低你;把它看作是一个看过两边的同事的程序员的意见。

在这种情况下,只需尝试UPDATE,如果失败,请改为INSERT

DO $do$
DECLARE
    obs timestamp := to_timestamp('06.07.2016 23:28:43', 'DD.MM.YYYY HH24:MI:SS');
BEGIN
    UPDATE public.measurement_pm2_5   
    SET measurement_value = 27  
    WHERE measurement_time = date_trunc('second', obs)
    AND   sensor_id = 2;

    IF NOT FOUND THEN   
        INSERT INTO public.measurement_pm2_5
               (sensor_id, measurement_time, measurement_value)  
        VALUES (2, obs, 27);  
    END IF;
END;
$do$ LANGUAGE plpgsql;