SQL group by day, показывать заказы на каждый день
У меня есть таблица SQL 2005, позвоните ей Orders, в формате:
OrderID, OrderDate, OrderAmount
1, 25/11/2008, 10
2, 25/11/2008, 2
3, 30/1002008, 5
Затем мне нужно создать таблицу отчетов, показывающую упорядоченную сумму за каждый день за последние 7 дней:
Day, OrderCount, OrderAmount
25/11/2008, 2, 12
26/11/2008, 0, 0
27/11/2008, 0, 0
28/11/2008, 0, 0
29/11/2008, 0, 0
30/11/2008, 1, 5
SQL-запрос, который обычно производит это:
select count(*), sum(OrderAmount)
from Orders
where OrderDate>getdate()-7
group by datepart(day,OrderDate)
Проблема в том, что она пропускает дни, когда нет заказов:
Day, OrderCount, OrderAmount
25/11/2008, 2, 12
30/11/2008, 1, 5
Обычно я исправлял это, используя таблицу таблиц и внешнее соединение с строками, но я действительно ищу для этого более простое или более эффективное решение. Похоже, это общее требование для запроса отчета, что для этого уже должно быть доступно какое-то изящное решение.
Итак: 1. Можно ли получить этот результат из простого запроса без использования таблиц таблиц?
и 2. Если нет, можем ли мы создать эту таблицу таблиц (надежно) "на лету" (я могу создать таблицу подсчета с использованием CTE, но стек рекурсии ограничивает меня до 100 строк)?
Ответы
Ответ 1
SQL не "пропускает" даты... потому что запросы выполняются против данных, которые фактически находятся в таблице. Итак, если у вас нет DATE в таблице 14 января, тогда почему SQL покажет вам результат:)
Что вам нужно сделать, это создать временную таблицу и присоединиться к ней.
CREATE TABLE #MyDates ( TargetDate DATETIME )
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 0, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 1, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 2, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 3, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 4, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 5, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 6, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 7, 101))
SELECT CONVERT(VARCHAR, TargetDate, 101) AS Date, COUNT(*) AS OrderCount
FROM dbo.Orders INNER JOIN #MyDates ON Orders.Date = #MyDates.TargetDate
GROUP BY blah blah blah (you know the rest)
Там вы идете!
Ответ 2
У меня была та же проблема, и вот как я ее решил:
SELECT datename(DW,nDays) TimelineDays,
Convert(varchar(10), nDays, 101) TimelineDate,
ISNULL(SUM(Counter),0) Totals
FROM (Select GETDATE() AS nDays
union Select GETDATE()-1
union Select GETDATE()-2
union Select GETDATE()-3
union Select GETDATE()-4
union Select GETDATE()-5
union Select GETDATE()-6) AS tDays
Left Join (Select * From tHistory Where Account = 1000) AS History
on (DATEPART(year,nDays) + DATEPART(MONTH,nDays) + DATEPART(day,nDays)) =
(DATEPART(year,RecordDate) + DATEPART(MONTH,RecordDate) + DATEPART(day,RecordDate))
GROUP BY nDays
ORDER BY nDays DESC
Вывод:
TimelineDays, TimelineDate, Totals
Tuesday 10/26/2010 0
Monday 10/25/2010 6
Sunday 10/24/2010 3
Saturday 10/23/2010 2
Friday 10/22/2010 0
Thursday 10/21/2010 0
Wednesday 10/20/2010 0
Ответ 3
Если вы хотите увидеть нулевое значение, введите следующий запрос:
select count(*), sum(OrderAmount)
from Orders
where OrderDate>getdate()-7
and sum(OrderAmount) > 0 or sum(OrderAmount) = 0
group by datepart(day,OrderDate)
Ответ 4
В зависимости от того, как SQL Server обрабатывает временные таблицы, вы можете более или менее легко организовать временную таблицу и заполнить ее с помощью дат 7 (или это 8?), которые вас интересуют. Затем вы можете использовать это как свое таблица таблиц. Я не знаю более чистого способа; вы можете выбрать только данные, которые существуют в таблице, или которые могут быть получены из данных, которые существуют в таблице или наборе таблиц. Если есть даты, не представленные в таблице "Заказы", вы не можете выбрать эти даты из таблицы "Заказы".
Ответ 5
Так как вы захотите часто использовать эту таблицу даты в других запросах, я предлагаю вам сделать ее постоянной таблицей и создать задание для добавления дат года один раз в год.
Ответ 6
CREATE PROCEDURE [dbo].[sp_Myforeach_Date]
-- Add the parameters for the stored procedure here
@SatrtDate as DateTime,
@EndDate as dateTime,
@DatePart as varchar(2),
@OutPutFormat as int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
Declare @DateList Table
(Date varchar(50))
WHILE @SatrtDate<= @EndDate
BEGIN
INSERT @DateList (Date) values(Convert(varchar,@SatrtDate,@OutPutFormat))
IF Upper(@DatePart)='DD'
SET @SatrtDate= DateAdd(dd,1,@SatrtDate)
IF Upper(@DatePart)='MM'
SET @SatrtDate= DateAdd(mm,1,@SatrtDate)
IF Upper(@DatePart)='YY'
SET @SatrtDate= DateAdd(yy,1,@SatrtDate)
END
SELECT * FROM @DateList
END
Просто поставьте этот код и вызовите SP
Таким образом
exec sp_Myforeach_Date @SatrtDate='03 Jan 2010',@EndDate='03 Mar 2010',@DatePart='dd',@OutPutFormat=106
Спасибо
* Сувабрата Рой
ICRA Online Ltd.
Kolkata *