I have a database table events and a table bets. All bets placed for a particular event are located in the bets table while information about the event is stored in the events table.
Let's say I have these tables:
events table:
id event_title
1 Call of Duty Finals
2 DOTA 2 Semi-Finals
3 GTA V Air Race
bets table:
id event_id amount
1 1 $10
1 2 $50
1 2 $100
1 3 $25
1 3 $25
1 3 $25
I want to be able to sort by popularity aka how many bets have been placed for that event and by prize aka the total amount of money for that event.
SORTING BY PRIZE
Obviously this query doesn't work but I want to do something like this:
SELECT * FROM bets GROUP BY event_id SORT BY amount
amount from the query above should be a cumulative value of all the bet amounts for that event_id added together, so this query would return
Array (
[0]=>Array(
'event_id'=>2
'amount'=>$150
)
[1]=>Array(
'event_id'=>3
'amount'=>$75
)
[2]=>Array(
'event_id'=>1
'amount'=>$10
)
)
SORTING BY POPULARITY
Obviously this query doesn't work either but I want to do something like this:
SELECT * FROM bets GROUP BY event_id SORT BY total_rows
total_rows from the query above should be the number of rows that exist in the bets table added together, so this query would return
Array (
[0]=>Array(
'event_id'=>3
'total_rows'=>3
)
[1]=>Array(
'event_id'=>2
'total_rows'=>2
)
[2]=>Array(
'event_id'=>1
'total_rows'=>1
)
)
I wouldn't necessarily need it to return the total_rows value as I could calculate that, but it does need to be sorted by the number of occurrences for that particular event_id in the bets table.
I think count and sum are your friends here:
SELECT COUNT(event_id) AS NumberBets,
SUM(amount) AS TotalPrize
FROM bets
GROUP BY event_id
Should do the trick.
Then you can ORDER BY either the NumberBets(popularity) or TotalPrize as you need. JOIN only needed if you want event titles.
You can use SUM and COUNT aggregate functions:
SELECT
e.id AS event_id, SUM(amount) AS sum_amount
FROM [events] e
LEFT JOIN bets b
ON b.event_id = e.id
GROUP BY
e.id
ORDER BY
sum_amount DESC
SELECT
e.id AS event_id, COUNT(e.event_id) AS no_of_events
FROM [events] e
LEFT JOIN bets b
ON b.event_id = e.id
GROUP BY
e.id
ORDER BY
no_of_events DESC
Related
I have a table documenting purchases from customers, with one row per purchase:
CustomerID | ProductID
1 | 1000
1 | 2000
1 | 3000
2 | 1000
3 | 1000
3 | 3000
... | ...
I am using the following code to find the ten customers with the greatest number of overlapping products with customer #1 (first result is the one with the most overlap etc):
SELECT othercustomers.CustomerID, COUNT(DISTINCT othercustomers.ProductID)
FROM `purchases` AS thiscustomer
JOIN `purchases` AS othercustomers ON
thiscustomer.CustomerID != othercustomers.CustomerID
AND thiscustomer.ProductID = othercustomers.ProductID
WHERE thiscustomer.CustomerID = '1'
GROUP BY othercustomers.CustomerID
ORDER BY COUNT(DISTINCT othercustomers.ProductID) DESC
LIMIT 10
The code yields the expected output (Customer ID + total number of overlapping products with customer #1).
I would now like the query to exclude customers with overlapping purchases who have purchased more than 1000 different products, because these are bulk buyers who purchase the entire stock and whose purchase history therefore has no meaning when searching for customers with a similar taste.
In other words, if customer #500 had bought >1000 different products, I want him/her excluded from the results when searching for customers with a similar taste to that of customer #1 - even if customer #500 has bought all three products that customer #1 had bought and would ordinarily rank first in similarity/overlap.
I suppose some HAVING is in order, but I cannot seem to figure out what the appropriate condition is.
Thanks!
I think that HAVING won't do what you want, since it will only give you the total count of overlaping products, while you want the total count of products for the other customer.
You could filter with a correlated subquery in the WHERE clause:
SELECT othercustomers.CustomerID, COUNT(DISTINCT othercustomers.ProductID)
FROM `purchases` AS thiscustomer
JOIN `purchases` AS othercustomers ON
thiscustomer.CustomerID != othercustomers.CustomerID
AND thiscustomer.ProductID = othercustomers.ProductID
WHERE
thiscustomer.CustomerID = '1'
AND (
SELECT COUNT(DISTINCT ProductID)
FROM `purchases` AS p
WHERE p.CustomerID = othercustomers.CustomerID
) < 1000
GROUP BY othercustomers.CustomerID
ORDER BY COUNT(DISTINCT othercustomers.ProductID) DESC
LIMIT 10
For performance, you want an index on purchases(CustomerID, ProductID).
I'm trying to get sales and quantity sale by crossing two tables, group by the first one and sum from the second one.
First table has sales/operations: id_sales, sales_rep
Second table has sales details: id_sales_details, id_sales, quantity
What I need to know is how many operations had each sales_rep and what was the total quantity sum of all those sales.
This MySQL query gives me the first part:
SELECT sales.sales_rep, count(*) AS sales
from sales
Group by sales_rep
Order by sales DESC
What I cannot solve is how to add to that query the second part I need. The result should look something like:
sales_rep sales quantity
Claire 4 13
Peter 2 18
Mary 1 8
John 1 7
Here's a Fiddle to make things clearer: http://sqlfiddle.com/#!9/708234/5
SELECT s.sales_rep, count(*) AS operations, sum(d.quantity)
from sales s, sales_details d
where s.id_sales = d.id_sales
Group by s.sales_rep
Order by operations DESC;
Quick solution
SELECT w.sales_rep, w.sales, SUM(quantity) as quantity
FROM
(SELECT s.sales_rep, t.sales,d.quantity FROM sales AS s
INNER JOIN sales_details AS d ON s.id_sales = d.id_sales
INNER JOIN
(SELECT sales_rep, count(*) AS sales
from sales
Group by sales_rep
Order by sales DESC ) AS t
ON s.sales_rep = t.sales_rep) AS w
GROUP BY w.sales_rep, w.sales
ORDER BY w.sales_rep ASC
I have these two tables
The first one is expenses table and the second one is expensename
Exp_Type(first table) is the Expense name(second table) as 2 is Food
I am trying to group expense according to expense type and get data between certain dates.
This is what i have tried, but it wont work.
select
(select
(select name from EXPENSENAME where id=EXP_TYPE)as ExpenseType,
sum(PRICE) as cost
from EXPENSES WHERE USERID=1 GROUP BY EXPENSES.EXP_TYPE),
[date]
from EXPENSES where [date] BETWEEN '10-09-2015' and '10-18-2015 23:59:59'
And
select
(select name from EXPENSENAME where id=EXP_TYPE)as ExpenseType,
sum(PRICE) as cost,
date
from EXPENSES WHERE USERID=1 and DATE BETWEEN '01/10/2015' and '29/10/2015' GROUP BY EXPENSES.EXP_TYPE
With out date, i am getting result by this query but i need the same data between certain dates,please help
select
(select name from EXPENSENAME where id=EXP_TYPE)as ExpenseType,
sum(PRICE) as cost
from EXPENSES WHERE USERID=1 GROUP BY EXPENSES.EXP_TYPE
you want to join the tables together
SELECT en.name as ExpenseType, SUM(e.price) as cost
FROM expenses e
JOIN expensename en ON en.id = e.exp_type
WHERE e.date BETWEEN '10-09-2015' and '10-18-2015'
GROUP BY en.name
this should give you the cost per name
the current query you have is TERRIBLE... and this is why
SELECT (SELECT ... FROM ... WHERE ... ) as ...
this is creating a correlated subquery which is executing once for every row of the parent select. meaning if you have a table with 4 rows in it (SELECT ... FROM ... WHERE ... ) will execute 4 times scanning 16 rows (assuming its from the same table) in general that is a really really bad way to get data... if you have a million rows... well do the math, its a bad idea
I'm working on a project where I have some attendance data. I want to be able to print the top # attendees.
My query as is is set to order the list by # of events attended for each individual. I allow the user to set a limit (so, say top 50 attendees). The problem is that this doesn't do anything to account for ties, so I want to generate a rank in the query that I can then use to limit by.
My relevant schema is as follows:
Members Table:
Member Name | Member ID | # Events Attended
Events Table:
Event Name | Event ID | Other Stuff
This table is then used as a foreign key for an attendance table, which links members to events by using a foreign key that combines a Member and Event ID.
Attendance Table:
Attendance Log ID | Member FK | Event FK
So, my query as is is this:
SELECT `Member Name`, `Member ID` , COUNT( `Member ID` ) AS Attendances
FROM `Members` m
INNER JOIN
(SELECT *
FROM `Events` e
INNER JOIN `Attendance` r ON `Event ID` = `Event FK`
) er
ON `Member ID` = `Member FK`
GROUP BY `Member ID`
ORDER BY `Attendances` DESC
So, to summarize, how can I create a "rank" that I can use to limit results? So top 50 attendees is top 50 ranked attendees (so #entries >= 50), rather than 50 individuals (# entries always 50, cuts off ties).
Thanks all!
Edit1:
Sample output from query with no limit (show all results):
Member Name | Member ID | Attendances
Bob Saget 1 5
John Doe 2 4
Jane Doe 3 3
Stack Overflow 4 3
So, when users request "Show top 3 attendees" with my current query,
they would get the following:
Member Name | Member ID | Attendances
Bob Saget 1 5
John Doe 2 4
Jane Doe 3 3
when in reality, I'd like it to display the ties and show something like
Rank | Member Name | Member ID | Attendances
1 Bob Saget 1 5
2 John Doe 2 4
3 Jane Doe 3 3
3 Stack Overflow 4 3
You can try this:-
SELECT IF(Attendances = #_last_Attendances, #curRank:=#curRank, #curRank:=#_sequence) AS rank,
#_sequence:=#_sequence+1,#_last_age:=age, Member Name, Member ID,
COUNT( `Member ID` ) AS Attendances
FROM `Members` m
INNER JOIN (SELECT * FROM `Events` e
INNER JOIN `Attendance` r
ON `Event ID` = `Event FK`) er
ON `Member ID` = `Member FK`,
(SELECT #curRank := 1, #_sequence:=1, #_last_Attendances:=0) r
GROUP BY `Member Name`, `Member ID`, Rank
HAVING COUNT( `Member ID`) >= (SELECT MAX (`Member ID`)
FROM `Members`
WHERE `Member ID` < (SELECT MAX (`Member ID`)
FROM `Members`
WHERE `Member ID` < (SELECT MAX (`Member ID`)
FROM `Members`)))
ORDER BY COUNT(`Member ID`) DESC;
I think this approach will help you.
Doing this in two queries is going to be your best bet, otherwise the query gets really convoluted.
Here is a SQLFiddle showing your table schema, example data, and the queries we're talking about.
The first problem we need to break down is how to determine what the correct rank is. We can do this by doing the select but only returning a single value of the rank that is our new limit. Assuming we want the top 3 ranks we'll return only the third row (offset 2, limit 1).
# Pre-select the lowest rank allowed.
SELECT COUNT(a.attendanceId) INTO #lowestRank
FROM Member AS m
JOIN Event AS e
JOIN Attendance AS a USING (memberId, eventId)
GROUP BY m.memberId
ORDER BY 'Attendances' DESC
LIMIT 1 OFFSET 2;
Once we have the #lowestRank we can now run the query again but with a HAVING clause to restrict the GROUP BY results. By restricting only results which have a rank equal to or greater than the #lowestRank we've essentially added a LIMIT to that field.
# Return all rows of the lowest rank or above.
SELECT m.name, m.memberId, COUNT(a.attendanceId) AS 'Attendances'
FROM Member AS m
JOIN Event AS e
JOIN Attendance AS a USING (memberId, eventId)
GROUP BY m.memberId
HAVING COUNT(a.attendanceId) >= #lowestRank
ORDER BY 'Attendances' DESC;
We could have done this in one query by making the first one a JOIN of the second one, but I don't recommend that because it complicates the queries, has potential performance impact, and makes it harder to change them independently.
For example the first query only limits duplicates at the cutoff point, but if you wanted to consider all duplicates a single rank then we could change that query to only consider DISTINCT rows. In this particular data set the results would be the same, but if we had two members with four attendance then we'd still get three distinct ranks (5, 4, 4, 3, 3) versus the above query only gets two distinct ranks (5, 4, 4).
Here is my tabel structure.
id
veh_id
user_id
amount
...
I have other tables to relate the user_id and veh_id as well.
I want to know how many times a user has put an amount on each veh_id and on how many occasions, this amount is actually the highest amount received. I would like to have those 2 counts for each user available.
id, veh_id, user_id, amount
1 1 30 100
2 1 32 105
3 2 30 100
4 2 32 95
5 2 33 90
I would like the select statement to give me:
user 30 as bid 2 times and 1 time is the higest bidder
user 32 as bid 2 time ans 1 time is the higest bidder
user 33 bid 1 time and 0 time the highest bidder
I don't know if it is possible to get those numbers.
This might be close, not sure exactly how you're relating vehicles together.
select
user_id,
count(*) as num_bids,
SUM(is_highest) as max_bids
from ( select
a.user_id,
COALESCE((select
MAX(b.amount) < a.amount
from bid as b
where b.id < a.id
and b.veh_id=a.veh_id
), 1) as is_highest
from bid as a
) as c
group by user_id
My understanding is user 30 has 2 max bids (2 first bids on a vehicle).
EDIT: If you're just looking for total 1 max bid per vehicle, let me know. That's actually a lot easier than rolling back to see who's bids were max when they came in...
EDIT2: Solution for only 1 max counts per vehicle:
Seems like this should be simpler for some reason:
select
user_id,
count(*) as num_bids,
count(vamt) as num_max
from bid
left join (
select veh_id as vid, max(amount) as vamt
from bid
group by veh_id
) as a on vid = veh_id and vamt <= amount
group by user_id
Try this,
select x.user_id, x.bid_times, COALESCE(y.max_times,0) as max_times from
(select user_id, count(*) as bid_times from testt group by user_id) as x
LEFT JOIN
(select user_id, count(*) as max_times from testt a where 0=( select count(*) from testt where amount > a.amount and veh_id=a.veh_id ) group by user_id) as y
ON x.user_id=y.user_id