Getting a win streak from a database - mysql

I have followed this tutorial on trying to get a win streak from my database of bets.
The data has a result (Win/Loss/Pending) and a date (Amongst other values)
Here is the SQL command I'm using...
SELECT *
FROM (SELECT Result,
MIN(date) as StartDate,
MAX(date) as EndDate,
COUNT(*) as Games
FROM (SELECT *,
(SELECT COUNT(*)
FROM bets G
WHERE G.result <> GR.result
AND G.date <= GR.date) as RunGroup
FROM bets GR WHERE user = 4 ORDER BY date DESC) A
GROUP BY result, RunGroup
ORDER BY Min(date)) A
WHERE result = 'Win'
ORDER BY Games DESC
The only difference with mine is I'm trying to filter a single users bets and not everyones bets but...I can see in my DB that there are 3 Win's in a row but my output is 2. Can anyone spot where I have gone wrong?
I want to get one row with the largest streak, which all I think I would need to do at this point is add LIMIT 1
Thanks

If you want all sequential wins summarized in one row, then I would suggest handling this has a gaps-and-islands problem. A simple method is to count the cumulative number of non-wins. This then assigns a group to each group of wins that can be used for aggregation:
select user, grp, count(*) as num_in_sequence,
min(date), max(date)
from (select b.*,
sum(result <> 'Win') over (partition by user order by date) as grp
from bets b
) b
where result = 'Win'
group by user, grp;

This is how I did it:
SELECT * FROM (SELECT result, MIN(date) as StartDate, MAX(date) as EndDate, COUNT(*) as Games FROM (SELECT date, result, (SELECT COUNT(*) FROM bets G WHERE G.result <> GR.result AND G.date <= GR.date AND user = ${uid}) as RunGroup FROM bets GR WHERE user = ${uid} ORDER BY date) A Where result = 'Win' GROUP BY result, RunGroup ORDER BY Min(date)) A ORDER BY Games DESC LIMIT 1

Related

Mysql query - GROUP BY and show the highest COUNT(*)

I'm doing a small project and I'm trying to get the restaurant with the most votes each week to be displayed once.
This is my query:
SELECT votedRestaurant,
week,
COUNT(*)
FROM mylunch.votes
GROUP BY votedRestaurant,
week
ORDER BY week DESC;
This gets me the following result:
I would only like to have the one with the highest COUNT(*) displayed per week.
Thanks for any help.
you can try use LIMIT and ordering by count, for example
SELECT votedRestaurant,
week,
COUNT(*) AS tcount
FROM mylunch.votes
GROUP BY votedRestaurant,
week
ORDER BY tcount DESC
LIMIT 1;
Also, you can use subquery, so says the documentation.
Using Mysql 8 you can make use of window functions
WITH
cte AS (SELECT votedRestaurant, WEEK, COUNT(*) total
FROM votes
GROUP BY votedRestaurant,WEEK
ORDER BY WEEK DESC, votedRestaurant)
SELECT *
FROM (
SELECT *,
row_number() over (PARTITION BY WEEK ORDER BY total DESC) AS rn
FROM
cte
) t
WHERE rn = 1
Demo
Another way would be by using string fuctions
SELECT t.week, SUBSTRING_INDEX(GROUP_CONCAT(t.votedRestaurant ORDER BY t.total DESC),',',1) votedRestaurant, MAX(t.total)
FROM(
SELECT votedRestaurant, WEEK, COUNT(*) total
FROM votes
GROUP BY votedRestaurant,WEEK
ORDER BY WEEK DESC
) t
GROUP BY t.week
ORDER BY t.week DESC
Demo

To find the maximum number of order count that occur in any 1 hour of the day from the database?

I have a food selling website in which there is order table which record the order of every user.It column for user id ,user name,orderid ,timestamp of order.I want to know the maximum number of order that has been made in any one hour span through out the day.Give me any formula for this,or any algorithm or any sql queries for these.
SQL server:
with CTE as
(
select cast(t1.timestamp as date) as o_date, datepart(hh, t1.timestamp) as o_hour, count(*) as orders
from MyTable t1
group by cast(t1.timestamp as date), datepart(hh, t1.timestamp)
)
select o_date, o_hour, orders
from CTE
where orders = (select max(orders) from CTE)
Oracle
with CTE as
(
select to_char(t1.timestamp, 'YYYYMMDD') as o_date, to_char(t1.timestamp, 'HH24') as o_hour, count(*)
from MyTable t1
group by to_char(t1.timestamp, 'YYYYMMDD'), to_char(t1.timestamp, 'HH24')
)
select o_date, o_hour, orders
from CTE
where orders = (select max(orders) from CTE)
You can get count by day and hour like this
For SQL
SELECT TOP 1
COUNT(*)
FROM myTable
GROUP BY DATEPART(day, [column_date]), DATEPART(hour, [column_date])
ORDER BY COUNT(*) DESC;
For MySQL
SELECT
COUNT(*)
FROM myTable
GROUP BY HOUR(column_date), DAY(column_date)
ORDER BY COUNT(*) DESC
LIMIT 1;

count consecutive days (streak) and number of records for current day

The following code was taken from another question on SO. Original Q&A
I would like to count the number of consecutive days (Streak) with records since today AND also how many records were made today. I'm using this to send notifications. If a user submits a new record the same day, they should not get a second notification telling them that they are on a streak (they were made aware the first time they submitted a record for the current day).
I tried adding a COUNT() function before #streak, after the first SELECT and pretty much everywhere that seemed reasonable but this query is too complex for me to figure it out.
SELECT streak + 1 as realStreak
FROM (
SELECT dt,
#streak := #streak+1 streak,
datediff(curdate(),dt) diff
FROM (
SELECT distinct date(dt) dt
FROM glucose where uid = 1
) t1
CROSS JOIN (SELECT #streak := -1) t2
ORDER BY dt desc
)
t1 where streak = diff
ORDER BY streak DESC LIMIT 1
http://sqlfiddle.com/#!9/45d386/1/0
The result of the above should be:
realStreak | RecordsToday
3 | 3
Just add a subquery for the today check
SELECT streak + 1 as realStreak,cdt
FROM (
SELECT dt,
#streak := #streak+1 streak,
datediff(curdate(),dt) diff
FROM (
SELECT distinct date(dt) dt
FROM gl where uid = 1
) t1
CROSS JOIN (SELECT #streak := -1) t2
ORDER BY dt desc
)t1
JOIN
(SELECT COUNT(CASE WHEN DATE(dt)=CURDATE() THEN 1 END) cdt FROM gl)x
where streak = diff
ORDER BY streak DESC LIMIT 1

How to Group a table and get results for a row based on the previous rows' data

I have a lookup table that relates dates and people associated with those dates:
id, user_id,date
1,1,2014-11-01
2,2,2014-11-01
3,1,2014-11-02
4,3,2014-11-02
5,1,2014-11-03
I can group these by date(day):
SELECT DATE_FORMAT(
MIN(date),
'%Y/%m/%d 00:00:00 GMT-0'
) AS date,
COUNT(*) as count
FROM user_x_date
GROUP BY ROUND(UNIX_TIMESTAMP(created_at) / 43200)
But, how can get the number of unique users, that have now shown up previously? For instance this would be a valid result:
unique, non-unique, date
2,0,2014-11-01
1,1,2014-11-02
0,1,2014-11-03
Is this possibly without having to rely on a scripting language to keep track of this data?
I think this query will do what you want, at least it seems to work for your limited sample data.
The idea is to use a correlated sub-query to check if the user_id has occurred on a date before the date of the current row and then do some basic arithmetic to determine number of unique/non-unique users for each date.
Please give it a try.
select
sum(u) - sum(n) as "unique",
sum(n) as "non-unique",
date
from (
select
date,
count(user_id) u,
case when exists (
select 1
from Table1 i
where i.user_id = o.user_id
and i.date < o.date
) then 1 else 0
end n
from Table1 o
group by date, user_id
) q
group by date
order by date;
Sample SQL Fiddle
I didn't include the id column in the sample fiddle as it's not needed (or used) to produce the result and won't change anything.
This is the relevant question: "But, how can get the number of unique users, that have now shown up previously?"
Calculate the first time a person shows up, and then use that for the aggregation:
SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date;
I would then use this as a subquery for another aggregation:
SELECT v.date, v.NumVisits, COALESCE(fv.FirstVisit, 0) as NumFirstVisit
FROM (SELECT date, count(*) as NumVisits
FROM user_x_date
GROUP BY date
) v LEFT JOIN
(SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date
) fv
ON v.date = fv.date;

least value in count

i have a table employee(id,dept_id,salary,hire_date,job_id) . the following query i have to execute.
Show all the employee who were hired on the day of the week on which least no of employee were hired.
i have done the query, but am not able to get the least. please check if am correct.
select id, WEEKDAY(hire_date)+1 as days,count(WEEKDAY(hire_date)+1) as count
from test.employee group by days
This should get you the weekday on which the least number of employees were hired:
SELECT
count(id) as `Total`,
WEEKDAY(hire_date) as `DoW`
FROM
test.employee
GROUP BY `DoW`
ORDER BY `Total` DESC LIMIT 1;
select id from test.employee where hire_date in
( select count(id) count,hire_date
from test.employee
order by count desc
limit 1)
this should work
You may try this, as it will not limit to one record if you have multiple week days where the same least number of employees were hired. In reality it makes sense. The following is based on sample data.
Query:
-- find minimum id count
SELECT MIN(e.counts) INTO #min
FROM (SELECT COUNT(*) as counts,
WEEKDAY(hire_date+1) as day
FROM employee
GROUP BY WEEKDAY(hire_date+1)) e
;
-- show weekdays with minimum id counts
SELECT e2.counts as mincount,
WEEKDAY(e1.hire_date+1) as weekday
FROM employee e1
JOIN (SELECT COUNT(id) as counts,
WEEKDAY(hire_date+1) as day
FROM employee
GROUP BY day
HAVING COUNT(*) = #min) e2
ON WEEKDAY(e1.hire_date+1) = e2.day;
Results:
MINCOUNT WEEKDAY
1 6
1 3
1 4
1 2
SQLFIDDLE
select min(id), WEEKDAY(hire_date)+1 as days,count(WEEKDAY(hire_date)+1) as count
from test.employee group by days
SELECT
*
FROM
employee
WHERE
DAYOFWEEK(hire_date)
IN
(
SELECT
weekday
FROM
(
SELECT
count(*) as bcount,
DAYOFWEEK(hire_date) as weekday
FROM
employee as a
GROUP BY
weekday
HAVING
bcount = (
SELECT
MIN(tcount)
FROM
(
SELECT
count(*) as tcount,
DAYOFWEEK(hire_date) as weekday
FROM
employee
GROUP BY
weekday
) as t
)
) as q