2009-08-13 9 views
7

Mam tabelę z informacjami o zamówieniu w sklepie e-commerce. Schemat wygląda tak:Wybierz dane z SQL DB dziennie

[Zamówienia]
Id | Razem | TAXAMOUNT | ShippingAmount | DateCreated

Tabela ta ma zawierać tylko dane dla każdego Zamówienia. Więc jeśli dzień mija bez żadnych zamówień, nie ma danych o sprzedaży za ten dzień.

Chciałbym wybrać sumę częściową na dzień z ostatnich 30 dni, w tym dni bez sprzedaży.

Zestaw wyników wyglądałby tak:

Data | SalesSum
2009-08-01 | 15235
2009-08-02 | 0
2009-08-03 | 340
2009-08-04 | 0
...

Robi to tylko daje mi dane dla tych dniach z rozkazem:

select DateCreated as Date, sum(ordersubtotal) as SalesSum 
from Orders 
group by DateCreated 

Można by utworzyć tabelę o nazwie Termin i wybrać z tej tabeli i dołącz tabelę Zamówienia. Ale naprawdę chcę tego uniknąć, ponieważ nie działa wystarczająco dobrze, gdy mamy do czynienia z różnymi strefami czasowymi i innymi rzeczami ...

Proszę nie śmiać się. SQL to nie moja rzecz ... :)

+0

Czego używasz? Odpowiedzi mogą się różnić, jeśli używasz MySQL lub SQL Server, lub czegoś innego ... – AnonJr

+0

Używam MS SQL Server – MartinHN

Odpowiedz

2

utworzyć funkcję, która może wygenerować tabelę datę następująco:
(skradziony z http://www.codeproject.com/KB/database/GenerateDateTable.aspx)

Create Function dbo.fnDateTable 
(
    @StartDate datetime, 
    @EndDate datetime, 
    @DayPart char(5) -- support 'day','month','year','hour', default 'day' 
) 
Returns @Result Table 
(
    [Date] datetime 
) 
As 
Begin 
    Declare @CurrentDate datetime 
    Set @[email protected] 
    While @CurrentDate<[email protected] 
    Begin 
    Insert Into @Result Values (@CurrentDate) 
    Select @CurrentDate= 
    Case 
    When @DayPart='year' Then DateAdd(yy,1,@CurrentDate) 
    When @DayPart='month' Then DateAdd(mm,1,@CurrentDate) 
    When @DayPart='hour' Then DateAdd(hh,1,@CurrentDate) 
    Else 
     DateAdd(dd,1,@CurrentDate) 
    End 
    End 
    Return 
End 

Następnie dołącz do tej tabeli

SELECT dates.Date as Date, sum(SubTotal+TaxAmount+ShippingAmount) 
FROM [fnDateTable] (dateadd("m",-1,CONVERT(VARCHAR(10),GETDATE(),111)),CONVERT(VARCHAR(10),GETDATE(),111),'day') dates 
LEFT JOIN Orders 
ON dates.Date = DateCreated 
GROUP BY dates.Date 
+0

Z nieznacznie zmodyfikowaną instrukcją Select, działa: WYBIERZ date.date, ISNULL (SUMA (ordersubtotal), 0) jako sprzedaż FROM [ dbo]. [DateTable] ('2009-08-01', '2009-08-31', 'day') dateLEFT JOIN Orders ON CONVERT (VARCHAR (10), Orders.datecreated, 111) = dates.dategroup według dat .date – MartinHN

+0

Zaktualizowałem drugie zapytanie. W polu wyboru/grupy miałem nieprawidłowe pole daty, więc ograniczyłem je tylko do dat sprzedaży. Przetestowałem tę wersję i myślę, że daje to, co chcesz. Ma NULL zamiast 0s przez kilka dni bez sprzedaży, ale możesz łatwo użyć funkcji COALESCE, aby je usunąć. – JamesMLV

+0

Nie mogę tego zrobić dla sera. Czy ktoś może pokazać mi dokładną poprawną odpowiedź? – philbird

2
declare @oldest_date datetime 
declare @daily_sum numeric(18,2) 
declare @temp table(
    sales_date datetime, 
    sales_sum numeric(18,2) 
) 
select @oldest_date = dateadd(day,-30,getdate()) 

while @oldest_date <= getdate() 
begin 
    set @daily_sum = (select sum(SubTotal) from SalesTable where DateCreated = @oldest_date) 
    insert into @temp(sales_date, sales_sum) values(@oldest_date, @daily_sum) 
    set @oldest_date = dateadd(day,1,@oldest_date) 
end 

select * from @temp 

OK - przegapiłem tę część "ostatnich 30 dni". Bit powyżej, choć nie tak czysty, IMHO, jako tabela daty, powinien działać. Innym wariantem byłoby użycie pętli while do wypełnienia tabeli tymczasowej tylko w ciągu ostatnich 30 dni i wykonanie lewego sprzężenia zewnętrznego z wynikiem mojego pierwotnego zapytania.

+0

Wystarczy dodać klauzulę where z ostatnich 30 dni – jdelator

+4

Nie będzie to obejmować dni, w których nie t mają jakąkolwiek sprzedaż w nich (jak pierwotnie żądano) – scwagner

+0

Gdyby było tak łatwo :) Potrzebuję każdego dnia, przez ostatnie 30 dni. – MartinHN

-1
SELECT DateCreated, 
SUM(SubTotal) AS SalesSum 
FROM Orders 
GROUP BY DateCreated 
1

włączając te dni z żadnym sprzedaży.

To trudna część. Nie sądzę, że pierwsza odpowiedź pomoże ci w tym. Zrobiłem coś podobnego do tego z oddzielną tabelą dat.

można znaleźć wskazówki, jak to zrobić tutaj:

Date Table

+0

W rzeczywistości zakładałem, że dni bez sprzedaży nie znajdą się w tabeli. Jeśli nie, zignoruj ​​moją odpowiedź. – DavidStein

+0

Nie jest. Tabela zawiera tylko dane dla każdego zamówienia. Więc jeśli dzień mija bez zamówień, nie ma danych o sprzedaży za ten konkretny dzień. – MartinHN

+1

Następnie utworzyłbym tabelę dat z wszystkimi datami, a następnie wykonałbym lewe sprzężenie z zapytaniem, które podsumowałoby sprzedaż dziennie. Należy również pamiętać, aby użyć instrukcji koalescencji, aby zwracać zero zamiast wartości zerowej w dniach bez sprzedaży. Musiałem to zrobić w wielu różnych sytuacjach, a zewnętrzna tabela daty była drogą do zrobienia. – DavidStein

0

Tak naprawdę zrobiłem to dzisiaj. Dostaliśmy także aplikację e-commerce. Nie chcę wypełniać naszej bazy danych terminami "bezużytecznymi". Po prostu robię grupę przez i tworzę wszystkie dni z ostatnich N dni w Javie i sprawdzam je z wynikami daty/sprzedaży z bazy danych.

0

Gdzie to ostatecznie się skończy? Pytam tylko dlatego, że łatwiej jest wypełnić puste dni programem, który ma zajmować się danymi, zamiast próbować zrobić to w SQL.

SQL jest wspaniałym językiem i jest zdolny do wielu różnych rzeczy, ale czasami lepiej jest pracować nad lepszymi punktami danych w programie.

1

Mam tabeli dziennika tabela z LogID indeksu, który nigdy nie usuwać żadnych rekordów. ma indeks od 1 do ~ 10000000. Korzystanie z tej tabeli można napisać

select 
    s.ddate, SUM(isnull(o.SubTotal,0)) 
from 
    (
     select 
      cast(datediff(d,LogID,getdate()) as datetime) AS ddate 
     from 
      Log 
     where 
      LogID <31 
    ) s right join orders o on o.orderdate = s.ddate 
group by s.ddate 
0

(Revised trochę - Uderzyłem wprowadzić zbyt szybko)

zacząłem grzebie przy tym, a jak trafi kilka bardzo trudnych pojęć SQL szybko przerodziła się następujące potwór. Jeśli to możliwe, lepiej dopasować rozwiązanie THEn; lub, jak wielu innych doradza, używanie kodu aplikacji do wypełniania luk może być preferowane.

-- A temp table holding the 30 dates that you want to check 
DECLARE @Foo Table (Date smalldatetime not null) 

-- Populate the table using a common "tally table" methodology (I got this from SQL Server magazine long ago) 
;WITH 
    L0 AS (SELECT 1 AS C UNION ALL SELECT 1), --2 rows 
    L1 AS (SELECT 1 AS C FROM L0 AS A, L0 AS B),--4 rows 
    L2 AS (SELECT 1 AS C FROM L1 AS A, L1 AS B),--16 rows 
    L3 AS (SELECT 1 AS C FROM L2 AS A, L2 AS B),--256 rows 
    Tally AS (SELECT ROW_NUMBER() OVER(ORDER BY C) AS Number FROM L3) 
INSERT @Foo (Date) 
select dateadd(dd, datediff(dd, 0, dateadd(dd, -number + 1, getdate())), 0) 
from Tally 
where Number < 31 

Krok 1 polega na zbudowaniu tabeli tymczasowej zawierającej 30 dat, którymi się zajmujesz. Ta abstrakcyjna dziwność jest o najszybszym znanym sposobie budowania tabeli kolejnych liczb całkowitych; dodaj kilka dodatkowych podkwerend i możesz wypełnić miliony lub więcej w zaledwie kilka sekund. Biorę pierwsze 30 i używam dateadd oraz aktualną datę/czas, aby przekonwertować je na daty. Jeśli masz już "ustalony" stół, który ma 1-30, możesz go użyć i całkowicie pominąć CTE (zastępując tabelę "Tally" swoim stołem).

Zewnętrzne dwie wywołania funkcji daty usuwają część czasu wygenerowanego ciągu.

(Zauważ, że zakładamy, że data zamówienia nie ma też część czasu - inaczej masz Innym częstym problemem do rozwiązania.)

Dla celów testowych I budowanych #Orders stole, i to dostaje się reszta:

SELECT f.Date, sum(ordersubtotal) as SalesSum 
from @Foo f 
    left outer join #Orders o 
    on o.DateCreated = f.Date 
group by f.Date 
+0

Jest to oparte na SQL Server 2005, w którym wprowadzono powszechne wyrażenia tabel (ta brzydka klauzula "Z"). Istnieją inne sposoby uzyskania tych wyników, ale CTE jest najszybszy w przypadku tabel tabel ad hoc. –

0

Stworzyłem funkcję DateTable, jak wskazał mi JamesMLV.

A potem SQL wygląda następująco:

SELECT dates.date, ISNULL(SUM(ordersubtotal), 0) as Sales FROM [dbo].[DateTable] ('2009-08-01','2009-08-31','day') dates 
LEFT JOIN Orders ON CONVERT(VARCHAR(10),Orders.datecreated, 111) = dates.date 
group by dates.date 
Powiązane problemy