Для решения вашего непосредственного вопроса: для итерации по массиву используйте цикл 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;
Это берет все лет из таблицы и возвращает те строки, в которых год в строке внутреннего запроса (только один в случае второго варианта) равен по крайней мере одному из значений в массив, который имеет значение true для всех строк, поскольку значения в массиве - это все существующих лет в этом столбце. Таким образом, по крайней мере одно из значений в массиве будет соответствовать значению в строке, просматриваемой в данный момент при обработке запроса, что, в свою очередь, означает, что в целом условие вообще не является необходимым.
Вы можете представить, что ваша функция (логически) обрабатывается так:
- получить все годы в массиве, поэтому массив содержит {2015, 2016, 2017}
найти все строки, в которых совпадает название модели. Для вашего примера это оставляет нас с
модель_имя запись_дата
автомобиль1 5-2015
автомобиль1 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;