views:

90

answers:

2

I'm using SQL-Server 2005

I have two tables, Users and Orders. Each user can have many orders. Tables connected via userID. Orders has date column ( which is when order was made ). Users have registrationSite column ( which is who is the affiliate site behind user and all of his orders ).

I want to select sum of orders per day and site so even if site haven't sold or user registred i will have 0 as sum value.

this is current query which misses the highlighted part.

select sum(orderSum)*40/100-0.17,count(*),
registrationSite,
dateadd(dd,datediff(dd,0,cu.date),0)
from Users cu 
inner join Orders cp 
on cu.userID=cp.userID
group by dateadd(dd,datediff(dd,0,cu.date),0),registrationSite
order by dateadd(dd,datediff(dd,0,cu.date),0),registrationSite
+3  A: 
Gaby
If no user registered on certain date left join wouldn't help me at all.
eugeneK
@eugeneK, updated with more info..
Gaby
@Gaby, thanks for this but this kind of solution i was trying to avoid but if no other better answer would be given i will use that... bth pretty neat trick with CTE in your link
eugeneK
+1  A: 

If you are using SQL 2005 or later, you can build your Calendar table on the fly using a common-table expression. In your original post, you are doing your date math on cu.date but the alias cu represents the Users table not the Orders table. I'm assuming that this was supposed to have been cp.date? I.e., your description talks about order dates but your SQL uses a date in the Users table.

With OrderDateBoundaries As
    (
    Select Cast(DateDiff(d,0,Min([Date]))) As MinDate
        , Cast(DateDiff(d,0,Max([Date]))) As MaxDate
    From Orders
    )
    , Calendar As
    (
    Select MinDate As [Date]
    From OrderDateBoundaries
    Union All
    Select DateAdd(d, 1, [Date])
    From Calendar
    Where [Date] <= DateAdd(d, 1, (
                                    Select MaxDate
                                    From OrderDateBoundaries
                                    ))
    )
Select Calendar.[Date]
    , Coalesce(Sum(O.ordersum) * 40 / 100 - 0.17,0) As OrderSum
    , Count(*)
    , RegistrationSite
From Calendar
        Left Join (Users As U
            Join Orders As O
                On O.userId = U.UserId)
             On Cast(DateDiff(d, 0, O.OrderDate) As datetime) =Calendar.Date
Group By Calendar.[Date], registrationsite
Option(MaxRecursion 0);

If it is the case that you do want to join on Users.Date, then it is a simple change to do that . In addition, it is not clear from which table ordersum is stored.

With DateBoundaries As
    (
    Select Cast(DateDiff(d,0,Min([Date]))) As MinDate
        , Cast(DateDiff(d,0,Max([Date]))) As MaxDate
    From Users
    )
    , Calendar As
    (
    Select MinDate As [Date]
    From DateBoundaries
    Union All
    Select DateAdd(d, 1, [Date])
    From Calendar
    Where [Date] <= DateAdd(d, 1, (
                                    Select MaxDate
                                    From DateBoundaries
                                    ))
    )
Select Calendar.[Date]
    , Coalesce(Sum(O.ordersum) * 40 / 100 - 0.17,0) As OrderSum
    , Count(*)
    , RegistrationSite
From Calendar
        Left Join (Users As U
            Join Orders As O
                On O.userId = U.UserId)
             On Cast(DateDiff(d,0,U.Date) As datetime) =Calendar.Date
Group By Calendar.[Date], RegistrationSite
Option(MaxRecursion 0);
Thomas
@Thomas, first of all thanks for proper reply. The OrderSum is stored within Orders table.
eugeneK
@Thomas, cu or cp on date gives the same results because each day there is a user registered same as there is at least one order. So it doesn't matter in this case because at least one record of each single day appears in both tables, though you are right abouts semantics.
eugeneK
@Thomas, your query doesn't run at all. Gives me 2 errors
eugeneK
@eugeneK - There were two typos and one oversight which I've fixed. I was missing an ending parenthesis on Min([Date]) and I had the alias of MaxDate twice. The oversight was not using the MaxRecursion option which is needed on the calendar CTE. If you don't use this and the number of days goes over the default of 100 recursive cycles, it will throw an error.
Thomas
@Thomas, thanks for the fix and i did in fact fixed those things myself but main error remains the same...Msg 156, Level 15, State 1, Line 27Incorrect syntax near the keyword 'Group'.
eugeneK
@eugeneK - Another typo on my part. The problem is that there is a missing ON clause which I accidentally incorporated into `AND U.Date =Calendar.Date`. Have corrected both queries.
Thomas
@Thomas, right! now the query works but give wrong results.It gives me all sales which were made at certain hour of the day instead of whole day. ie. 2010-07-23 13:07:00
eugeneK
@Thomas, moreover it gives results of future days. ie. 2010-07-29 13:07:00 Odd ah?
eugeneK
@eugeneK - Arg. One last correction. We need to convert the order/registration date to a day value. I've updated my post. In short, you need to strip the time. In my case, I typically use `Cast(DateDiff(d,0,SomeDate) as datetime)`. However, I have also seen people use `Cast(Floor(Cast(SomeDate As float)) As datetime)`
Thomas
@Thomas, there is slight problem with it since i will need to cast that at join's on condition which is probably impossible.Any other ideas?
eugeneK
@Thomas, i've added same cast to Calendar to get day min/max values so join would be valid.Now, the query doesn't do what it intended to. It still shows me sites with at least one order only. There is no row for sites with 0 orders.
eugeneK
@eugeneK - You do not need to do the cast on the Calendar CTE. You can simply do it on the "boundaries" CTE (i.e. the first one in each of the two queries). You just need the start date to have the time stripped and all dates generated by the Calendar will be then also have their time stripped (or set to zero to be specific).
Thomas