Как суммировать даты с помощью SQL? - PullRequest
1 голос
/ 29 июня 2010

Посмотрите на следующий ОБНОВЛЕННЫЙ сценарий (извините, что я одурачил вас не обновленной версией - надеюсь, теперь она станет понятнее) - некоторым это может показаться простым, и, надеюсь, это так!

Объяснение: Каждая строка является Запросом. Выделено количество людей, запрошенных для какого-либо действия, общее количество - это общее количество людей в этой стране, доступное для действий, а разница - это ... разница между общим количеством людей и количеством использованных людей. И "Макс люди использовали ..." - это то, на чем все остальное держится.

SHOULD BE:                      

COLLECTION OF REQUESTS WITH DIFFERENT START- AND END DATES

COUNTRY START DATE  END DATE    ALLOCATED   TOTAL    Max people used for this period    DIFF
China     NOV 1       NOV 2       2           5         4                                 1
China     NOV 3       NOV 4       2           5         4                                 1
China     NOV 1       NOV 4       2           5         4                                 1


MY RESULT:

COLLECTION OF REQUESTS WITH DIFFERENT START- AND END DATES

COUNTRY START DATE  END DATE    ALLOCATED   TOTAL    Max people used for this period    DIFF
China     NOV 1       NOV 2       2           5         4                                 1
China     NOV 3       NOV 4       2           5         4                                 1
China     NOV 1       NOV 4       2           5         6                                -1

(For NOV 1 to NOV 4 "Max people used..." sums ALLOCATED as 2+2+2 instead of 2+2...)

И тут видно, как я получил "МОЙ РЕЗУЛЬТАТ"

SELECT DISTINCT Country.Country,
-- here comes the sum that doesn´t work...
SUM(Requests.[Amount of people per day needed]) AS [Max people used for this period]
FROM         Country INNER JOIN
                      Requests ON Country.CountryID = Requests.CountryID
WHERE     (Country.Country = 'China')
AND (Requests.[End date] >= @busyStartDate)
AND (Requests.[Start date] <= @busyEndDate)
GROUP BY Country.Country

«Максимум, что люди использовали ...» - это то, что здесь не работает - могу ли я сделать это правильно, остальное будет следовать бизнес-логике, которую вы здесь не видите: -)

UPDATE

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

Ответы [ 2 ]

1 голос
/ 29 июня 2010

Я думаю, что требуемое условие поиска будет выглядеть примерно так:

SELECT *
  FROM MyTable AS T1
 WHERE CASE 
          WHEN @start_date > T1.start_date THEN @start_date 
          ELSE T1.start_date 
       END 
       < 
       CASE 
          WHEN @end_date > T1.end_date THEN T1.end_date 
          ELSE @end_date 
       END;

... но я бы сделал много предположений о ваших данных, чтобы придумать гораздо больше, например Вы используете закрытое-открытое представление, используете ли вы значения DATETIME и т. д.?

Временный дизайн базы данных очень трудно понять правильно, и если ваш SQL DDL не верен, то ваш SQL DML действительно будет очень хитрым. Хорошая книга на эту тему - Разработка приложений для баз данных, ориентированных на время, в SQL . Автор - Рик Снодграсс, которую можно бесплатно скачать в формате PDF.

1 голос
/ 29 июня 2010

Многофункциональное решение CTE (спасибо, Мартин!)

with AllDates as (
  select  StartDate as [day] from Request
  union
  select  Enddate as [day] from Request),
TotalUsage as (
  select  [day], sum(allocated) as TotalAllocated
    from  AllDates
    join  Request
      on  [day] between StartDate and EndDate
    group by [day]),
MaxPerRequest as (
  select  CountryId, StartDate, EndDate, Allocated, MAX(TotalAllocated) as MaxAllocated
    from  Request
    join  TotalUsage
      on  [day] between StartDate and EndDate
    group by CountryId, StartDate, EndDate, Allocated
    )
select StartDate, EndDate, Allocated, MaxAllocated, Country.People - MaxAllocated as Diff
  from MaxPerRequest
  join Country on MaxPerRequest.CountryId = Country.CountryId

Старое решение для временных таблиц

Увы, я не думаю, что вы можете вкладывать CTE, поэтому вам нужно что-то вроде

with alldates as (
  select StartDate as [day] from request
  union
  select EndDate as [day] from request)
select [Day], sum(allocated) as TotalAllocated
into #TotalUsage
from alldates
join request on [Day] between StartDate and EndDate
group by [Day];

для построения общей суммы, выделенной на день для всех интересных дат, во временную таблицу. (Я никогда не могу вспомнить, какой механизм временных таблиц является лучшим для SQL Server, извините - может быть, лучше использовать переменную таблицы, и может потребоваться добавить индексы + ключи в любом случае.) Затем вы можете выбрать max (TotalAllocated) из для данного диапазона дат.

with MaxPerRequest as (
  select CountryID, StartDate, EndDate, Allocated, MAX(TotalAllocated) as MaxAllocated
    from request
    join #TotalUsage
      on [DAY] between StartDate and EndDate
    group by CountryID, StartDate, EndDate, Allocated
    )
select StartDate, EndDate, Allocated, MaxAllocated, Country.People - MaxAllocated as Diff
  from MaxPerRequest
  join Country on MaxPerRequest.CountryID = Country.CountryID

drop table #TotalUsage

Извините, я не могу придумать более простого решения.

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