разделить выбранное значение на количество (*) - PullRequest
1 голос
/ 08 мая 2020

У меня есть 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       |
|-------------------------------|

1 Ответ

1 голос
/ 08 мая 2020

Рассмотрим следующий запрос. Я изменил переменные вашей таблицы на временные таблицы, чтобы было легче отлаживать.

;WITH CTE AS
    (
    SELECT fk_Project, count(fk_Product) CNT 
    FROM #tbl_ProjectProduct
    GROUP BY fk_Project
    )
    ,CTE2 AS
        (
        SELECT t1.Date, t2.fk_Project, Hours/CNT NewHours
        FROM #tbl_BookedHours t1
        INNER JOIN CTE t2 on t1.fk_Project = t2.fk_Project
        )
SELECT t4.ID fk_Product, MONTH(date) MN, SUM(NewHours) HRS
FROM CTE2 t1
INNER JOIN #tbl_Projects t2 on t1.fk_Project = t2.id
INNER JOIN #tbl_ProjectProduct t3 on t3.fk_Project = t2.ID
INNER JOIN #tbl_Products t4 on t4.ID = t3.fk_Product
GROUP BY t4.ID,MONTH(date)
...