select data from two rows as single row sequentially - mysql

enter image description hereAs shown in the image below, we have 6 records for same vehicle_id (3 IN,3 OUT on different dates).
I need result as :
ID vehicle_id IN OUT
1 X first_record second_record
2 x third_record fourth_record
3 x fifth_record sixth_record
So,for one record one IN time and one OUT time.
Is it possible to get with select query or do I need to write a stored proc?

You could use sub queries with a limit clause for example
drop table if exists t;
create table t(id int auto_increment primary key, vid int, trip_status varchar(3),dt datetime);
insert into t (vid,trip_status,dt)
values
(1,'in','2018-12-01 01:00:00'),
(1,'out','2018-12-01 02:00:00'),
(1,'in','2018-12-01 03:00:00'),
(1,'out','2018-12-01 04:00:00'),
(1,'in','2018-12-01 05:00:00'),
(1,'in','2018-12-01 05:00:00');
select t.*
, (select case when t1.trip_status ='out' then trip_status
else concat(t1.trip_status, '**Error**')
end
from t t1 where t1.vid = t.vid and t1.id > t.id order by t1.id limit 1) nexttrip_status
, (select t1.dt from t t1 where t1.vid = t.vid and t1.id > t.id order by t1.id limit 1) next_dt
from t where trip_status = 'in';
+----+------+-------------+---------------------+-----------------+---------------------+
| id | vid | trip_status | dt | nexttrip_status | next_dt |
+----+------+-------------+---------------------+-----------------+---------------------+
| 1 | 1 | in | 2018-12-01 01:00:00 | out | 2018-12-01 02:00:00 |
| 3 | 1 | in | 2018-12-01 03:00:00 | out | 2018-12-01 04:00:00 |
| 5 | 1 | in | 2018-12-01 05:00:00 | in**Error** | 2018-12-01 05:00:00 |
| 6 | 1 | in | 2018-12-01 05:00:00 | NULL | NULL |
+----+------+-------------+---------------------+-----------------+---------------------+
4 rows in set (0.00 sec)

Click here This image show the sql records as per your questions
This is the output as you expect.
SQL = "Select x.id, x.vehicle_id, x.time as in_time, (Select y.time from xx.new_table as y where y.id =x.id+1) as outtime from xx.new_table as x where x.id % 2 = 1"
Please note "where x.id % 2 = 1" this condition you have to make it dynamic. Sometimes you have to set = 0 or = 1 based on your ID of the record. For that, you need to write addition select SQL to check it. Hope this will help you.
Click Here To See output screen shot

Related

Update value based on value from nearest smaller neigbour

I have a table with a column A that is INT(11) (it's a timestamp, but for now I just use small numbers)
id | A | diff |
---+----+------+
1 | 12 | |
2 | 7 | |
3 | 23 | |
4 | 9 | |
5 | 2 | |
6 | 30 | |
I like to update diff with the difference between A and it's nearest smaller neighbour. So if A=12 it's first smaller neightbour is A=7, if A=30 it is A=23. I should end up with a table like this (sorted on A):
id | A | diff |
---+----+------+
5 | 2 | - |
2 | 7 | 5 | (7-5)
4 | 9 | 2 | (9-7)
1 | 12 | 3 | (12-9)
3 | 23 | 11 | (23-12)
6 | 30 | 7 | (30-23)
I can calculate the difference at the moment of insertion, as I know A then (here: A=15):
INSERT INTO `table` (`A`,`diff`)
(SELECT 15 , 15-`A` FROM `table` WHERE `A` < 15 ORDER BY `A` DESC LIMIT 1)
This results in a new record:
id | A | diff |
---+----+------+
7 | 15 | 3 | (3 being the difference between A=12 and A=15
(NOTE: This fails miserably when A=1, being the new smallest value and having no smaller neighbour, so no value of diff)
But now the value of diff in record 3 is wrong, because it still is based on the difference between 23 - 12 as is now should be 23 - 15.
So I just want to insert the A value and then run an update on the table, refreshing diff where necessery. But that's where my knowledge of MYSQL ends...
I crafted this query, but it fails saying `You can't specify table 't1' for update in FROM clause
UPDATE `table` AS t1
SET
t1.`diff` = t1.`A` - (SELECT `A` FROM `table`
WHERE `A` < t1.`A`
ORDER BY `A` DESC LIMIT 1
)
Here's a query:
SELECT x.*
, x.a-MAX(y.a) diff
FROM my_table x
LEFT
JOIN my_table y
ON y.a < x.a
GROUP
BY x.id
ORDER
BY a;
I'm not sure why you would want to store derived data, but you can I guess...
UPDATE my_table m
JOIN
( SELECT x.*
, x.a-MAX(y.a) q
FROM my_table x
JOIN my_table y
ON y.a < x.a
GROUP
BY x.id
) n
ON n.id = m.id
SET m.diff = q;
You may try this after inserting new value :
UPDATE x
SET
x.diff = iq2.new_diff
FROM
#t x
INNER JOIN
(SELECt id,A,diff , new_diff
FROM
(select id,A,15 as new_number,
CASE WHEN (A-15) < 0 THEN NULL ELSE (A-15) END as new_diff,diff
from #t
) iq
WHERE
iq.new_diff <= iq.diff
AND iq.new_diff <> 0
)iq2
on x.A = iq2.A
inner query compares the previous difference and current one and then updates the relevant ones.

Return latest entry result providing there is a review or close entry

I have a table that holds the answers to a question which is asked at entry to the system, at review periods and then at closure. The client can be opened and closed multiple times during their life on the system.
I am trying to get the latest 'entry' result from the table which also has either an associated 'review' or 'close' result.
This is my table (I have just included 1 user but the actual table has thousands of users):
row | user_id | answer | type | date_entered |
----+---------+--------+--------+--------------+
1 | 12 | 3 | entry | 2016-03-13 |
2 | 12 | 1 | review | 2016-03-14 |
3 | 12 | 7 | review | 2016-03-16 |
4 | 12 | 7 | close | 2016-03-17 |
5 | 12 | 8 | entry | 2016-03-20 |
6 | 12 | 2 | review | 2016-03-21 |
7 | 12 | 3 | close | 2016-03-22 |
8 | 12 | 1 | entry | 2016-03-28 |
So for this table the query would just return row 5 because the 'entry' on row 8 doesn't have any 'review' or 'closure' records after it.
Hopefully that makes sense.
SELECT a.*
FROM my_table a
JOIN
( SELECT x.user_id
, MAX(x.date_entered) date_entered
FROM my_table x
JOIN my_table y
ON y.user_id = x.user_id
AND y.date_entered > x.date_entered
AND y.type IN ('review','close')
WHERE x.type = 'entry'
GROUP
BY x.user_id
) b
ON b.user_id = a.user_id
AND b.date_entered = a.date_entered;
Basically you can seperate your query into two sub-queries. First query should get lastest record id (review and closure). Second query should have row_id > found_id.
SELECT *
FROM my_table
WHERE type = 'entry'
AND row_id > (SELECT Max(row_id)
FROM my_table
WHERE ( type = 'review'
OR type = 'close' ))
Please be careful about that; subquery may return zero-set.
I could think of several ways of doing it. But first a note: your date_entered field seems to be just a date. To tell which occurs "later" I'm going to use row because e.g. if both entry and review occurred on the same date, it's not possible to tell from the date_entered which one was later.
I just list a couple of solutions. The first one might be more efficient, but you should measure.
Here's a join against a subquery:
SELECT
m1.*
FROM
mytable m1
JOIN (SELECT
row, user_id
FROM
mytable
WHERE
type IN ('review', 'close') AND
user_id = 12
ORDER BY row DESC LIMIT 1) m2 ON m1.user_id = m2.user_id
WHERE
m1.user_id = 12 AND
m1.row < m2.row
ORDER BY
row DESC LIMIT 1
Here's a subquery for max:
SELECT
*
FROM
mytable
WHERE
row = (SELECT
MAX(m1.row)
FROM
mytable m1,
mytable m2
WHERE
m1.user_id = m2.user_id AND
m1.type = 'entry' AND
m2.type IN ('review', 'close') AND
m1.row < MAX(m2.row))

how to update max row per group in SQL

I just added the 'default' column to my DB. I am trying to set the default value to '1' based on the latest 'addDate' per accountId.
+----+-----------+--------------------+--------+
| id | accountId | addDate | default|
+----+-----------+--------------------+--------+
| 1 | 45 |2012-02-29 08:41:59 | |
| 2 | 55 |2012-03-29 08:41:59 | |
| 3 | 45 |2012-04-29 08:41:59 | |
| 4 | 55 |2012-05-29 08:41:59 | |
| 5 | 60 |2012-05-29 08:41:59 | |
+----+-----------+--------------------+--------+
I found I was able to isolate the proper rows by using =>
select * from tble1
where addDate = (select max(addDate) from tble1 as sl where sl.accountId = tble1.accountId);
I need to be able to run an UPDATE that sets 'default' column to '1' only 1 time per 'accountId' basing it off of latest 'addDate'.
try this
UPdate Table1
SET `default` = 1
where addDate in (select * from (
select max(addDate) from table1 as sl group by accountId)t
)
DEMO HERE
UPDATE table1 x
LEFT
JOIN table1 y
ON y.accountid = x.accountid
AND y.adddate > x.adddate
SET x.default = 1
WHERE y.id IS NULL;
or (faster)
UPDATE table1 x
JOIN
( SELECT accountid
, MAX(addDate) max_adddate
FROM table1
GROUP
BY accountid
) y
ON y.accountId = x.accountId
AND y.max_adddate = x.adddate
SET x.default = 1;

Getting unique values in sql server

I have a table say :
id| AccID | Subject | Date
1 | 103 | Open HOuse 1 | 11/24/2011 9:00:00 AM
2 | 103 | Open HOuse 2 | 11/25/2011 10:00:00 AM
3 | 72 | Open House 3 | 11/26/2011 1:10:28 AM
4 | 82 | OPen House 4 | 11/27/2011 5:00:29 PM
5 | 82 | OPen House 5 | 11/22/2011 5:00:29 PM
From the above table, i need all the unique values for the Accid. But say, if there are two or more columns with the same Accid, then i need the one which has the smaller date (among the columns which have the same Accid)
So, from the above table, the o/p should be :
1
3
5
Can any1 please help me in this ? Thanks
SELECT t1.*
FROM [MyTable] t1
INNER JOIN
(
SELECT AccID, MIN(Date) Date
FROM [MyTable]
GROUP BY AccID
) t2 ON t1.AccID = t2.AccID AND t1.Date = t2.Date
More than just the AccID but...
WITH SEL
AS
(
SELECT AccID, MIN(DATE)
FROM table
GROUP BY AccID
)
SELECT table.*
FROM table
JOIN SEL ON SEL.AccID = table.AccID

Selecting unique rows on basis of certain criteria

I have an SQL table called "trainings" that looks like this:
+-----+-----------+--------+------------+------------+------------+-------+
| Id | Booked |Coach_No| Student_No | StartDate | EndDate | Color |
+-----+-----------+--------+------------+------------+------------+-------+
| 1 | 1 | 20 | NULL | 2011-03-18 |2011-03-19 | 3 |
| 2 | 1 | 20 | 45 | 2011-03-18 |2011-03-19 | 1 |
| 3 | 1 | 15 | 41 | 2011-03-20 |2011-03-21 | 18 |
| 4 | 0 | 21 | NULL | 2011-03-22 |2011-03-23 | 3 |
| 5 | 0 | 33 | NULL | 2011-03-20 |2011-03-21 | 3 |
| 6 | 0 | 34 | NULL | 2011-03-20 |2011-03-21 | 3 |
+-----+-----------+--------+------------+------------+------------+-------+
I'm looking to frame an SQL query that will fetch all the rows with unique start and end dates. For rows with duplicate start and end dates, I need to select those with a color of 1 or 18 in preference over those with a color of 3.
I've attempted to use the query below, but the distinct row that is selected is the one with the lowest Id
SELECT * FROM trainings GROUP BY StartDate,EndDate
What is the right approach?
You could group by on StartDate, EndDate, and select two ID's for the different color priorities. Then join back to the original table, preferring the high priority:
select b1.*
from Trainings b1
join (
select max(case when Color in (1,18) then Id end) as HighPrioID
, max(case when Color not in (1,18) then Id end) as LowPrioID
from Trainings
group by
StartDate
, EndDate
) b2
on b1.Id = COALESCE(b2.HighPrioID, b2.LowPrioID);
Test data:
drop table if exists Trainings;
create table Trainings (id int, StartDate datetime, EndDate datetime, Color int);
insert Trainings values
(1,'2011-03-18','2011-03-19', 3),
(2,'2011-03-18','2011-03-19', 1),
(3,'2011-03-20','2011-03-21',18),
(4,'2011-03-22','2011-03-23', 3),
(5,'2011-03-20','2011-03-21', 3);
SELECT DISTINCT CONCAT(StartDate, EndDate) FROM trainings
If I understood it right.
Is it your mean
SELECT * FROM trainings WHERE color IN (1,18) GROUP BY StartDate,EndDate
Assuming StartDate, EndDate and Colors results in unique records ....
SELECT * FROM
From Trainings T
(
SELECT
StartDate,
EndDate,
MAX(CASE WHEN Color = 3 THEN 0 ELSE Color END) Color
From Trainings
GROUP By StartDate, EndDate
) T1 on T.StartDate = T1.StartDate AND T.EndDate = T1.EndDate AND T.Color = T1.Color
You can do something like this :
select
t1.*,
case
when t2.Id is null then 1
when t1.color in (1,18) then 2
else 3
end as priority
from trainings as t1
left join trainings as t2 on
t1.StartDate = t2.StartDate and
t1.EndDate = t2.EndDate and
t1.Id != t2.Id
order by priority
The value of priority will help you find what you want :
rows with priority 1 have unique start and end date
rows with priority 2 have 1 or 18 has color
all other rows have priority 3