@holllop

Как составить сложный агрегированный запрос?

У меня есть три таблицы
spoiler
-- Это первая таблица
Table "public.order"
     Column     |  Type   | Collation | Nullable |                    Default
----------------+---------+-----------+----------+-----------------------------------------------
 order_id       | integer |           | not null | nextval('"main_table_N_order_seq"'::regclass)
 departament_id | integer |           |          |
 customer_id    | integer |           |          |
 date           | date    |           |          |
 type_expenses  | integer |           |          |
 budget         | boolean |           |          |
Indexes:
    "main_table_pkey" PRIMARY KEY, btree (order_id)
Foreign-key constraints:
    "main_table_customer_id_fkey" FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
    "main_table_customer_id_fkey1" FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
    "main_table_departament_id_fkey" FOREIGN KEY (departament_id) REFERENCES departaments(departament_id)
    "main_table_type_expenses_fkey" FOREIGN KEY (type_expenses) REFERENCES type_expenses(id) NOT
VALID
Referenced by:
    TABLE "works" CONSTRAINT "works_id_order_fkey" FOREIGN KEY (id_order) REFERENCES "order"(order_id)
-- Это вторая таблица
Table "public.works"
   Column    |          Type          | Collation | Nullable |                    Default

-------------+------------------------+-----------+----------+-----------------------------------
------------
 id_work     | integer                |           | not null | nextval('"main_table_N_order_seq"'
::regclass)
 id_order    | integer                |           |          |
 name_object | character varying(100) |           |          |
 n_plan      | integer                |           |          |
Indexes:
    "works_pkey" PRIMARY KEY, btree (id_work)
Foreign-key constraints:
    "works_id_order_fkey" FOREIGN KEY (id_order) REFERENCES "order"(order_id)
Referenced by:
    TABLE "expenses" CONSTRAINT "work_object_work_id_fkey" FOREIGN KEY (n_plan) REFERENCES works(id_work)
-- Это третья таблица
Table "public.expenses"
    Column    |     Type     | Collation | Nullable |                    Default

--------------+--------------+-----------+----------+--------------------------------------------
---
 n_work       | integer      |           | not null | nextval('"main_table_N_order_seq"'::regclas
s)
 n_plan       | integer      |           |          |
 type_work_id | integer      |           |          |
 printer_id   | integer      |           |          |
 material_id  | integer      |           |          |
 performer_id | integer      |           |          |
 format_id    | integer      |           |          |
 n_sheets     | numeric(4,1) |           |          |
 n_page       | numeric(4,1) |           |          |
 n_ruined     | numeric(4,1) |           |          |
Indexes:
    "work_object_pkey" PRIMARY KEY, btree (n_work)
Foreign-key constraints:
    "work_object_format_id_fkey" FOREIGN KEY (format_id) REFERENCES format(format_id)
    "work_object_material_id_fkey" FOREIGN KEY (material_id) REFERENCES material(material_id)
    "work_object_performer_id_fkey" FOREIGN KEY (performer_id) REFERENCES performers(performer_id)
    "work_object_printer_id_fkey" FOREIGN KEY (printer_id) REFERENCES printer(printer_id)
    "work_object_type_work_id_fkey" FOREIGN KEY (type_work_id) REFERENCES type_work(type_work_id)
    "work_object_work_id_fkey" FOREIGN KEY (n_plan) REFERENCES works(id_work)

и из кода выше можно определить следующую структуру, что один order_id соответствует нескольким id_work, а один id_work соответствует нескольким n_work
хочу из них вывести информацию
spoiler
o.order_id, d.name AS dname, c.customer, o.date, w.id_order, w.id_work, w.name_object, e.n_work, tw.type_work, pr.printer, ma.material, pe.performer, f.format, e.n_sheets

По этим столбцам, но прекрасно понимаю что если не применить агрегацию, то это будет куча записей с одинаковым order_id, по этому начал пытатся применять агрегацию.
spoiler
SELECT
    w.id_order,
    w.id_work,
    w.name_object,
    STRING_AGG(e.n_work::text, ',') AS n_works,
    STRING_AGG(tw.type_work, ',') AS types_of_work,
    STRING_AGG(pr.printer, ',') AS printers,
    STRING_AGG(ma.material, ',') AS materials,
    STRING_AGG(pe.performer, ',') AS performers,
    STRING_AGG(f.format, ',') AS formats,
    STRING_AGG(e.n_sheets::text, ',') AS total_sheets
    FROM 
      works w
    INNER JOIN 
      expenses e ON w.id_work = e.n_plan
    INNER JOIN 
      type_work tw ON e.type_work_id = tw.type_work_id
    INNER JOIN 
      printer pr ON e.printer_id = pr.printer_id
    INNER JOIN 
      material ma ON e.material_id = ma.material_id
    INNER JOIN 
      performers pe ON e.performer_id = pe.performer_id
    INNER JOIN 
      format f ON e.format_id = f.format_id
    GROUP BY 
      w.id_order, w.id_work, w.name_object;

вроде этой команды получал из неё
spoiler
[
{
id_order: 15,
id_work: 16,
name_object: "80",
n_works: "61,60,59,58",
types_of_work: "Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать",
printers: "Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i",
materials: "A3,A4,A4,A4",
performers: "",
formats: "A0,A0,A0,A0",
total_sheets: "14.0,100.0,100.0,100.0"
},
{
id_order: 12,
id_work: 25,
name_object: "",
n_works: "27",
types_of_work: "Ч/б печать",
printers: "Kyosera 3510i",
materials: "A3",
performers: "Буракова О.Ю.",
formats: "A3",
total_sheets: "12.0"
},
{
id_order: 12,
id_work: 26,
name_object: "",
n_works: "28",
types_of_work: "Ч/б печать",
printers: "Kyosera 3510i",
materials: "A3",
performers: "",
formats: "A3",
total_sheets: "13.0"
},
{
id_order: 13,
id_work: 30,
name_object: "какой-то",
n_works: "31",
types_of_work: "Цветная печать",
printers: "HP DesignJet 500",
materials: "914*50m",
performers: "",
formats: "A1",
total_sheets: "0.0"
},
{
id_order: 13,
id_work: 32,
name_object: "какой-то",
n_works: "33",
types_of_work: "Цветная печать",
printers: "HP DesignJet 500",
materials: "914*50m",
performers: ".",
formats: "A1",
total_sheets: "0.0"
},
{
id_order: 13,
id_work: 34,
name_object: "какой-то",
n_works: "41,42,43,44,45,46,47,48,49,50,51,40,53,54,55,56,39,38,57,37,36,35,52",
types_of_work: "Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Ч/б печать,Цветная печать,Ч/б печать,Ч/б печать",
printers: "Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,Kyosera 3510i,HP DesignJet 500,Kyosera 3510i,Kyosera 3510i",
materials: "610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,610*175m,914*50m,A3,610*175m",
performers: "",
formats: "A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A1,A3,A0",
total_sheets: "0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,12.0,0.0,0.0,0.0,0.0"
}
]

и как видно выводится всё равно несколько одинаковых order_id хотя по сути должен быть вывод всего 3 записей
  • Вопрос задан
  • 138 просмотров
Решения вопроса 1
@holllop Автор вопроса
Правильный sql запрос для того чтобы реализовать, то что я хотел выглядит так
SELECT 
      o.order_id, 
      d.name AS dname, 
      c.customer, 
      o.date, 
      array_agg(
        json_build_object(
          'id_works', w.id_work::text, 
          'name_object', w.name_object, 
          'work_items', subq.work_items
        )
      ) AS works_info
      FROM "order" o
      JOIN works w ON o.order_id = w.id_order
      JOIN departaments d ON o.departament_id = d.departament_id
      JOIN customers c ON o.customer_id = c.customer_id
      LEFT JOIN (
        SELECT
            w.id_work,
            w.name_object,
            json_agg(json_build_object(
                'n_works', e.n_work::text,
                'type_works', tw.type_work,
                'printers', pr.printer,
                'materials', ma.material,
                'performers', pe.performer,
                'formats', f.format,
                'n_sheets', e.n_sheets::text
            )) AS work_items
        FROM works w
        LEFT JOIN expenses e ON w.id_work = e.n_plan
        LEFT JOIN type_work tw ON e.type_work_id = tw.type_work_id
        LEFT JOIN printer pr ON e.printer_id = pr.printer_id
        LEFT JOIN material ma ON e.material_id = ma.material_id
        LEFT JOIN performers pe ON e.performer_id = pe.performer_id
        LEFT JOIN format f ON e.format_id = f.format_id
        GROUP BY w.id_work, w.name_object
      ) AS subq ON w.id_work = subq.id_work
    GROUP BY o.order_id, d.name, c.customer, o.date
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы