如何从我的 postgresql 函数中删除重复项?

how to eliminate duplicates from my function in postgresql?

我有这个 vehicle_data table: 创建 TABLE public.vehicle_data

CREATE TABLE vehicle_data
(
  model_name text NOT NULL,
  record_date text NOT NULL,
  inv_quantity integer,
  CONSTRAINT vehicle_data_pkey PRIMARY KEY (model_name, record_date)
)

我的 table 看起来像:

model_name  record_date
  car1         5-2015
  car1         1-2016
  car1         2-2015
  car2         2-2017
  car3         8-2016

当我 运行 我的函数搜索任何汽车时,我想获得按月然后按年排序条目的结果,到目前为止 car1,它应该是这样的:

model_name  record_date
  car1         2-2015
  car1         5-2015
  car1         1-2016

因为我的 record_date 是 TEXT,我认为在我的函数中我可以使用 split_part(record_date,'-',2) 拆分 TEXT 数组以获得年份值,将所有唯一值存储在一个数组中,然后 运行 我的 select 查询每年。

CREATE OR REPLACE FUNCTION getdata(model text)
   RETURNS TABLE(a text, b text) AS
$BODY$
DECLARE  i int;
     list TEXT[]:= ARRAY(SELECT DISTINCT split_part(record_date,'-',2) as xyz
             from vehicle_data 
             order by xyz);
BEGIN
i:=0;
WHILE i < (select cardinality(list)-1) LOOP 
RETURN QUERY
    select model_name, record_date
    from vehicle_data
    where model_name LIKE model AND split_part(record_date,'-',2) LIKE list[i]
    order by length(record_date), record_date ASC;
i:=i+1;
END LOOP;
RETURN;
END;
$BODY$
  LANGUAGE plpgsql;

尽管该函数确实有效,但它会将结果复制 68 次,而不是停止。

解决您的直接问题:要遍历数组,请使用 FOREACH 循环,而不是 WHILE 循环。所以你应该把你的函数改成这样:

CREATE OR REPLACE FUNCTION getdata(p_model text)
   RETURNS TABLE(a text, b text) AS
$BODY$
DECLARE  
  l_year text;
  l_year_list TEXT[]:= ARRAY(SELECT DISTINCT split_part(record_date,'-',2) as xyz
                             from vehicle_data);
BEGIN
  foreach l_year in array l_year_list loop
    RETURN QUERY
      select model_name, record_date
      from vehicle_data
      where model_name LIKE p_model 
        AND split_part(record_date,'-',2) = l_year
      order by length(record_date), record_date ASC;
  END LOOP;
END;
$BODY$
  LANGUAGE plpgsql;

由于不涉及通配符,我将 LIKE 更改为 =。我还对参数和变量应用了不同的命名模式。

但是Postgres在SQL中数组的特性真的很强大,所以上面可以改写为不带循环的单个查询:

CREATE OR REPLACE FUNCTION getdata(p_model text)
   RETURNS TABLE(a text, b text) AS
$BODY$
DECLARE  
  l_year_list TEXT[]:= ARRAY(SELECT DISTINCT split_part(record_date,'-',2) as xyz
                             from vehicle_data);
BEGIN
  RETURN QUERY
    select model_name, record_date
    from vehicle_data
    where model_name LIKE p_model 
      AND split_part(record_date,'-',2) = ANY(l_year_list)
    order by length(record_date), record_date ASC;
END;
$BODY$
  LANGUAGE plpgsql;

这需要 所有 年从 table 和 returns 那些行中的年份在内部 quer 的行中(只有一个在情况下第二个变体)至少等于数组中的一个值,这对所有行都是正确的,因为数组中的值是该列中 all 的现有年份。因此,在处理查询时,数组中的至少一个值将与当前正在查看的行中的值相匹配,这反过来意味着整个条件根本不是必需的。

你可以想象你的函数正在(逻辑上)被这样处理:

  1. 将所有年份放入一个数组中,因此该数组包含 {2015, 2016, 2017}
  2. 查找模型名称匹配的所有行。对于您的示例,这给我们留下了

    model_name record_date car1 5-2015 car1 1-2016 car1 2-2015

  3. 浏览上面的行,看看 record_date 的年份部分是否与数组中的任何日期匹配。该条件将始终为真,因为数组包含该列的所有可能值。所以条件不会从结果中删除任何内容。

这反过来意味着,您的查询等同于:

select vd1.model_name, vd1.record_date
from vehicle_data vd1
where vd1.model_name LIKE = 'car1'
order by split_part(record_date, '-', 2)::int, 
         split_part(record_date, '-', 1)::int;