sql - 如何从我的 postgresql 函数中消除重复项?
问题描述
我有这个 vehicle_data 表:CREATE 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)
)
我的桌子看起来像:
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 数组以获取年份值,将所有唯一值存储在一个数组中,然后运行我的选择查询每年。
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;
这会从表中获取所有年份并返回内部查询行中的年份(在第二个变体的情况下只有一个)等于数组中至少一个值的那些行,这对于所有行都是正确的,因为数组中的值是该列中所有现有的年份。因此,数组中的至少一个值将与处理查询时当前正在查看的行中的值匹配,这反过来意味着整个条件根本不是必需的。
你可以想象你的函数(逻辑上)是这样处理的:
- 将所有年份放入一个数组中,因此该数组包含 {2015, 2016, 2017}
查找模型名称匹配的所有行。对于您的示例,这给我们留下了
型号名称 记录日期 car1 5-2015 car1 1-2016 car1 2-2015
遍历上面的行,查看 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;
推荐阅读
- php - PHP (MYSQL) 客户端 API 版本更新
- python - 带有空列表的切片分配 - 为什么?
- c# - 如何在构造函数中解析类型安全集合?
- ios - xcode 10错误:产生多个命令-本机反应
- docker - 访问 Wildfly 管理控制台时出错 - 需要身份验证
- python - 用于预测性别的数据集
- python - Kubernetes 的 Airflow GCP 连接问题 - Fernet 密钥必须是 32 个 url 安全的 base64 编码字节
- javascript - 如何从网页中编辑或删除数据库的表数据
- c - 位掩码和位数组之间有区别吗?
- java - 无法加载 javafx 场景