how to get next/prev row from mysql by group - mysql

I have a table on MySQL like this:
ID Name Group
1 One A
2 Two B
3 Three A
4 Fore C
5 Five B
6 Six A
7 Seven B
I want to get the previous row/ next row in same group from my selected row. Like if I have selected row with ID=5, now how can I get the same group previous row(ID=2) when I haven't any information about the row and same with next row(ID=7).

You are looking for LEAD or LAG with Windows function, but it's was supported mysql higher version than 8.0. so you can instead write a subquery on select
look like this.
TestDLL
CREATE TABLE T(
ID int,
Name VARCHAR(100),
`Group` VARCHAR(5)
);
INSERT INTO T VALUES (1,'One','A');
INSERT INTO T VALUES (2,'Two','B');
INSERT INTO T VALUES (3,'Three','A');
INSERT INTO T VALUES (4,'Fore','C');
INSERT INTO T VALUES (5,'Five','B');
INSERT INTO T VALUES (6,'Six','A');
INSERT INTO T VALUES (7,'Seven','B');
Query
select *,IFNULL((
SELECT t2.ID
FROM T t2
WHERE t1.Group = t2.Group and t1.ID > t2.ID
ORDER BY t2.ID DESC
LIMIT 1
),t1.ID)previousID
,IFNULL((
SELECT t2.ID
FROM T t2
WHERE t1.Group = t2.Group and t1.ID < t2.ID
ORDER BY t2.ID
LIMIT 1
),t1.ID) nextID
from T t1
[Results]:
| ID | Name | Group | previousID | nextID |
|----|-------|-------|------------|--------|
| 1 | One | A | 1 | 3 |
| 2 | Two | B | 2 | 5 |
| 3 | Three | A | 1 | 6 |
| 4 | Fore | C | 4 | 4 |
| 5 | Five | B | 2 | 7 |
| 6 | Six | A | 3 | 6 |
| 7 | Seven | B | 5 | 7 |
If your mysql support windows function, you can try this.
select *,
LAG(ID)previousID,
LEAD(ID) nextID
from T
sqlfiddle

Related

Show row on mysql with this case

I have rows in my table like this
+----+-------+--------+--------------+---------------------+
| id | cid | number | value | date |
+----+-------+--------+--------------+---------------------+
| 2 | 1 | 55 | two to one | 2020-04-19 11:25:52 |
| 2 | 9 | 56 | two to nine | 2020-04-19 11:26:04 |
| 1 | 2 | 57 | one to two | 2020-04-19 11:27:02 |
| 9 | 2 | 58 | nine to two | 2020-04-19 11:28:01 |
+----+-------+--------+--------------+---------------------+
What is the sql code to show like this
+----+-------+--------+--------------+---------------------+
| id | cid | number | value | date |
+----+-------+--------+--------------+---------------------+
| 1 | 2 | 57 | one to two | 2020-04-19 11:27:02 |
| 9 | 2 | 58 | nine to two | 2020-04-19 11:28:01 |
+----+-------+--------+--------------+---------------------+
That is mean just show latest row and make the id with cid is same like id=1-cid=2 is same with id=2-cid=1. Anybody please help and i hope you are know what i mean. Thank you so much
You can use a derived table to generate a list of latest date values for each combination of id and cid values, using LEAST and GREATEST to map (for example) (1, 2) to (2, 1). This can then be JOINed to the original table to get the data for latest date:
SELECT t1.id, t1.cid, t1.number, t1.value, t1.date
FROM data t1
JOIN (
SELECT LEAST(id, cid) AS l_id,
GREATEST(id, cid) AS g_id,
MAX(date) AS max_date
FROM data
GROUP BY l_id, g_id
) t2 ON t2.max_date = t1.date
AND (t2.l_id = t1.id AND t2.g_id = t1.cid OR
t2.l_id = t1.cid AND t2.g_id = t1.id)
Output (for your sample data):
id cid number value date
1 2 57 one to two 2020-04-19T11:27:02Z
9 2 58 nine to two 2020-04-19T11:28:01Z
Demo on SQLFiddle

All Entries on Table 1 but only matching entires on table 2 where table 2 contains where statement

I have a problem joining the following tables in that Table 1 conatins all specialists ie
John (id1)
Pete (id2)
Harry (id3)
Joanne (id4)
etc
Table 2 is only populated when a specialist has availability on a certain day ie
id1 2018-10-19
id3 2018-10-19
The results I need from the MySQL query when I use the where statement table2.date=2018-10-19 is
John 2018-10-19
Pete
Harry 2018-10-19
Joanne
but what I actually get is
John 2018-10-19
Harry 2018-10-19
which is correct but I need all specialists to show in order.
Can any one help with any suggestions please
Unless your question is not a good one (and I suspect that it may be a bad one) you don't need the where statement. So
drop table if exists t1,t2;
create table t1 (id int,val varchar(10));
insert into t1 values
(1,'John' ),
(2,'Pete' ),
(3,'Harry'),
(4,'Joanne');
create table t2(t1id int,dt date);
insert into t2 values
(1 ,'2018-10-19'),
(3 ,'2018-10-19');
SELECT * from t1
LEFT OUTER JOIN t2 ON t1.id = t2.t1id
order by t1.val;
Result
+------+--------+------+------------+
| id | val | t1id | dt |
+------+--------+------+------------+
| 3 | Harry | 3 | 2018-10-19 |
| 4 | Joanne | NULL | NULL |
| 1 | John | 1 | 2018-10-19 |
| 2 | Pete | NULL | NULL |
+------+--------+------+------------+
4 rows in set (0.00 sec)
I have no idea how you would get johns,pete,harry,joanne in your result set if you wish to order by name value.
And '"&request.querystring("d")&"' is not mysql what is this php maybe?
If you are interested in the availability or otherwise for a specific date you would first cross join(creating a cartesian product) specialists to date(s) for example
select t1.id,t1.val,dt
from t1
cross join (select '2018-10-19' dt
#union all select '2018-10-20'
) s;
+------+--------+------------+
| id | val | dt |
+------+--------+------------+
| 1 | John | 2018-10-19 |
| 2 | Pete | 2018-10-19 |
| 3 | Harry | 2018-10-19 |
| 4 | Joanne | 2018-10-19 |
+------+--------+------------+
4 rows in set (0.00 sec)
and then see if they exist in table2
select t.id,t.val,t.dt tdt , ifnull(t2.dt,'Not Available') t2dt
from
(select t1.id,t1.val,dt
from t1
cross join (select '2018-10-19' dt
#union all select '2018-10-20'
) s
) t
left join t2
on t.id = t2.t1id and t2.dt = t.dt
order by t.dt,val;
+------+--------+------------+---------------+
| id | val | tdt | t2dt |
+------+--------+------------+---------------+
| 3 | Harry | 2018-10-19 | 2018-10-19 |
| 4 | Joanne | 2018-10-19 | Not Available |
| 1 | John | 2018-10-19 | 2018-10-19 |
| 2 | Pete | 2018-10-19 | Not Available |
+------+--------+------------+---------------+
Note you can have any number of dates in the cross join by using union. I have 2018-10-20 commented out.
If you have a large range of dates union may become unwieldy and creating a calendar/dates table in your db may be useful and you would substitute that in the cross join. for example
select t.id,t.val,t.dt tdt , ifnull(t2.dt,'Not Available') t2dt
from
(select t1.id,t1.val,dt
from t1
cross join (select dte dt from dates where dte between '2018-10-19' and '2018-10-19'
) s
) t
left join t2
on t.id = t2.t1id and t2.dt = t.dt
order by t.dt,val;
You can of course amend the cross join where condition to whatever you want.

I need to get the average for every 3 records in one table and update column in separate table

Table Mytable1
Id | Actual
1 ! 10020
2 | 12203
3 | 12312
4 | 12453
5 | 13211
6 | 12838
7 | 10l29
Using the following syntax:
SELECT AVG(Actual), CEIL((#rank:=#rank+1)/3) AS rank FROM mytable1 Group BY rank;
Produces the following type of result:
| AVG(Actual) | rank |
+-------------+------+
| 12835.5455 | 1 |
| 12523.1818 | 2 |
| 12343.3636 | 3 |
I would like to take AVG(Actual) column and UPDATE a second existing table Mytable2
Id | Predict |
1 | 11133
2 | 12312
3 | 13221
I would like to get the following where the Actual value matches the ID as RANK
Id | Predict | Actual
1 | 11133 | 12835.5455
2 | 12312 | 12523.1818
3 | 13221 | 12343.3636
IMPORTANT REQUIREMENT
I need to set an offset much like the following syntax:
SELECT #rank := #rank + 1 AS Id , Mytable2.Actual FROM Mytable LIMIT 3 OFFSET 4);
PLEASE NOTE THE AVERAGE NUMBER ARE MADE UP IN EXAMPLES
you can join your existing query in the UPDATE statement
UPDATE Table2 T2
JOIN (
SELECT AVG(Actual) as AverageValue,
CEIL((#rank:=#rank+1)/3) AS rank
FROM Table1, (select #rank:=0) t
Group BY rank )T1
on T2.id = T1.rank
SET Actual = T1.AverageValue

MySQL select from specific ID until match condition

Given this table:
+----+-----------+--------+
| id | condition | values |
+----+-----------+--------+
| 1 | a | 1 |
+----+-----------+--------+
| 2 | a | 2 |
+----+-----------+--------+
| 3 | a | 3 |
+----+-----------+--------+
| 4 | a | 4 |
+----+-----------+--------+
| 5 | b | 5 |
+----+-----------+--------+
| 6 | b | 6 |
+----+-----------+--------+
How can I get a new table that begins on id=3 (including) and goes until condition = b (excluding):
+----+-----------+--------+
| id | condition | values |
+----+-----------+--------+
| 3 | a | 3 |
+----+-----------+--------+
| 4 | a | 4 |
+----+-----------+--------+
added fiddle: http://sqlfiddle.com/#!2/9882f7
Basically I want a table between a matching first condition (over a specific column - id) and a second one (over a different column - condition)
You need to stop thinking of SQL data as having any order. Think of SQL data in sets; you have to search by values, not by positions.
SELECT t1.*
FROM t AS t1
JOIN (
SELECT MIN(id) AS id FROM t
WHERE id >= 3 AND `condition` = 'b'
) AS t2
WHERE t1.id >= 3 AND t1.id < t2.id
ORDER BY t1.id
Something like this:
select t.*
from table t
where id >= 3 and id < (select min(t2.id) from table t2 where t2.condition = 'b');
EDIT:
This query works fine on the SQL Fiddle:
select t.*
from t
where id >= 3 and id < (select min(t2.id) from t t2 where t2.condition = 'b');
If I understand what you are asking for, I believe this will work for you:
SELECT id, condition, values
FROM tableName
WHERE id > 2
AND condition != b
ORDER BY id
I hope that works for you.

MySQL query to select group of IDs from one table, depending on query on a second table

I am sure this would be easy to google if I knew the right words to use, but I've tried and not come up with anything: apologies if this is a common question on SO.
I have one table which lists a set of records which can be one of 4 types.
table_1:
+-------+------------+------+
| id | value | type |
+-------+------------+------+
| 1 | x | 1 |
| 2 | y | 1 |
| 3 | z | 2 |
| 4 | a | 3 |
+-------+------------+------+
I have another table which references the id of this table and stores data
table_2:
+-------+------------+------+
| id | table_1_id |value |
+-------+------------+------+
| 1 | 4 | A |
| 2 | 2 | B |
| 3 | 3 | C |
| 4 | 2 | D |
+-------+------------+------+
I want to write a query that effects:
"Find all the records from table 1 which are of type 1, take the id's of those records, and find all the records in table 2 where 'table_1_id' which match one of that set of ids."
In the above very oversimplified table example that would result in the query returning records with ids 2 and 4 in table 2
Sounds like your looking for IN:
select *
from table2
where table_1_id in (select id from table1 where type = 1)
Or perhaps you could JOIN the tables:
select t2.*
from table2 t2
join table1 t1 on t2.table_1_id = t1.id
where t1.type = 1
Joining the tables could result in duplicate records. Depends on your needs.
SELECT t1.value,t1.type,t2.value FROM table1 t1,table2 t2 WHERE t1.id = t2.table_1_id AND t1.type = 1;