Тонкая настройка запроса MS SQL-сервера, объединяющего две таблицы с группированным результатом - PullRequest
0 голосов
/ 18 ноября 2018

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

Итак, вот мои три таблицы:

enter image description here

enter image description here

enter image description here

И вот вывод, который я хочу: enter image description here

Таблица вывода должна отображать месячные значения с января по декабрь В реальной базе данных таблица A содержит ~ 40 тыс. Строк, таблица B содержит 20 строк, а таблица C содержит ~ 1 млн. Строк. Ниже вы можете увидеть часть запроса, который я написал и который генерирует желаемый вывод, однако когда я запускаю его для реальной БД, это занимает ~ 20-30 секунд:

  SELECT TableA.Id
    ,TableA.Title
    ,TableA.Description
    ,TableB.Title
    ,f1.[Value] as TableC_JanuaryValue
    ,f2.[Value] as TableC_FebruaryValue
    ....
    FROM <tablename>
INNER JOIN TableB ON TableB.Id = TableA.TableB_FK_Id
INNER JOIN TableC as f1 ON (f1.TableA_FK_Id = TableA.Id AND f1.[Year] = 2018 AND f1.[Month] = 1)
INNER JOIN TableC as f2 ON (f2.TableA_FK_Id = TableA.Id AND f2.[Year] = 2018 AND f2.[Month] = 2)
.....

Я пытался написать это по-другому и сделать это быстрее, и мне удалось сократить его до 2-3 секунд, однако вывод не совсем то, что я хочу. Вот второй запрос:

  SELECT TableA.Id
    ,TableA.Title
    ,TableA.Description
    ,TableB.Title
    ,count(case when TableC.Value = 'V1' and TableC.[Month] = 1 then TableC.Id end) as JAN_IsV1
    ,count(case when TableC.Value = 'V2' and TableC.[Month] = 1 then TableC.Id end) as JAN_IsV2
    ,count(case when TableC.Value = 'V3' and TableC.[Month] = 1 then TableC.Id end) as JAN_IsV3
    ,count(case when TableC.Value = 'V1' and TableC.[Month] = 2 then TableC.Id end) as FEB_IsV1
    ,count(case when TableC.Value = 'V2' and TableC.[Month] = 2 then TableC.Id end) as FEB_IsV2
    ,count(case when TableC.Value = 'V3' and TableC.[Month] = 2 then TableC.Id end) as FEB_IsV3
    ....
    FROM <tablename>
INNER JOIN TableB ON TableB.Id = TableA.TableB_FK_Id
INNER JOIN TableC ON TableA.Id = TableC.TAbleA_FK_Id
where TableC.[Year] = 2018
group by TableA.Id, TableA.Title, TableA.Description, TableB.Title

И вот что я получаю: enter image description here

Я знаю, что это очень близко к результату, который я хочу, однако это не совсем то же самое :(

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018
 SELECT 
       tablea.Id AS TableA_Id,  
       tablea.Title AS TableA_Title, 
       tablea.Description AS TableA_Description,
       (SELECT tableb.Title FROM tableb WHERE tableb.Id = TableA.TableB_FK_Id) AS TableB_Id,
       (SELECT tablec.Value FROM tablec WHERE tablea.Id = TableC.TableA_FK_Id AND tablec.Month = 1) AS TableC_JanValue,
       (SELECT tablec.Value FROM tablec WHERE tablea.Id = TableC.TableA_FK_Id  AND tablec.Month = 2) AS TableC_FebValue
FROM tablea;

этот тоже можно попробовать .. !!:)

0 голосов
/ 18 ноября 2018

Просто сделайте поворот на TableC до того, как присоедините его к остальным.И используйте MAX(CASE) вместо COUNT(CASE)

SELECT
    TableA.Id
    ,TableA.Title
    ,TableA.Description
    ,TableB.Title
    ,TableC.*
FROM
    TableA
INNER JOIN
    TableB
        ON TableB.Id = TableA.TableB_FK_Id
INNER JOIN
(
    SELECT
        TableA_FK_Id,
        MAX(CASE WHEN [Month] = 1 THEN Value END) AS JAN,
        MAX(CASE WHEN [Month] = 2 THEN Value END) AS FEB, 
        MAX(CASE WHEN [Month] = 3 THEN Value END) AS MAR, 
        ...
    FROM
        TableC
    WHERE
        [YEAR] = 2018
    GROUP BY
        TableA_FK_Id
)
    TableC
        ON TableA.Id = TableC.TableA_FK_Id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...