CSC Бызы данных, 9 дз
Вам нужно посчитать некоторую статистику о багах в багтрекере. Статистику вы хотите видеть в представлениях, соответственно основной задачей является написание запросов, формирующих представления.
Во-первых, вам хочется для каждого проекта найти суммарное количество багов каждого из имеющихся у вас статусов. Хочется видеть примерно такое:
SELECT * FROM BusSummaryPerProject; project_id | new | assigned | fixed | verified | not reproducible 1001 45 24 3 0 10 1002 56 10 37 104 15
Для упрощения можете считать, что множество статусов известно и не собирается меняться.
Во-вторых, для каждого статуса хочется видеть компоненту с максимальным, минимальным и медианным количеством багов с таким статусом. Например, если у нас 7 компонент и количество багов со статусом “new” в них распределено так:
C1 | 10 C2 | 50 C3 | 15 C4 | 30 C5 | 20 C6 | 25 C7 | 35
то в строке представления для статуса new должно быть:
SELECT * FROM StatisticsPerStatus WHERE status='new'; status | max_component | max_value | min_component | min_value | median_component | median_value new C2 50 C1 10 C6 25
Если число компонент четное, то считайте медианой большее из двух возможных значений. Если медианное значение принадлежит нескольким компонентам, то добавьте лексикографическую сортировку по названию компоненты (так, если бы в примере выше в компоненте C4 было бы 25 багов, то медианой стала бы она, если бы в компоненте C5 было 25 багов, то медианой осталась бы C6, а если бы и в C4 и в C5 было бы 25 багов, то медианой стала бы C5)
Собсвтенно решение:
Пунт 1
Для вывода информаци по кадому проекту я построил впомогательно представление которое получает отношение "проект - статус - количество"
-- View: statustoproject -- DROP VIEW statustoproject; CREATE OR REPLACE VIEW statustoproject AS SELECT count(bug.status_id) AS count, bug.status_id AS status, component.project_id AS project FROM bug JOIN bugcomponent ON bug.num = bugcomponent.bug_num JOIN component ON bugcomponent.component_id = component.id GROUP BY component.project_id, bug.status_id ORDER BY component.project_id, bug.status_id; ALTER TABLE statustoproject OWNER TO postgres;
Далее, собственно, выбираю из вспомогательной выбоки и строю нужное отношение.
-- View: bussummaryperproject -- DROP VIEW bussummaryperproject; CREATE OR REPLACE VIEW bussummaryperproject AS SELECT project.id AS project_id, COALESCE(( SELECT statustoproject.count FROM statustoproject WHERE statustoproject.project = project.id AND statustoproject.status = 1), 0::bigint) AS new, COALESCE(( SELECT statustoproject.count FROM statustoproject WHERE statustoproject.project = project.id AND statustoproject.status = 2), 0::bigint) AS assigned, COALESCE(( SELECT statustoproject.count FROM statustoproject WHERE statustoproject.project = project.id AND statustoproject.status = 3), 0::bigint) AS fixed, COALESCE(( SELECT statustoproject.count FROM statustoproject WHERE statustoproject.project = project.id AND statustoproject.status = 4), 0::bigint) AS verified, COALESCE(( SELECT statustoproject.count FROM statustoproject WHERE statustoproject.project = project.id AND statustoproject.status = 5), 0::bigint) AS "not reproducible" FROM project; ALTER TABLE bussummaryperproject OWNER TO postgres;
Пункт 2
Самым сложным для меня было создать функцию медианы
CREATE OR REPLACE FUNCTION array_median(numeric[]) RETURNS numeric AS $$ SELECT CASE WHEN array_upper($1,1) = 0 THEN null ELSE asorted[ceiling(array_upper(asorted,1)/2.0)] END FROM (SELECT ARRAY(SELECT ($1)[n] FROM generate_series(1, array_upper($1, 1)) AS n WHERE ($1)[n] IS NOT NULL ORDER BY ($1)[n] ) As asorted) As foo ; $$ LANGUAGE 'sql' IMMUTABLE; CREATE AGGREGATE median(numeric) ( SFUNC=array_append, STYPE=numeric[], FINALFUNC=array_median );
Далее как и в первом примере я строю вспомогательное представление.
-- View: statustocomponent -- DROP VIEW statustocomponent; CREATE OR REPLACE VIEW statustocomponent AS SELECT DISTINCT count(bug.status_id) AS count, bug.status_id AS status, component.id, component.title AS componentname FROM bug JOIN bugcomponent ON bug.num = bugcomponent.bug_num JOIN component ON bugcomponent.component_id = component.id GROUP BY component.id, bug.status_id ORDER BY component.id, bug.status_id; ALTER TABLE statustocomponent OWNER TO postgres;
Далее строю нужно отношение.
-- View: statisticsperstatus -- DROP VIEW statisticsperstatus; CREATE OR REPLACE VIEW statisticsperstatus AS SELECT bugstatus.value AS status, COALESCE(( SELECT statustocomponent.componentname FROM statustocomponent WHERE statustocomponent.status = bugstatus.id ORDER BY statustocomponent.count DESC, statustocomponent.componentname LIMIT 1), 'null'::character varying) AS max_component, COALESCE(( SELECT max(statustocomponent.count) AS max FROM statustocomponent WHERE statustocomponent.status = bugstatus.id), 0::bigint) AS max_value, COALESCE(( SELECT statustocomponent.componentname FROM statustocomponent WHERE statustocomponent.status = bugstatus.id ORDER BY statustocomponent.count, statustocomponent.componentname LIMIT 1), 'null'::character varying) AS min_component, COALESCE(( SELECT min(statustocomponent.count) AS min FROM statustocomponent WHERE statustocomponent.status = bugstatus.id), 0::bigint) AS min_value, COALESCE(( SELECT statustocomponent.componentname FROM statustocomponent WHERE statustocomponent.status = bugstatus.id AND statustocomponent.count::numeric = (( SELECT median(statustocomponent.count::numeric) AS median FROM statustocomponent WHERE statustocomponent.status = bugstatus.id)) ORDER BY statustocomponent.componentname LIMIT 1), 'null'::character varying) AS median_component, COALESCE(( SELECT median(statustocomponent.count::numeric) AS median FROM statustocomponent WHERE statustocomponent.status = bugstatus.id), 0::numeric) AS median_value FROM bugstatus; ALTER TABLE statisticsperstatus OWNER TO postgres;
Работет все это достаточно шутсро, поэтому решиние претендует быть верным.
Вомозможно я неверно лексиграфически упрорячиваю названия компонент
Дамп базы dbhw9.sql
Leave a comment