Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-04 : 14:09:24
|
| I have 2 tables to track visitors to a hotel, as shown below. Is there a way to add the profits for each visit made by a customer, and then average those totals for the last 3 visits to the hotel? The ultimate goal is to set a ranking to each visitor by that average. Thank you ahead of time for your help.CREATE TABLE TripStat(ID INT,StartVisit SMALLDATETIME,EndVisit SMALLDATETIME)CREATE TABLE DayStat(ID INT,Profit INT,VisitDay SMALLDATETIME)INSERT INTO TripStat (ID, StartVisit, EndVisit)SELECT 1, '2011-01-01', '2011-01-03' UNION ALLSELECT 1, '2011-02-01', '2011-02-03' UNION ALLSELECT 1, '2011-03-01', '2011-03-03' UNION ALLSELECT 2, '2011-01-01', '2011-01-03' UNION ALLSELECT 2, '2011-02-01', '2011-02-03' UNION ALLSELECT 2, '2011-03-01', '2011-03-03' UNION ALLSELECT 2, '2011-04-01', '2011-04-03' UNION ALLSELECT 3, '2011-01-01', '2011-01-05'INSERT INTO DayStat (ID, Profit, VisitDay)SELECT 1, 2, '2011-01-01' UNION ALLSELECT 1, 5, '2011-01-02' UNION ALLSELECT 1, 3, '2011-01-03' UNION ALLSELECT 1, 9, '2011-02-01' UNION ALLSELECT 1, 5, '2011-02-02' UNION ALLSELECT 1, 4, '2011-02-03' UNION ALLSELECT 1, 20, '2011-03-01' UNION ALLSELECT 1, 25, '2011-03-02' UNION ALLSELECT 1, 30, '2011-03-03' UNION ALLSELECT 2, 900, '2011-01-01' UNION ALLSELECT 2, 1000, '2011-01-02' UNION ALLSELECT 2, 800, '2011-01-03' UNION ALLSELECT 2, 24, '2011-02-01' UNION ALLSELECT 2, 25, '2011-02-02' UNION ALLSELECT 2, 30, '2011-02-03' UNION ALLSELECT 2, 21, '2011-03-01' UNION ALLSELECT 2, 24, '2011-03-02' UNION ALLSELECT 2, 34, '2011-03-03' UNION ALLSELECT 2, 21, '2011-04-01' UNION ALLSELECT 2, 25, '2011-04-02' UNION ALLSELECT 2, 39, '2011-04-03' UNION ALLSELECT 3, 65, '2011-01-01' UNION ALLSELECT 3, 100, '2011-01-02' UNION ALLSELECT 3, 90, '2011-01-03' UNION ALLSELECT 3, 80, '2011-01-04' UNION ALLSELECT 3, 75, '2011-01-05'Ranking1 AverageTripSum >= 200 2 AverageTripSum BETWEEN 60 AND 2003 AverageTripSum BETWEEN 0 AND 60Desired Results3 rank 12 rank 21 rank 3ID 2 should not have had january trip contributing to the ranking at all. |
|
|
singularity
Posting Yak Master
153 Posts |
Posted - 2011-11-06 : 12:30:59
|
| [code]select ID, case when avg(Profit) between 0 and 60 then 3 when avg(Profit) > 60 and avg(Profit) < 200 then 2 else 1 end as rkfrom(select a.ID, a.StartVisit, a.EndVisit, sum(b.Profit) as Profit, row_number() over (partition by a.ID order by a.EndVisit desc) as rnfrom TripStat ajoin DayStat b on a.ID = b.ID and b.VisitDay between a.StartVisit and a.EndVisitgroup by a.ID, a.StartVisit, a.EndVisit) awhere rn <= 3group by ID[/code] |
 |
|
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-07 : 12:16:42
|
| Is there a way to do this without Row_Number()? My version of SQL server doesn't recognize that function. |
 |
|
|
X002548
Not Just a Number
15586 Posts |
|
|
X002548
Not Just a Number
15586 Posts |
|
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-07 : 13:39:00
|
| What I want is a single ranking based off of the total for the month, but only for the last 3 visits. I may need to tie in the visitor table too, then if you think that these tables would only give a monthly ranking. I just through the data out quickly, but some visitors may have come only once each year for the last few years, but like in visitor 2, I only wanted the most recent 3 visits, and then to disregard visits beyond that. The economy is changing enough that 3 visits tends to give a better representation of what each visitor is currently. |
 |
|
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-07 : 13:44:02
|
| I hope that better explains it.Thank you all, by the way, for your consideration. |
 |
|
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-07 : 13:47:32
|
| The reply from Singularity, from the little I know of SQL, looks like it would give me exactly what I'm looking for, if this database were on a newer version of SQL Server. |
 |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2011-11-07 : 13:57:55
|
I thought you wanted it by dates, so if I do thisSELECT ID, SUM(Profit) AS SUM_PROFIT, YEAR(VisitDay) AS [YEAR], MONTH (VisitDay) AS MONTH , MAX(VisitDay) AS MAX_Visit FROM DayStatGROUP BY ID, YEAR(VisitDay), MONTH (VisitDay) I getID SUM_PROFIT YEAR MONTH MAX_Visit----------- ----------- ----------- ----------- -----------------------1 10 2011 1 2011-01-03 00:00:001 18 2011 2 2011-02-03 00:00:001 75 2011 3 2011-03-03 00:00:002 2700 2011 1 2011-01-03 00:00:002 79 2011 2 2011-02-03 00:00:002 79 2011 3 2011-03-03 00:00:002 85 2011 4 2011-04-03 00:00:003 410 2011 1 2011-01-05 00:00:00(8 row(s) affected) Is this somewhat in the right direction?Brett8-)Hint: Want your questions answered fast? Follow the direction in this linkhttp://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspxWant to help yourself?http://msdn.microsoft.com/en-us/library/ms130214.aspxhttp://weblogs.sqlteam.com/brettk/http://brettkaiser.blogspot.com/ |
 |
|
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-07 : 14:12:23
|
| Yes, then you average them, so:ID___ AVG_SUM_Profit_ Rank----- --------------- -----1____ 34.33__________ 3____2____ 81_____________ 2____3____ 410____________ 1____ |
 |
|
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-07 : 14:15:34
|
| Again, as you can see with visitor 2, only taking the most recent 3 visits into account. |
 |
|
|
X002548
Not Just a Number
15586 Posts |
|
|
X002548
Not Just a Number
15586 Posts |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2011-11-07 : 14:56:04
|
And here are the Last 3 rowsSELECT ID, Profit, VisitDay FROM DayStat oWHERE EXISTS (SELECT * FROM DayStat i WHERE i.ID = o.ID GROUP BY ID HAVING o.VisitDay = MAX(VisitDay))UNIONSELECT ID, Profit, VisitDay FROM DayStat o WHERE EXISTS ( SELECT * FROM DayStat o1 WHERE EXISTS (SELECT * FROM DayStat i2 WHERE i2.ID = o1.ID GROUP BY ID HAVING o1.VisitDay < MAX(VisitDay)) AND o1.ID = o.ID GROUP BY ID HAVING o.VisitDay = MAX(VisitDay)) UNIONSELECT ID, Profit, VisitDay FROM DayStat o WHERE EXISTS ( SELECT * FROM DayStat o1 WHERE EXISTS ( SELECT * FROM DayStat o2 WHERE EXISTS (SELECT * FROM DayStat i3 WHERE i3.ID = o2.ID GROUP BY ID HAVING o2.VisitDay < MAX(VisitDay)) AND o2.ID = o.ID GROUP BY o2.ID HAVING o1.VisitDay < MAX(VisitDay)) AND o1.ID = o.ID GROUP BY o1.ID HAVING o.VisitDay = MAX(VisitDay)) Brett8-)Hint: Want your questions answered fast? Follow the direction in this linkhttp://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspxWant to help yourself?http://msdn.microsoft.com/en-us/library/ms130214.aspxhttp://weblogs.sqlteam.com/brettk/http://brettkaiser.blogspot.com/ |
 |
|
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-07 : 15:30:26
|
| This is actually for work, we're trying to market special offers to our best customers, and alter the offers according to how much they're making us. |
 |
|
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-07 : 16:25:31
|
quote: Originally posted by X002548
SELECT ID, SUM(Profit) AS SUM_PROFIT, YEAR(VisitDay) AS [YEAR], MONTH (VisitDay) AS MONTH , MAX(VisitDay) AS MAX_Visit FROM DayStatGROUP BY ID, YEAR(VisitDay), MONTH (VisitDay) I getID SUM_PROFIT YEAR MONTH MAX_Visit----------- ----------- ----------- ----------- -----------------------1 10 2011 1 2011-01-03 00:00:001 18 2011 2 2011-02-03 00:00:001 75 2011 3 2011-03-03 00:00:002 2700 2011 1 2011-01-03 00:00:002 79 2011 2 2011-02-03 00:00:002 79 2011 3 2011-03-03 00:00:002 85 2011 4 2011-04-03 00:00:003 410 2011 1 2011-01-05 00:00:00(8 row(s) affected)
I think we should go back to this point, because we seemed to be correct here. The later queries are confusing me. Now that we have these sums, we need to choose the 3 most recent Max_Visit dates for each visitor. |
 |
|
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-07 : 16:33:36
|
| Actually, I was looking at the output more than the query itself here, and now that I look closer at it, it doesn't actually take the trip into account, and that has to do with poor data I put in. This assumes that each visitor is only coming on one trip per month, which often isn't the case. We have some com every weekend, which amounts to multiple monthly trips. With this query the way it is, it doesn't take those weekend trips into account. |
 |
|
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-07 : 16:59:57
|
quote: Originally posted by singularity
select ID, case when avg(Profit) between 0 and 60 then 3 when avg(Profit) > 60 and avg(Profit) < 200 then 2 else 1 end as rkfrom(select a.ID, a.StartVisit, a.EndVisit, sum(b.Profit) as Profit, row_number() over (partition by a.ID order by a.EndVisit desc) as rnfrom TripStat ajoin DayStat b on a.ID = b.ID and b.VisitDay between a.StartVisit and a.EndVisitgroup by a.ID, a.StartVisit, a.EndVisit) awhere rn <= 3group by ID
Like I said earlier, I'm pretty sure singularity had it right if the company had a newer version of SQL Server, I'll walk through what I see this doing, the only problem is that I can't use the row_number() function.select ID, case when avg(Profit)--This is taking the sum of the daily profits, and averaging them, and then assigning the ranking to it between 0 and 60 then 3 when avg(Profit) > 60 and avg(Profit) < 200 then 2 else 1 end as rkfrom(select a.ID, a.StartVisit, a.EndVisit, sum(b.Profit) as Profit, row_number() over (partition by a.ID order by a.EndVisit desc) as rn -- this row_number is taking the visits, and ordering them by their most recent as the lower numbers, and doing so according the the EndVisit Datefrom TripStat ajoin DayStat b on a.ID = b.ID and b.VisitDay between a.StartVisit --Here is where it takes only the days during each visitand a.EndVisitgroup by a.ID, a.StartVisit, a.EndVisit) a--This is where it takes only the most recent 3where rn <= 3group by ID Hopefully seeing the needed aspects here will make the ultimate goal a little more clear. I do wish I had more authorities in this system, to where I could make some views that could potentially help, organize it a little cleaner, but I'm a new guy, and therefore have to do it all in one query. Again, I think this would work, if I could just get it to ohoose the most recent 3 visits from each customer. |
 |
|
|
X002548
Not Just a Number
15586 Posts |
|
|
mgonda
Starting Member
29 Posts |
Posted - 2011-11-07 : 18:06:15
|
| Thank you. I had tried running the UNION query to see exactly what it did, and let it run for 15 min, before I decided to stop it. I guess I just hadn't given it enough time.Thanks again for your help. |
 |
|
|
X002548
Not Just a Number
15586 Posts |
|
|
Next Page
|
|
|
|
|