МиСПрИС_КР2_Петрова_Романова_Заболотников_9373
.pdfРисунок 25 – Добавим спецификацию для велосипеда Победа в виде 45
Шестигранников
Рисунок 26 – Результат
21
Рисунок 27 – Проверка спецификации
Рисунок 28 – Спецификация верна
22
Выводы.
В данной работе была разработан проект каркаса для работы со спецификациями. Реализация произведена в базе данных PostgreSQL.
Проведено тестирование, показывающее корректную работу реализованных функций для работы с данными. Кроме того, был реализован пользовательский интерфейс для взаимодействия человека с базой данных.
Проведены тесты работы приложения и была установлена его корректная работа. Полный код программы можно посмотреть в приложении А. Методы классов технической программы представлены в приложении Б.
23
ПРИЛОЖЕНИЕ А
---НОВАЯ ТАБЛИЦА----
create table Spec_Product --Таблица позиций спецификатора
(
id_variation serial not null primary key,-- id пары главного продукта и используемого
id_mainProduct integer not null, -- id главного продукта id_useProduct integer not null, --id составного продукта positionInSP integer not null, -- Номер позиции
countInSP integer not null, -- Количество используемого продукта в главном
flag integer not null,-- Флаг базы
CONSTRAINT id_mainProduct FOREIGN KEY (id_mainProduct) REFERENCES Product (id_product) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE
)
create unique index union_MainAndUse on Spec_Product(id_mainProduct, id_useProduct); --Создадим индекс для уникальности пар (главный продукт, составной продукт)
ALTER TABLE Spec_Product ADD CONSTRAINT id_useProduct FOREIGN KEY (id_useProduct)
REFERENCES public.Product (id_product) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE cascade
---ФУНКЦИИ-----
-- Добавление элементов в таблицу SP
/*функция: Дообавляет новую позицию в спецификатор и поверяет не создано ли циклов. Если циклы есть, то изменения откатываются вход: id_mainProductN - ид. продукта главного
id_useProductN - ид. используемого продукта countInSPN -количество используемого продукта flagN - флаг базы
эффекты:
24
1.Если продукта главного или используемого не существует, то будет выведена ошибка.
2.Если при поощи новой позиции был создан цикл, то изменения не будут внесены.
3.Позиция пары будет вычислена автоматически
*/
CREATE OR REPLACE function add_posSP ( id_mainProductN integer, id_useProductN integer,
countInSPN integer,
flagN integer) RETURNS VOID as $$
declare ind_mp int default 0; declare ind_up int default 0; declare posNew int default 0; begin
select id_product from product where id_mainProductN = id_product into ind_mp;
select id_product from product where id_useProductN = id_product into ind_up;
if (ind_mp is not null) then if ind_up is not null then
select max(positioninsp)+1 from spec_product where id_mainProductN = id_mainproduct into posNew;
if posNew is null then posNew:= 1;
end if;
INSERT INTO spec_product(id_mainproduct, id_useproduct,positioninsp,countinsp,flag) VALUES (id_mainProductN, id_useProductN,posNew,countInSPN,flagN);
if check_loop(id_mainProductN) is not null then delete from spec_product where id_mainproduct =
id_mainProductN and id_useproduct = id_useProductN;
raise exception 'You have created the loop. Db
was not updated.';
end if;
else
25
raise exception 'This using product is not existing. Db was not updated.';
end if; else
raise exception 'This main product is not existing. Db was not updated.';
end if;
end $$ LANGUAGE plpgsql;
--Удаление Позиции в спецификаторе
/*функция: Удаляет ппозицию в спецификаторе, если заявленный идентификато пары существует
вход: spIdToDelete - id_variation пары, которую нужно удалить эффекты:
1. Если id пары нет, то будет выведено сообщение об ошибке.
*/
CREATE OR REPLACE function delete_sp ( spIdToDelete integer) RETURNS VOID
as $$ begin
if(select id_variation from spec_product where spIdToDelete = id_variation limit 1) is not null then
DELETE FROM spec_product WHERE spIdToDelete = id_variation;
else
raise exception 'SP with this id does not exist. DB wasnt
updated.'; end if;
end $$ LANGUAGE plpgsql;
/*функция: Проверяет наличие циклов и возвращает либо 0, либо число отличное от 0
вход: spIdToCheck - id новой позиции, которая проверяется на создание цикла
выход: id_useproduct - либо id продукта которрый стоит перед заданным в цикле,либо null - если цикла нет
26
*/
CREATE OR REPLACE function check_loop (
spIdToCheck integer) RETURNS table (id_useproduct int) LANGUAGE plpgsql as $func$
begin
RETURN QUERY
with recursive graph(id_mainproduct, id_useproduct, path) as ( select sp.id_mainproduct, sp.id_useproduct, CAST
(sp.id_useproduct AS TEXT) as PATH
from spec_product as sp where sp.id_mainproduct = spIdToCheck union all
select spec_product.id_mainproduct, spec_product.id_useproduct, CAST ( graph.PATH ||' = > '|| spec_product.id_useproduct AS TEXT)
from spec_product inner join graph on graph.id_useproduct = spec_product.id_mainproduct
where spec_product.id_mainproduct <> spIdToCheck
)
select graph.id_useproduct from graph where graph.id_useproduct = spIdToCheck limit 1;
end $func$;
--
/*функция: Выводит все позиции используемых продуктов для заданного и считает количество каждого из них
вход: spIdToCheck - идентификатор того продукта, для которого необходио составить список выход: Таблица с количеством продукта и его идентификатором
*/
CREATE OR REPLACE function func_count (
spIdToCheck integer) RETURNS table (countProd bigint,id_useproduct
int)
LANGUAGE plpgsql as $func$ begin
RETURN QUERY
27
with recursive graph(id_mainproduct, id_useproduct, path) as ( select sp.id_mainproduct, sp.id_useproduct, CAST
(sp.id_useproduct AS TEXT) as PATH
from spec_product as sp where sp.id_mainproduct = spIdToCheck union all
select spec_product.id_mainproduct, spec_product.id_useproduct, CAST ( graph.PATH ||' = > '|| spec_product.id_useproduct AS TEXT)
from spec_product inner join graph on graph.id_useproduct = spec_product.id_mainproduct
)
select func_price(t1.id, spIdToCheck), id from (select distinct graph.id_useproduct as id from graph) as t1;
end $func$;
select * from func_price(9,1);
/*функция: Высчитывает количество для заданного продукта вход: spIdToCheck - идентификатор того продукта, для которого расчитывается количество выход: Количество продукта
*/
CREATE OR REPLACE function func_price (
spIdToCheck integer, MainIdProd integer) RETURNS table (countprod bigint)
LANGUAGE plpgsql as $func$ begin
RETURN QUERY
with recursive graph(id_mainproductt, id_useproduct, path, countp) as (
select sp.id_mainproduct, sp.id_useproduct, CAST ( sp.id_useproduct|| ' = > ' || sp.id_mainproduct AS TEXT) as path, sp.countinsp
from spec_product as sp where sp.id_useproduct = spIdToCheck union all
28
select spec_product.id_mainproduct, spec_product.id_useproduct, CAST ( graph.PATH ||' = > '|| spec_product.id_mainproduct AS TEXT), spec_product.countinsp*graph.countp
from spec_product inner join graph on graph.id_mainproductt = spec_product.id_useproduct
)
select sum (t2.countp) from (select id_mainproductt, countp from graph where id_mainproductt = MainIdProd) as t2;
end $func$;
/*функция: На основании ранее перечисленных функций объединяет таблицы и выводит позиции для главного продуктав понятном виде
вход: idProd - идентификатор того продукта, для которого выводится список с количеством выход: Таблица с классом продукта, его названием, количеством и единицой измерения
*/
CREATE OR REPLACE function func_output (
idProd integer) RETURNS table (countProduct bigint, nameProduct text, nameClass text, nameUom text)
LANGUAGE plpgsql as $func$ begin
RETURN QUERY
select t2.countprod, t2.name_product, t2.name_class, uom.name_uom
from(
select t1.countprod, t1.name_product, pc.name_class, pc.id_uom from
(select countprod, name_product, id_class from func_count(idProd) as f left join product as p on p.id_product = f.id_useproduct) as t1
left join product_class pc on pc.id_class = t1.id_class) as
t2
left join unit_of_measure uom on uom.id_uom = t2.id_uom;
end $func$;
29
---------------------------------------------Заполнение таблиц -------
-----------------------------------------------
select add_class('Велосипед',null,1); select add_class('Горный',1,1); select add_class('Спортивный',1,1); select add_class('Прогулочный',1,1);
select add_class('Колёса', null, 1); select add_class('БольшиеКолёса', 5, 1); select add_class('МаленькиеКолёса', 5, 1); select add_class('СредниеКолёса', 5, 1);
select add_class('Руль', null, 1); select add_class('ТипА_Р', 9, 1); select add_class('ТипБ_Р', 9, 1); select add_class('ТипС_Р', 9, 1);
select add_class('Болты', null, 1); select add_class('ТипА_Б', 13, 1); select add_class('ТипБ_Б', 13, 1); select add_class('ТипС_Б', 13, 1);
select add_class('Крылья', null, 1); select add_class('Резиновые', 17, 1); select add_class('Железные', 17, 1);
select add_class('Спицы', null, 1); select add_class('ТипА_С', 20, 1); select add_class('ТипБ_С', 20, 1); select add_class('ТипС_С', 20, 1);
select add_class('Металл', null, 1); select add_class('ТипА_М', 24, 1); select add_class('ТипБ_М', 24, 1); select add_class('ТипС_М', 24, 1);
30