Previous records in mysql - mysql

id game_id user_id user_playing_status user_turn_status
1 1 2 1 1
2 1 4 1 0
3 1 6 1 0
How can we access previous record of current record ?
If there are three records r1,r2,r3 in table
so previous record of r2 should be r1 , r3 should be r1 and r1 should be r3.
I use the following query
select user_id
from current_playing_users
where id < (select id from current_playing_users where user_id = 2)
But i am not getting previous record of first record.I want to get records in anticlockwise manner. Like in image previous user_id of 2 should be 6

Are looking you for the correlated subquery ? :
select cu.*.
(select cu1.user_id
from current_playing_users cu1
where cu1.id < cu.id
order by cu1.id desc
limit 1
) as prev_user_id
from current_playing_users cu;

you could use LAG function
select LAG(user_id) over (order by {your desired order}) as previous_row
from ..
LAG function return the former cell at the desired column with a pre-defined order.

Related

get 1st and 2nd highest vlaue rows in case of similar values

I have a table with the columns : id, status, value.
id status value
-- ------ -----
1 10 100
2 10 100
3 10 60
4 11 20
5 11 15
6 12 100
7 12 50
8 12 50
I would like to get the id and value of the first and second highest valued rows, from each status group. My table should have the following columns:
status, id of the first highest value, first highest value, id of second highest value, second highest value.
I should get:
status 1stID 1stValue 2ndID 2ndValue
------ ----- -------- ----- --------
10 1/2 100 2/1 100
11 4 20 5 15
12 6 100 7/8 50
I tried all kinds of solutions, but I couldn't find a solution for same-value 1st s (two rows with the same value, which happened to be the highest in that status group) or same-value seconds.
For example, in case of two rows sharing the highest value in their status group, this not-so-elegant query will return two rows with the same status, different 1sts and same 2nd:
SELECT 2nds.status, 1sts.id AS "1stID",1sts.value AS "1stValue",
2nds.id AS "2ndID",2nds.value AS "2ndValue"
FROM
(SELECT v.* FROM
(SELECT status, MAX(value) AS "SecMaxValue" FROM table o
WHERE value < (SELECT MAX(value) FROM table
WHERE status = o.status
GROUP BY status) AS m
INNER JOIN table v
ON v.status = m.status AND v.value = m.SecMaxValue) AS 2nds
INNER JOIN
(SELECT v.* FROM
(SELECT status, MAX(value) AS maxValue FROM table
GROUP BY status) AS m
INNER JOIN table v
ON v.status = m.status AND v.value = m.MaxValue) AS 1sts
ON 1sts.status = 2nds.status ;
This query will give me:
status 1stID 1stValue 2ndID 2ndValue
------ ----- -------- ----- --------
10 1 100 3 60
10 2 100 3 60
11 4 20 5 15
12 6 100 7 50
12 6 100 8 50
To conclude, I would like to find a solution in which:
a. if there are two rows with the highest value the query puts the details one of them in the column of the 1st and the details of other in 2nd (no mather which)
b. if there are two rows with the second highst value it puts the highest in its place and one of the seconds in the second place.
Is there a way to change the query above? someone has a nicer solution?
I came across several 1st and 2nd queries but they had the same problem - for example this solution: Finding the highest n values of each group in MySQL. it does not deliver 1st and 2nd in the same row, but the main problem it provides only one of the firsts.
Thanks
After spent a lot of time, finally I found a solution for above problem. Please try it out:
select 1st.status as Status,
SUBSTRING_INDEX(1st.id,'/',1) as 1stID,
1st.value as 1stValue,
(case when locate('/',1st.id) > 0 then SUBSTRING_INDEX(1st.id,'/',-1)
else 2nd.id
end) as 2ndID,
(case when locate('/',1st.id) > 0 then 1st.value
else 2nd.value
end) as 2ndValue
from
(
(select status, SUBSTRING_INDEX(Group_concat(id separator '/'),'/',2) as id,value
from t1
where (status,value) in (select status,value
from t1
group by status
having max(value))
group by status) 1st
inner join
(select status,id,value
from t1
where (status,value) not in (select status,value
from t1
group by status
having max(value))
group by status,value
order by status,value desc) 2nd
on 1st.status = 2nd.status)
group by 1st.status;
Just replace t1 with your tablename and it should work like a charm.
Click here for Updated Demo
If you have any doubt(s), feel free to ask.
Hope it helps!

MySQL status_id changed over time select just the latest based on the needed status

I know this sounds a little bit strange but I don't really know how to explain this better without an example.
I have the following table
ID contract_id status_id created
1 1 1 2015-10-14
2 1 2 2015-10-15
3 1 1 2016-02-02
4 1 4 2017-03-01
If the query is something like
SELECT * FROM table WHERE status_id = 1 AND created BETWEEN 2015-10-10 AND 2017-03-05
The item with contract_id = 1 should not display because the latest status in that date interval is 4
But if the query is something like this
SELECT * FROM table WHERE status_id = 1 AND created BETWEEN 2015-10-10 AND 2017-02-28 the item with contract_id 1 should show up because the latest status_id = 1
Basically what I need is something like this: Get me the latest item if the status_id = 1 at the end date
I know this is quite simple but I running around in circles right now. I did try abs(datediff(end, start)), select based on if or select in select but I am not getting the result I am looking for.
Thank you very much for your help.
One of the approaches would be to use an INNER JOIN of the latest date a given contract_id had the required status, and test if the date is earlier than the border date:
EDIT: After further reading the comments, most probably this one will do exactly what you need
SELECT t.*
FROM statuses AS t
INNER JOIN (
SELECT max(id) AS lastid, max(created) AS lastdate
FROM statuses
WHERE status_id = 1 AND created < '2016-01-01'
GROUP BY contract_id
) AS latest ON t.ID = latest.lastid
Note that it will work only if the dates are put in chronologically, in other words that for every contract_id: ID' < ID'' ≡ created' < created''
Oracle :
SELECT * FROM table WHERE status_id = 1 AND created BETWEEN 2015-10-10 AND 2017-03-05 AND ROWNUM <=1 ORDER BY created desc
MySQL :
SELECT * FROM table WHERE status_id = 1 AND created BETWEEN 2015-10-10 AND 2017-03-05 ORDER BY created desc LIMIT 1
SQL Server :
SELECT TOP 1 FROM table WHERE status_id = 1 AND created BETWEEN 2015-10-10 AND 2017-03-05 ORDER BY created desc
I understood your question as that you want an item with status_id = 1 and which has most recent created date

Distinct outside group in sql

I have a table called order_status_log, which logs who changed order statuses.
Simplified table and query below:
order_id user_id status time
1 1 1 2016-01-27 19:35:44
2 2 2 2016-01-27 19:36:45
4 3 2 2016-01-27 19:37:43
2 1 5 2016-01-27 19:38:41
I also have SQL which counts changes by each user:
SELECT
COUNT(*) as count,
user_id
FROM order_status_log
WHERE status = 1
GROUP BY user_id
ORDER BY count
Now I want to improve my query to count only first status changes in order.
In other words I need unique order_id with older time.
How I can change my query to do that?
Something like this?
SELECT *
FROM order_status_log o
WHERE NOT EXISTS
( SELECT 'x'
FROM order_status_log o2
WHERE o2.user_id = o.user_id
AND o2.time < o.time)

SQL Query to return rows where a column value appears multiple time

I'm creating a simple database which will allow me to track snooker results, producing head to head results between players. Currently I have 3 tables: (Player, Fixture, Result)
PlayerID PlayerName
1 Michael Abraham
2 Ben Mullen
3 Mark Crozier
FixtureID Date TableNo Group
1 07/12/2015 19:00:00 12 0
2 08/12/2015 12:00:00 9 0
ResultID FixtureID PlayerID FramesWon
1 1 1 3
2 1 3 1
3 2 1 5
4 2 2 1
I would like a query which returns all rows in the result table for fixtures which took place between players 1 and 3. Currently my query is:
SELECT *
FROM Result
WHERE PlayerID IN (1,3);
This returns the first 3 rows of the result table - when I'm only looking for the top 2 rows because they share the same FixtureID. Is there an easy way to remove the third row from this query result, or should I reconsider my database design? Any help would be appreciated.
One solution is to use a GROUP BY query, grouping by FixtureID and counting the rows for each FixtureID. This query will select all FixtureIDs with both players 1 and 3:
select
FixtureID
from
Results
where
PlayerID IN (1,3)
group by
FixtureID
having
count(*)=2
then to get the record from the Results table you can use this query:
select *
from Results
where FixtureID IN (
select FixtureID
from Results
where PlayerID IN (1,3)
group by FixtureID
having count(*)=2
)
You could join your fixtures table twice, like this:
select
*
from
Result as R1
join Result as R2 on R1.FixtureID = R2.FixtureID
where
R1.PlayerID in (1,3)
AND R2.PlayerID in (1,3)
AND R1.PlayerID != R2.PlayerID
group by
R1.FixtureID
;
Or, since it's a bit messy now, show it like a snooker score display often is shown:
select
R1.FixtureID, R1.PlayerID as player1, R1.FramesWon as player1_frames, R1.FramesWon+R2.FramesWon as total_frames, R2.FramesWon as player2_frames, R2.PlayerID as player2
from
Result as R1
join Result as R2 on R1.FixtureID = R2.FixtureID
where
R1.PlayerID in (1,3)
AND R2.PlayerID in (1,3)
AND R1.PlayerID != R2.PlayerID
group by
R1.FixtureID
;

MySQL query, COUNT and SUM with two joined tables

I need a little help with a MySQL query.
I have two tables one table is a list of backlinks with a is_homepage (bool) flag. The second table is a list of the domains for all of the backlinks, a was link_found (bool) flag, and a url_count column which is the number of rows in the backlinks table that are associated with each domain.
Note that the domain_id column is the foreign key to the domain table id column. Heres some sample data.
backlinks
id domain_id is_homepage page_href
1 1 1 http://ablog.wordpress.com/
2 1 0 http://ablog.wordpress.com/contact/
3 1 0 http://ablog.wordpress.com/archives/
4 2 1 http://www.somewhere.org/
5 2 0 http://www.somewhere.org/page=3
6 3 1 http://www.great-fun-site.com/
7 3 0 http://www.great-fun-site.com/index.html
8 4 0 http://red.blgspot.com/page=7
9 4 0 http://blue.blgspot.com/page=9
domains
id url_count link_found domain_name
1 3 1 wordpress.com
2 2 0 somewhere.org
3 2 1 great-fun-site.com
4 2 1 blgspot.com
The results Im looking to get from the above data would be: count = 2, total = 5.
Im trying to get the count of rows from the domains table (count) and then the sum of the url_count (total) from the domains table WHERE link_found is 1 and where one of the links in the backlink table is_homepage is 1.
Here's the query I'm trying to work with.
SELECT SUM(1) AS count, SUM(`url_count`) total
FROM `domains` AS domain
LEFT JOIN `backlinks` AS link ON link.domain_id = domain.id
WHERE domain.id IN (
SELECT DISTINCT(bl.domain_id)
FROM `backlinks` AS bl
WHERE bl.tablekey_id = 11
AND bl.is_homepage = 1
)
AND domain.link_found = 1
AND link.is_homepage = 1
GROUP BY `domain`.`id`
The problem with this query is that it returns a row for each entry in the domains table. I think I might need one more sub query to add up the returned results but I'm not sure if that's correct. Does anyone see what I'm doing wrong? Thank you!
EDIT:
The problem I'm having is that if there are more than one homepage in the back-links table then its counted multiple times. I need to only count each domain once.
Well, you shouldn't have to do a group by as you are not selecting anything other than aggregated fields. I'm no mysql expert, but this should work:
SELECT count(d.id) as count, sum(d.url_count) as total from domains as d
inner join backlinks as b
on b.domain_id = d.id
Where d.Link_found = 1 and b. is_homepage = 1
The reason you're getting a row for each entry in the domains table is that you're grouping by domain.id. If you want grand totals only, just leave off the GROUP BY piece.
I think a fairly simple query will do the trick:
SELECT COUNT(*), SUM(domains.URL_Count)
FROM domains
WHERE domains.link_found = 1 AND domains.id IN (
SELECT domain_id FROM backlinks WHERE is_homepage = 1)
There's a working SQLFiddle here.
Thanks for the help. Sorry it was so hard to explain I need a MySQL fiddle :)
If anyones interested heres what I ened up with:
SELECT SUM(1) AS count, SUM(total) AS total
FROM
(
SELECT SUM(`url_count`) total
FROM `domains` AS domain
LEFT JOIN `backlinks` AS link ON link.domain_id = domain.id
WHERE domain.id IN (
SELECT DISTINCT(bl.domain_id)
FROM `backlinks` AS bl
WHERE bl.tablekey_id = 11
AND bl.is_homepage = 1
)
AND domain.link_found = 1
AND link.is_homepage = 1
GROUP BY `domain`.`id`
) AS result