SQL группа по дням, показывает заказы на каждый день - PullRequest
14 голосов
/ 01 декабря 2008

У меня есть таблица 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 строк)?

Ответы [ 6 ]

10 голосов
/ 01 декабря 2008

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 голосов
/ 26 октября 2010

У меня была такая же проблема, и вот как я ее решил:

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
1 голос
/ 22 августа 2010

Если вы хотите увидеть нулевое значение, поставьте следующий запрос:

select count(*), sum(OrderAmount)
from Orders
where OrderDate>getdate()-7
  and sum(OrderAmount) > 0 or sum(OrderAmount) = 0
group by datepart(day,OrderDate)
0 голосов
/ 23 декабря 2010
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

Просто поставьте этот код и позвоните в ИП Таким образом

exec sp_Myforeach_Date @SatrtDate='03 Jan 2010',@EndDate='03 Mar 2010',@DatePart='dd',@OutPutFormat=106

Спасибо * Сувабрата Рой ICRA Online Ltd. Kolkata *

0 голосов
/ 02 декабря 2008

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

0 голосов
/ 01 декабря 2008

В зависимости от того, как SQL Server обрабатывает временные таблицы, вы можете более или менее легко организовать создание временной таблицы и заполнить ее интересующими вас 7 (или теми 8?) Датами. Затем вы можете использовать это как Счетный стол. Я не знаю более чистого пути; Вы можете выбрать только те данные, которые существуют в таблице или могут быть получены из данных, которые существуют в таблице или наборе таблиц. Если в таблице «Заказы» имеются даты, вы не можете выбрать эти даты из таблицы «Заказы».

...