Оператор SQL для получения значения поля datetime записи в виде столбца результата - PullRequest
3 голосов
/ 23 ноября 2011

У меня есть следующие две таблицы

activity(activity_id, title, description, group_id)
statistic(statistic_id, activity_id, date, user_id, result)

group_id и user_id приходят из активного каталога. Результатом является целое число.

Учитывая user_id и диапазон дат 6 дней (понедельник-суббота), которые я рассчитал на стороне бизнес-логики, и тот факт, что некоторые даты в диапазоне дат могут не иметь статистического результата для конкретного дата (т. е. день1 и день 4, возможно, ввели статистические строки для конкретной операции, но может не быть записей для дней 2, 3, 5 и 6), как я могу получить результат SQL в следующем формате? Имейте в виду, что если конкретное действие не имеет записи на конкретную дату в таблице статистики, то этот день должен возвращать 0 в результате SQL.

activity_id    group_id    day1result    day2result    day3result    day4result    day5result    day6 result
-----------    --------    ----------    ----------    ----------    ----------    ----------    -----------
sample1        Secured     0             5             1             0             2             1
sample2        Unsecured   1             0             0             4             3             2

Примечание. В настоящее время я планирую обработать это в бизнес-логике, но для этого потребуется несколько запросов (один для создания списка отдельных действий для этого пользователя для диапазона дат, и один для каждой операции, циклически повторяющейся для каждой даты для результат или отсутствие результата, чтобы заполнить 2-е измерение массива результатами, связанными с датой). Это может закончиться 50+ запросами для каждого пользователя в диапазоне дат, что кажется мне излишним.

У меня это работало в течение 4 дней, и я могу заставить его работать в течение всех 6 дней, но это кажется излишним. Есть ли способ упростить это?:

SELECT d1d2.activity_id, ISNULL(d1d2.result1,0) AS day1, ISNULL(d1d2.result2,0) AS day2, ISNULL(d3d4.result3,0) AS day3, ISNULL(d3d4.result4,0) AS day4
FROM
    (SELECT ISNULL(d1.activity_id,0) AS activity_id, ISNULL(result1,0) AS result1, ISNULL(result2,0) AS result2
     FROM
         (SELECT ISNULL(statistic_result,0) AS result1, ISNULL(activity_id,0) AS activity_id
          FROM statistic 
              WHERE user_id='jeremiah' AND statistic_date='11/22/2011'
          ) d1
          FROM JOIN
          (SELECT ISNULL(statistic_result,0) AS result2, ISNULL(activity_id,0) AS activity_id
           FROM statistic WHERE user_id='jeremiah' AND statistic_date='11/23/2011'
          ) d2
          ON d1.activity_id=d2.activity_id
     ) d1d2
     FULL JOIN
     (SELECT d3.activity_id AS activity_id, ISNULL(d3.result3,0) AS result3, ISNULL(d4.result4,0) AS result4
      FROM
          (SELECT ISNULL(statistic_result,0) AS result3, ISNULL(activity_id,0) AS activity_id
           FROM statistic WHERE user_id='jeremiah' AND statistic_date='11/24/2011'
          ) d3
          FULL JOIN
          (SELECT ISNULL(statistic_result,0) AS result4, ISNULL(activity_id,0) AS activity_id
           FROM statistic WHERE user_id='jeremiah' AND statistic_date='11/25/2011'
          ) d4
          ON d3.activity_id=d4.activity_id
     ) d3d4
     ON d1d2.activity_id=d3d4.activity_id
ORDER BY d1d2.activity_id

Ответы [ 2 ]

3 голосов
/ 23 ноября 2011

Вот типичный подход для такого рода вещей:

DECLARE @minDate DATETIME,
        @maxdate DATETIME,
        @userID VARCHAR(200)

SELECT  @minDate = '2011-11-15 00:00:00',
        @maxDate = '2011-11-22 23:59:59',
        @userID = 'jeremiah'

SELECT A.activity_id, A.group_id, 
        SUM(CASE WHEN DATEDIFF(day, @minDate, S.date) = 0 THEN S.Result ELSE 0 END) AS Day1Result,
        SUM(CASE WHEN DATEDIFF(day, @minDate, S.date) = 1 THEN S.Result ELSE 0 END) AS Day2Result,
        SUM(CASE WHEN DATEDIFF(day, @minDate, S.date) = 2 THEN S.Result ELSE 0 END) AS Day3Result,
        SUM(CASE WHEN DATEDIFF(day, @minDate, S.date) = 3 THEN S.Result ELSE 0 END) AS Day4Result,
        SUM(CASE WHEN DATEDIFF(day, @minDate, S.date) = 4 THEN S.Result ELSE 0 END) AS Day5Result,
        SUM(CASE WHEN DATEDIFF(day, @minDate, S.date) = 5 THEN S.Result ELSE 0 END) AS Day6Result
FROM activity A 
    LEFT OUTER JOIN statistic S 
        ON A.activity_id = S.activity_ID
            AND S.user_id = @userID
WHERE S.date between @minDate AND @maxDate 
GROUP BY A.activity_id, A.group_id 

Сначала я использую group by, чтобы уменьшить набор результатов до одной строки на action_id / group_id, затем использую CASE для разделения значений для каждого отдельного столбца.В этом случае я смотрю на какой день из последних семи, но вы можете использовать любую логику, чтобы определить, какая дата.Операторы case будут возвращать значение S.result, если строка для этого конкретного дня, или 0, если это не так.SUM сложит отдельные значения (или только одно, если есть только одно) и объединит их в одну строку.

Вы также заметите, что мой диапазон дат основан на полуночи первого дня диапазона и 23:59 - последнем дне диапазона, чтобы гарантировать, что все времена включены в диапазон.

Наконец, я выполняю левое соединение, поэтому у вас всегда будет 0 в столбцах, даже если статистика отсутствует.

0 голосов
/ 23 ноября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...