У меня есть Microsoft SQL -Server со следующими таблицами:
- Projects
- BookedHours (с fk_Project = Projects.ID)
- Products
- ProjectsToProducts (n: m с fk_Projects = Projects.ID и fk_Products = Products.ID)
Теперь я хочу выбрать, сколько часов зарезервировано для какого продукта в месяц. Проблема в том, что в одном проекте может быть несколько продуктов (вот почему мне нужна таблица n: m).
Если я сделаю следующее, часы будут подсчитаны дважды, если в проекте есть два продукта.
SELECT P.ID AS fk_Product, MONTH(B.Datum) AS Monat, SUM(B.Hours) AS Stunden
FROM tbl_BookedHours AS B INNER JOIN tbl_Projects AS M on B.fk_Project = M.ID
INNER JOIN tbl_ProjectProduct AS PP ON PP.fk_Project = M.ID
INNER JOIN tbl_Products AS P ON PP.fk_Product = P.ID
WHERE YEAR(B.Datum) = 2020
GROUP BY P.ID,MONTH(B.Datum)
ORDER BY P.ID, MONTH(B.Datum)
Я могу получить количество продуктов для каждого проекта с помощью этого SQL:
SELECT fk_Project, COUNT(*) AS Cnt
FROM tbl_ProjectProduct
GROUP By fk_MainProject
Но как я теперь могу разделить часы для каждого проекта на его индивидуальный коэффициент и сложить все это по продукту и месяцу?
Я мог бы сделать это в моей C# программе или я мог бы использовать курсор и перебирать все проекты, но я думаю, что должен быть более элегантный способ.
Редактировать с использованием данных образца
|----------------| |----------------| |------------------------------|
| tbl_Projects | | tbl_Products | | tbl_ProjectProduct |
|----------------| |----------------| |------------------------------|
| ID | Name | | ID | Name | | ID | fk_Project | fk_Product |
|----+-----------| |----+-----------| |------------------------------|
| 1 | Project 1 | | 1 | Product 1 | | 1 | 1 | 1 |
| 2 | Project 2 | | 2 | Product 2 | | 2 | 1 | 2 |
| 3 | Project 3 | | 3 | Product 3 | | 3 | 2 | 1 |
| 4 | Project 4 | | 4 | Product 4 | | 4 | 3 | 3 |
|----------------| |----------------| | 5 | 4 | 1 |
| 6 | 4 | 2 |
| 7 | 4 | 4 |
|------------------------------|
|--------------------------------------|
| tbl_BookedHours |
|--------------------------------------|
| ID | fk_Project | Hours | Date |
|--------------------------------------|
| 1 | 1 | 10 | 2020-01-15 |
| 2 | 1 | 20 | 2020-01-20 |
| 3 | 2 | 10 | 2020-01-15 |
| 4 | 3 | 30 | 2020-01-18 |
| 5 | 2 | 20 | 2020-01-20 |
| 6 | 4 | 30 | 2020-01-25 |
| 7 | 1 | 10 | 2020-02-15 |
| 8 | 1 | 20 | 2020-02-20 |
| 9 | 2 | 10 | 2020-02-15 |
| 10 | 3 | 30 | 2020-03-18 |
| 11 | 2 | 20 | 2020-03-20 |
| 12 | 4 | 30 | 2020-03-25 |
|--------------------------------------|
Результат должен быть:
|----------------------------|
| fk_Product | Month | Hours |
|----------------------------|
| 1 | 1 | 55 |
| 2 | 1 | 25 |
| 3 | 1 | 30 |
| 4 | 1 | 10 |
| 1 | 2 | 25 |
| 2 | 2 | 15 |
| 1 | 3 | 30 |
| 2 | 3 | 10 |
| 3 | 3 | 30 |
| 4 | 3 | 10 |
|----------------------------|
Например, бронирование №. 1 нужно разделить на 2 (поскольку в проекте 1 есть два продукта) и одна половина суммы добавляется к продукту 1, а другая - к продукту 2 (оба в январе). Бронирование Nr. 4 не следует разделять, потому что в Project 3 только один продукт. Например, номер бронирования 12 нужно разделить на 3. Таким образом, итоговые часы в сумме будут равны той же сумме. Надеюсь, теперь стало понятнее. * РЕДАКТИРОВАТЬ 2 *
DECLARE @tbl_Projects TABLE (ID INT, [Name] VARCHAR(MAX))
INSERT INTO @tbl_Projects VALUES
(1,'Project 1'),
(2,'Project 2'),
(3,'Project 3'),
(4,'Project 4')
DECLARE @tbl_Products TABLE (ID INT, [Name] VARCHAR(MAX))
INSERT INTO @tbl_Products VALUES
(1,'Product 1'),
(2,'Product 2'),
(3,'Product 3'),
(4,'Product 4')
DECLARE @tbl_ProjectProduct TABLE (ID INT, fk_Project int, fk_Product int)
INSERT INTO @tbl_ProjectProduct VALUES
(1,1,1),
(2,1,2),
(3,2,1),
(4,3,3),
(5,4,1),
(6,4,2),
(7,4,4)
DECLARE @tbl_BookedHours TABLE (ID INT, fk_Project int, Hours int, [Date] Date)
INSERT INTO @tbl_BookedHours VALUES
(1,1,10,'2020-01-15'),
(2,1,20,'2020-01-20'),
(3,2,10,'2020-01-15'),
(4,3,30,'2020-01-18'),
(5,2,20,'2020-01-20'),
(6,4,30,'2020-01-25'),
(7,1,10,'2020-02-15'),
(8,1,20,'2020-02-20'),
(9,2,10,'2020-02-15'),
(10,3,30,'2020-03-18'),
(11,2,20,'2020-03-20'),
(12,4,30,'2020-03-25')
SELECT P.ID AS fk_Product, MONTH(B.Date) AS Month, SUM(B.Hours) AS SumHours
FROM @tbl_BookedHours AS B INNER JOIN @tbl_Projects AS M on B.fk_Project = M.ID
INNER JOIN @tbl_ProjectProduct AS PP ON PP.fk_Project = M.ID
INNER JOIN @tbl_Products AS P ON PP.fk_Product = P.ID
GROUP BY P.ID,MONTH(B.Date)
ORDER BY P.ID, MONTH(B.Date)
Это дает мне неправильный результат, потому что он считает часы для обоих продуктов:
| fk_Product | Month | SumHours |
|-------------------------------|
| 1 | 1 | 90 |
| 1 | 2 | 40 |
| 1 | 3 | 50 |
| 2 | 1 | 60 |
| 2 | 2 | 30 |
| 2 | 3 | 30 |
| 3 | 1 | 30 |
| 3 | 3 | 30 |
| 4 | 1 | 30 |
| 4 | 3 | 30 |
|-------------------------------|