MySQL select from specific ID until match condition - mysql

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.

Related

how to get next/prev row from mysql by group

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

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 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;

MySQL fetching rows based on condition within condition

I have the following below
---------------------------------
| Id | Value | Flag |
---------------------------------
| 1 | 23 | 0 |
---------------------------------
| 1 | 24 | 1 |
---------------------------------
| 2 | 30 | 0 |
---------------------------------
I require a query, which should fetch the last two rows. The condition here is IF two rows have the same Id then the output should fetch the row which has flag = 1 . Where as If there is only one row for an Id, then the row with Flag = 0 should be fetched. Thus the output for the given requirement will be
---------------------------------
| 1 | 24 | 1 |
---------------------------------
| 2 | 30 | 0 |
SELECT
*
FROM yourTable yt1
WHERE Flag = (SELECT MAX(Flag) FROM yourTable yt2 WHERE yt1.Id = yt2.Id)
GROUP BY Id
Other answers looks correct to me. This is a different approach:
SELECT t1.*
FROM
yourtable t1 LEFT JOIN yourtable t2
ON t1.Id = t2.Id AND t1.Flag=0 AND t2.Flag=1
WHERE
t2.Id IS NULL
Please see fiddle here.
I prefer an uncorellated approach...
SELECT x.*
FROM my_table x
JOIN
( SELECT id,MAX(flag) max_flag FROM my_table GROUP BY id ) y
ON y.id = x.id
AND y.max_flag = x.flag;

how is "USING" and "ON" keywords are useful in this code

SELECT table1.PrimaryKey(Some ID), table2.nameOfSomething
FROM table1
INNER JOIN table2
Here is the part i don't get :
USING(id)
this ID is table1 foreign key, and table2 primary key
i dont really get it..
table1.ID values:
25 Rows:
row 1-5 = 1 , row 6-10 = 2 , row 11-15 = 3 , row 16-20 = 4 , row 21-25 = 5
table2.ID values :
5 Rows:
row 1 = 1 , row 2 = 2 , row 3 = 3 , row 4 = 4 , row 5 = 5
i test it and i get different result without it, how comes?
Note : Table1 contains interests, Table2 contains categories for these interests
feel free to ask for more information
USING specifies that a join should be performed by joining on the listed columns in both tables. That is
SELECT t1.col1,
t1.col2,
t2.col1
FROM table1 AS t1
INNER JOIN table2 AS t2
USING (col1)
is the same as
SELECT t1.col1,
t1.col2,
t2.col1
FROM table1 AS t1
INNER JOIN table2 AS t2
ON t1.col1 = t2.col1
For reference, see the MySql homepage.
USING is a equi-join and relies on attribute names for the same data element remaining the same between tables.
ON is more flexible: because it requires you to explicitly specify the attribute name in both tables, attribute names for the same data element can be the same or they can be different between the tables. Also, it is a theta-join, meaning that the join type can be any condition, including equality. As a result of this flexibility, ON is more verbose.
| Table1: | Table2: |
| id | id | table1_id |
| 1 | 1 3 |
| 2 | 2 2 |
| 3 | 3 1 |
If you join the above two tables together with USING(id) it will match rows where the id value in Table1 are the same as the id value in Table2...
SELECT * FROM table1 JOIN table2 USING(id)
| id | id table1_id |
| 1 | 1 3 |
| 2 | 2 2 |
| 3 | 3 1 |
But, the id in Table2 might have nothing to do with the id in Table1. If that's the case, you can use ON to be specific about how you match records together...
SELECT * FROM table1 JOIN table2 ON table1.id = table2.table1_id
| id | id table1_id |
| 1 | 3 1 |
| 2 | 2 2 |
| 3 | 1 3 |
If you specify nothing at all, you match every record in one table, against every record in the other table...
SELECT * FROM table1 CROSS JOIN table2
| id | id table1_id |
| 1 | 1 3 |
| 1 | 2 2 |
| 1 | 3 1 |
| 2 | 1 3 |
| 2 | 2 2 |
| 2 | 3 1 |
| 3 | 1 3 |
| 3 | 2 2 |
| 3 | 3 1 |