Self join table current row and next row horizontally in MySQL - mysql

I am implementing a functionality wherein I have to delete current row based on values present in next row of same table.
I have records with columns: id, created_at and mark.
I need delete all records,
WHERE currentrow.mark != nextrow.mark or (currentrow.mark = nextrow.mark and currentrow.created_at= '2000-01-01 00:00:00.000')
i.e. only records with next rows have not same mark or records with next row have same mark and created_at = '2000-01-01 00:00:00.000'
id created_at mark
235 1990-01-01 00:00:00.000 5 /delete
236 1990-01-01 00:00:00.000 5 /delete
237 1990-01-01 00:00:00.000 5
238 2016-10-10 23:45:40.000 5
id created_at mark
312 1990-01-01 00:00:00.000 8 /delete
313 2016-01-09 18:00:00.000 6
314 1990-01-01 00:00:00.000 4 /delete
315 1990-01-01 00:00:00.000 7
316 2016-10-10 23:45:40.000 7
Kindly help to retrieve table every row joined next rows of same table horizontally in result set.

One way to join the next row is
INNER JOIN `tablename` AS `next` ON `next`.`id` = (
SELECT MIN(id) FROM `tablename` WHERE `tablename`.`id` > `current`.`id`
)
AND (`next`.`mark` != `current`.`mark`
OR `next`.`created_at` = '2000-01-01 00:00:00.000') // maybe 1990?

I did not understand the delete conditions completely. But I will give answer to your last question
"Kindly help to retrieve table every row joined next rows of same table horizontally in result set."
SELECT * FROM
(SELECT (#rowid1 := #rowid1 + 1) firstSeq, id firsttableid, created_at firsttablecreated_at, mark firsttablemark FROM `mytable`
JOIN (SELECT #rowid1 := 0) a) table1
LEFT JOIN (SELECT (#rowid2 := #rowid2 + 1) secondSeq, id secondtableid, created_at secondtablecreated_at, mark secondtablemark FROM `mytable`
JOIN (SELECT #rowid2 := 0) a) table2 ON table1.firstSeq = table2.secondSeq - 1 and **(your conditions)**
This will give you the result set as you need. Now you may add your required conditions to convert to delete

Related

Get original RANK() value based on row create date

Using MariaDB and trying to see if I can get pull original rankings for each row of a table based on the create date.
For example, imagine a scores table that has different scores for different users and categories (lower score is better in this case)
id
leaderboardId
userId
score
submittedAt ↓
rankAtSubmit
9
15
555
50.5
2022-01-20 01:00:00
2
8
15
999
58.0
2022-01-19 01:00:00
3
7
15
999
59.1
2022-01-15 01:00:00
3
6
15
123
49.0
2022-01-12 01:00:00
1
5
15
222
51.0
2022-01-10 01:00:00
1
4
14
222
87.0
2022-01-09 01:00:00
1
5
15
555
51.0
2022-01-04 01:00:00
1
The "rankAtSubmit" column is what I'm trying to generate here if possible.
I want to take the best/smallest score of each user+leaderboard and determine what the rank of that score was when it was submitted.
My attempt at this failed because in MySQL you cannot reference outer level columns more than 1 level deep in a subquery resulting in an error trying to reference t.submittedAt in the following query:
SELECT *, (
SELECT ranking FROM (
SELECT id, RANK() OVER (PARTITION BY leaderboardId ORDER BY score ASC) ranking
FROM scores x
WHERE x.submittedAt <= t.submittedAt
GROUP BY userId, leaderboardId
) ranks
WHERE ranks.id = t.id
) rankAtSubmit
FROM scores t
Instead of using RANK(), I was able to accomplish this by with a single subquery that counts the number of users that have a score that is lower than and submitted before the given score.
SELECT id, userId, score, leaderboardId, submittedAt,
(
SELECT COUNT(DISTINCT userId) + 1
FROM scores t2
WHERE t2.userId = t.userId AND
t2.leaderboardId = t.leaderboardId AND
t2.score < t.score AND
t2.submittedAt <= t.submittedAt
) AS rankAtSubmit
FROM scores t
What I understand from your question is you want to know the minimum and maximum rank of each user.
Here is the code
SELECT userId, leaderboardId, score, min(rankAtSubmit),max(rankAtSubmit)
FROM scores
group BY userId,
leaderboardId,
scorescode here

ierate each row and pass the values of two columns to a query and append each result to the table

I have a table with the structure below with name table1
sid userid date result
1 169110 2020-01-03 (null)
2 178662 2020-01-06 (null)
3 165381 2020-01-07 (null)
5 368031 2020-01-08 (null)
7 163626 2020-01-09 (null)
Now I need to send each row values of cft.userid and cft.date to a mysql query (query is below) which gives the value of the result for each row
UPDATE collision_fact_table cft
SET cft.on_time_completion = (
SELECT DISTINCT
CONCAT(ROUND(NULLIF(SUM(facttable.compliant), 0) / NULLIF(SUM(facttable.Occurences), 0) * 100), '%') AS `Percentage Completed`
FROM fd_dw.ComplianceFactTable facttable
WHERE (CAST(facttable.`CourseModule_dueDateID` AS date) - cft.collision_date) <= 0
AND facttable.UserLicenseInUsing = 1
AND (facttable.`CourseModule_dueDateID` > 0)
AND facttable.UserId = cft.userid
GROUP BY facttable.`UserID`);
For example, when i send first row values of userid 169110 and date value to the above query, i will get result as 69 and i need to update 69 to the table1 like below
sid userid date result
1 169110 2020-01-03 69
Similarly it should iterate for all the rows and table1 should get updated like below
sid userid date result
1 169110 2020-01-03 69
2 178662 2020-01-06 55
3 165381 2020-01-07 64
5 368031 2020-01-08 48
7 163626 2020-01-09 56
But when i tried to execute the update query, its giving me error Unknown column 'cft.date' in field list
Please anyone help me
I think you basically want a correlated subquery:
update table1 t1
set result = (
select cd.result
from ...
where
cd.ScheduleDateID <= t1.date
and cd.CourseModuleComplete_DateID <= t1.date
and cd.UserId = t1.userid
)
You don't give much details about the subquery itself. It is critical that it should return one row, and one row only:
if it returns no rows, then the result of the corresponding row in table1 will be set to null (regardless of its original value) - this might, or might not be what you want
if it returns more than one row, then the query will error

MySQL Select distinct column for each Relational_ID where largest timestamp below X

I am attempting to find all of the individual rows with a distinct or unique In_Column value for each Item_ID (our relational_id here) where Item_Table = 'X' and the Timestamp of the row is the highest for this distinct In_Column + Item_ID + Item_Table but lower than the supplied value.
sample_table
In_Column End_Value Item_Table Item_ID Timestamp
----------------------------------------------------------
Length 3 Pipe 3 2016-07-29 09:00:00
Length 2 Pipe 3 2016-07-30 09:00:00
Length 5 Pipe 4 2016-07-30 11:00:00
Kg 12 Pipe 3 2016-07-29 09:00:00
Kg 25 Steel 1 2016-07-29 09:00:00
Ideal result if supplied date was current time and Item_Table = 'Pipe'
In_Column End_Value Item_Table Item_ID Timestamp
----------------------------------------------------------
Length 2 Pipe 3 2016-07-30 09:00:00
Length 5 Pipe 4 2016-07-30 11:00:00
Kg 12 Pipe 3 2016-07-29 09:00:00
The ordering doesn't matter as I will be casting the return (which will be big, there is a lot of matching rows on the table) into an array following fetching.
Sorry for not providing an example query, I have played around with some concatenated LEFT JOINs but their execution time was understandably quite long and the result set wasn't as specific as intended.
This should work for you
SELECT
`t1`.*
FROM
`your_table` `t1`
INNER JOIN
(
SELECT
`Item_ID`,
`In_Column`,
MAX(`Timestamp`) AS `latest`
FROM
`your_table`
WHERE
`Item_Table` = 'Pipe' AND
`Timestamp` < 'Supplied Time'
GROUP BY
`Item_ID`, `In_Column`) `t2`
ON
`t1`.`Item_ID` = `t2`.`Item_ID` AND
`t1`.`In_Column` = `t2`.`In_Column` AND
`t1`.`Timestamp` = `t2`.`latest`
WHERE
`Item_Table` = 'Pipe'
Just replace your_table with correct table name.

How to compare datetime in same column in sql

I'm currently developing a function where I needto compare two datetime in a same column and if two values are equal then I need to rank it 1. If the next datetime is greater than current, I need to increment the rank to 2 and so on. I don't want to use Ranking functions as i am facing some issues when I use ranking functions. I need to take time also into account while comparing the dates. Please help me with this. Thanks in advance
Table
Date
2012-07-09 00:00:00.000
2012-07-09 00:00:00.000
2012-07-09 00:00:00.000
2014-06-01 00:00:00.000
2014-06-01 00:00:00.000
2014-06-01 00:00:00.000
2015-01-01 13:09:00.000
2015-01-01 13:09:00.000
2015-01-01 13:09:00.000
Desired Output
Date Qnum
2012-07-09 00:00:00.000 1
2012-07-09 00:00:00.000 1
2012-07-09 00:00:00.000 1
2014-06-01 00:00:00.000 2
2014-06-01 00:00:00.000 2
2014-06-01 00:00:00.000 2
2015-01-01 13:09:00.000 3
2015-01-01 13:44:00.000 4
2015-01-01 13:44:00.000 4
See if this works for you.
Usage : Select * from [dbo].usf_Rank
How it works : It builds a list of Dates in asc order and ranks them using an identity column while inserting into the helper table #Tbl in this manner :
1 D1
2 D2
3 D3
Then just inner join with the original table using the date column to expand and get the results as you wanted by returning a Table. (Using Table Valued Functions syntax )
CREATE Function [dbo].[usf_Rank]()
RETURNS #Results Table
(
D1 Datetime ,
RNK INT
)
AS
Begin
Declare #Tbl Table (ID INT IDENTITY(1,1) NOT NULL , D1 Datetime )
Declare #Tbl2 Table ( D1 DAtetime)
-- INERT INTO #Tbl2 (D1) SELECT DATE_COLUMN FROM REAL_TABLE -- I suppose this would be how you would actually use it instead of the fixed date values that I used for illustration below.
INSERT INTO #Tbl2 (D1) Values
('2012-07-09 00:00:00.000'),
('2012-07-09 00:00:00.000'),
('2012-07-09 00:00:00.000'),
('2014-06-01 00:00:00.000'),
('2015-01-01 13:44:00.000'),
('2015-01-01 13:44:00.000'),
('2014-06-01 00:00:00.000'),
('2014-06-01 00:00:00.000'),
('2015-01-01 13:44:00.000')
-- Generate the Rankings by using ID col which is identity column
insert into #Tbl select D1 from #Tbl2 group by D1 Order by D1
-- Expand by joining with orig table to get results in the format you want
insert into #Results
select t1.D1, t1.ID from #Tbl t1 inner join #Tbl2 T2 ON T1.D1 = T2.D1
RETURN
END
Go

MySQL - Union or join?

I'm trying to collect statistic data in one SQL query for the convenience of having the date sorted automatically in a union. It is really only one table but I want to count different cases of data.
The table I have looks something like this:
ID In Wanted
441 2011-03-14 0
439 2011-03-14 1
442 2011-03-14 0
428 2011-03-13 1
431 2011-03-13 1
425 2011-03-11 0
423 2011-03-11 1
420 2011-03-09 1
I get close to the desired result with this query:
SELECT * FROM
(
(SELECT date(In) n, count(date(In)) cntw, null cntl FROM items i WHERE Wanted=1 group by date(In))
union all
(SELECT date(In) n, null cntw, count(date(In)) cntl FROM items i WHERE Wanted=0 group by date(In))
) Serie
Order by n DESC
But close isn't close enough :D The result i get is this:
n cntw cntl
2011-03-14 null 2
2011-03-14 1 null
2011-03-13 2 null
2011-03-11 null 1
2011-03-11 1 null
2011-03-09 1 null
What I want is to "blend" the results on the same line, by date:
n cntw cntl
2011-03-14 1 2
2011-03-13 2 null
2011-03-11 1 1
2011-03-09 1 null
As you can see there is only ONE row for each date.
Actually the most perfect result would be to even have the missing dates in there too:
n cntw cntl
2011-03-14 1 2
2011-03-13 2 null
2011-03-12 null null
2011-03-11 1 1
2011-03-10 null null
2011-03-09 1 null
...but I guess this isn't possible.
Thank you!
select date(In) as n,
sum(case when wanted = 1 then 1 else 0 end) as cntw,
sum(case when wanted = 0 then 1 else 0 end) as cntl
from items
group by date(In)
order by n desc
You'd use a LEFT JOIN using your n field to get the dates where you have stuff... Then you'd UNION this with a query that gives you the lines where there's nothing (the info you give above doesn't allow me to help in what query this would be :D).
You want to join them, I think this will work
SELECT * FROM
(SELECT date(In) n, count(date(In)) cntw, null cntl FROM items i WHERE Wanted=1 group by date(In)) as a
LEFT JOIN
(SELECT date(In) n, null cntw, count(date(In)) cntl FROM items i WHERE Wanted=0 group by date(In)) as b
ON a.n = b.n
Order by n DESC
But I think this can be done in a single query, like this perhaps?
CREATE TABLE #tmpFoo (
SomeDate datetime,
Wanted bit
)
INSERT INTO #tmpFoo VALUES ('2011-03-11', 0)
INSERT INTO #tmpFoo VALUES ('2011-03-11', 1)
INSERT INTO #tmpFoo VALUES ('2011-03-12', 0)
INSERT INTO #tmpFoo VALUES ('2011-03-12', 1)
INSERT INTO #tmpFoo VALUES ('2011-03-14', 0)
SELECT SomeDate n,
count(NULLIF(Wanted,0)) cntw,
count(NULLIF(Wanted,1)) cntl
FROM #tmpFoo i
GROUP BY SomeDate