Помогите мне с этим SQL-запросом - PullRequest
2 голосов
/ 27 июля 2010

У меня есть таблица SQL Server CE 3.5 ( Транзакции ) со следующей схемой:

  • ID
  • TRANSACTION_DATE
  • Категория
  • Описание
  • Сумма

Запрос:

  SELECT Transaction_Date, SUM(Amount) 
    FROM Transactions 
GROUP BY Transaction_Date;

Я пытаюсь выполнить СУММУ (Сумма) и сгруппировать по транзакции_дате, чтобы получить общую сумму за каждый день, но хочу получить значения даже для дней, когда не было транзакций, поэтому в основном это запись за день без транзакций просто будет $ 0,00 за сумму.

Спасибо за помощь!

Ответы [ 5 ]

0 голосов
/ 27 июля 2010

Когда у вас есть таблица календаря (подробнее об этом позже), вы можете выполнить внутреннее объединение диапазона ваших данных, чтобы заполнить пропущенные даты:

SELECT CalendarDate, NULLIF(SUM(t.Amount),0)
FROM (SELECT CalendardDate FROM Calendar
WHERE CalendarDate>= (SELECT MIN(TransactionDate) FROM Transactions) AND
  CalendarDate<= (SELECT MAX(TransactionDate) FROM Transactions)) c
 LEFT JOIN 
    Transactions t ON t.TransactionDate=c.CalendarDate
GROUP BY CalendarDate

Чтобы создать таблицу календаря, вы можете использовать CTE:

WITH CalendarTable
AS
(
  SELECT CAST('20090601' as datetime) AS [date]
  UNION ALL
  SELECT DATEADD(dd, 1, [date])
  FROM CTE_DatesTable
  WHERE DATEADD(dd, 1, [date]) <= '20090630' /* last date */
)
SELECT [date] FROM CTE_DatesTable
OPTION (MAXRECURSION 0);

Объединяя два, мы имеем

WITH CalendarTable
AS
(
  SELECT MIN(TransactionDate) FROM Transactions AS [date]
  UNION ALL
  SELECT DATEADD(dd, 1, [date])
  FROM CTE_DatesTable
  WHERE DATEADD(dd, 1, [date]) <= (SELECT MAX(TransactionDate) FROM Transactions) 
)
SELECT c.[date], NULLIF(SUM(t.Amount),0)
FROM Calendar c
 LEFT JOIN 
    Transactions t ON t.TransactionDate=c.[date]
GROUP BY c.[date]
0 голосов
/ 27 июля 2010

Вам нужно как-то ограничить верхнюю и нижнюю границу вашего утверждения, но, возможно, это поможет.

DECLARE @Start  smalldatetime, @End smalldatetime

SELECT @Start = 'Jan 1 2010', @End = 'Jan 18 2010';

--- make a CTE of range of dates we're interested in
WITH Cal AS (
    SELECT CalDate = convert(datetime, @Start) 
    UNION ALL
    SELECT CalDate = dateadd(d,1,convert(datetime, CalDate))  FROM Cal WHERE CalDate < @End

)

SELECT CalDate AS TransactionDate, ISNULL(SUM(Amount),0) AS TransactionAmount
FROM  Cal AS C
LEFT JOIN Transactions AS T On C.CalDate = T.Transaction_Date
GROUP BY CalDate ;
0 голосов
/ 27 июля 2010

Если вы хотите, чтобы даты, в которых нет транзакций, появлялись Вы можете добавить DUMMY транзакцию на каждый день с нулевой суммой это не будет мешать SUM и будет так, как вы хотите

0 голосов
/ 27 июля 2010

Не уверен, работает ли это с CE

С общими табличными выражениями

DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME

SET @StartDate = '2010-07-10'
SET @EndDate = '2010-07-20'

;WITH Dates AS (
    SELECT  @StartDate AS DateValue
    UNION ALL
    SELECT  DateValue + 1
    FROM    Dates
    WHERE   DateValue + 1 <= @EndDate
)
SELECT      Dates.DateValue, ISNULL(SUM(Transactions.Amount), 0)
FROM        Dates
LEFT JOIN   Transactions ON
                Dates.DateValue = Transactions.Transaction_Date
GROUP BY    Dates.DateValue;

С циклом + временная таблица

DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME

SET @StartDate = '2010-07-10'
SET @EndDate = '2010-07-20'

SELECT @StartDate AS DateValue INTO #Dates

WHILE @StartDate <= @EndDate
BEGIN
    SET @StartDate = @StartDate + 1
    INSERT INTO #Dates VALUES (@StartDate)
END

SELECT      Dates.DateValue, ISNULL(SUM(Transactions.Amount), 0)
FROM        #Dates AS Dates
LEFT JOIN   Transactions ON
                Dates.DateValue = Transactions.Transaction_Date
GROUP BY    Dates.DateValue;

DROP TABLE  #Dates
0 голосов
/ 27 июля 2010

Вам нужна таблица календаря, чтобы выбрать даты.В качестве альтернативы, если у вас есть таблица чисел, вы можете эффективно превратить ее в таблицу календаря.По сути, это просто таблица с каждой датой.Создать и сгенерировать для него данные достаточно просто, и в таких ситуациях это очень удобно.Тогда вы просто используете:

SELECT
    C.calendar_date,
    SUM(T.amount)
FROM
    Calendar C
LEFT OUTER JOIN Transactions T ON
    T.transaction_date = C.calendar_date
GROUP BY
    C.calendar_date
ORDER BY
    C.calendar_date

Несколько вещей, которые нужно иметь в виду:

Если вы отправляете это во внешний интерфейс или механизм отчетов, то вам просто нужно отправить датычто у вас есть (ваш исходный запрос), и внешний интерфейс, если это возможно, сам заполняет 0,00 долларов.

Кроме того, я предположил, что дата является точным значением даты без компонента времени (следовательно,"=" в соединении).Ваша календарная таблица может содержать «start_time» и «end_time», чтобы вы могли использовать BETWEEN для работы с датами, включающими часть времени.Это избавит вас от необходимости отбирать порции времени и потенциально разрушать использование индекса.Вы также можете просто рассчитать начальную и конечную точки дня, когда вы его используете, но, поскольку это предварительно заполненная рабочая таблица, в IMO проще включить start_time и end_time.

...