MySQL update column based on previous row (same column) - mysql

I have the following data:
ID | Image
1 | 10
2 | 11
3 |
4 |
5 |
And I would like to update the missing values with the value of the row before plus one.
The final output should be:
ID | Image
1 | 10
2 | 11
3 | 12
4 | 13
5 | 14
I thought about a select during the update, but it doesn't work.
UPDATE items AS item1
SET item1.image = (SELECT image
FROM items AS item2
WHERE item2.id < item1.id
ORDER BY item2.id DESC LIMIT 1) + 1

You can use an UPDATE with a JOIN to a derived table for this:
UPDATE Items AS i1
JOIN (
SELECT ID, #n := #n + 1 AS Image
FROM Items
CROSS JOIN (SELECT #n := (SELECT MAX(Image) FROM Items)) AS v
WHERE Image IS NULL
ORDER BY ID
) AS i2 ON i1.ID = i2.ID
SET i1.Image = i2.Image;
The derived table uses variables in order to calculate the Image values of the records having NULLs.
Demo here

Try this solution using a user variable, with a complete demo as below.
SQL:
-- data
create table items(ID int, Image int);
insert into items values
(1, 10),(2, NULL),(3, NULL),(4, NULL),(5, NULL);
SELECT * FROM items;
-- SQL needed
SET #i = 0;
UPDATE items
SET Image = (IF(Image IS NULL OR Image = '',
#i:=#i+1,
#i:=Image
));
SELECT * FROM items;
Output:
mysql> SELECT * FROM items;
+------+-------+
| ID | Image |
+------+-------+
| 1 | 10 |
| 2 | NULL |
| 3 | NULL |
| 4 | NULL |
| 5 | NULL |
+------+-------+
5 rows in set (0.00 sec)
mysql>
mysql> SET #i = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE items
-> SET Image = (IF(Image IS NULL OR Image = '',
-> #i:=#i+1,
-> #i:=Image
-> ));
Query OK, 4 rows affected (0.00 sec)
Rows matched: 5 Changed: 4 Warnings: 0
mysql> SELECT * FROM items;
+------+-------+
| ID | Image |
+------+-------+
| 1 | 10 |
| 2 | 11 |
| 3 | 12 |
| 4 | 13 |
| 5 | 14 |
+------+-------+
5 rows in set (0.00 sec)

I have same problem, and I use simple Update with variable (#)
update items,(select #n := 10) v set `Image`=#n:=#n+1 order by ID asc;
I hope to be useful this query :D

Given that the tables you present are not a sample I'd do something hacky and simple like this:
Update items Set items.Image=items.id+9 WHERE items.Image is NULL;
Oh god, I smell the incoming downvotes!

Related

update inner select successful but data not update

this is my code
UPDATE `mytable`
SET `income` = (SELECT sum(`row`) FROM (SELECT * FROM `mytable`)AS mmc WHERE `view_date` = '2018-5-21')
WHERE id = 1 AND view_date = '2018-5-21'
I run this code and it successful, but my data was not update.
You can use the below SQL to update your table properly.
SQL:
update mytable m
join (select id,view_date,sum(row) as row from mytable group by id,view_date) t on (m.id = t.id and m.view_date = t.view_date)
set m.income = t.row
where m.id = 1 and m.view_date = '2018-05-23';
Example are below:
mysql> create table mytable(id int,income int, row int, view_date date);
Query OK, 0 rows affected (0.54 sec)
mysql> insert into mytable values(1,null,230,current_date);
Query OK, 1 row affected (0.12 sec)
mysql> insert into mytable values(1,null,450,current_date);
Query OK, 1 row affected (0.05 sec)
mysql> select * from mytable;
+------+--------+------+------------+
| id | income | row | view_date |
+------+--------+------+------------+
| 1 | NULL | 230 | 2018-05-23 |
| 1 | NULL | 450 | 2018-05-23 |
| 2 | NULL | 800 | 2018-05-23 |
+------+--------+------+------------+
3 rows in set (0.00 sec)
mysql> update mytable m
-> join (select id,view_date,sum(row) as row from mytable group by id,view_date) t on (m.id = t.id and m.view_date = t.view_date)
-> set m.income = t.row
-> where m.id = 1 and m.view_date = '2018-05-23';
Query OK, 2 rows affected (0.13 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> select * from mytable;
+------+--------+------+------------+
| id | income | row | view_date |
+------+--------+------+------------+
| 1 | 680 | 230 | 2018-05-23 |
| 1 | 680 | 450 | 2018-05-23 |
| 2 | NULL | 800 | 2018-05-23 |
+------+--------+------+------------+
3 rows in set (0.00 sec)

MySQL Count name greater than a value

Please how can i check if a particular name is greater than a value in MySQL database. I want to do something like.
SELECT id FROM table WHERE COUNT(name = 'john') > 2
i know this does not work, but i really need to do something like this.
An Example: A student studying CS, From New York, and grad point is 4.5 wants to check into a hostel.
I have a hostel tables with fields course, state, and Grade_Point. i want to select the hostel_id where no same user with the same course > 2, state > 2 and grade_point > 2 are in the same room.
You can use the HAVING clause :
SELECT t.id FROM YourTable t
GROUP BY id
HAVING SUM(t.name = 'john') > 2
MySQL takes boolean expression as 0,1 , so SUM(t.name = 'john') will sum the number of occurences john appears for each ID , and will bring back those that appear more then twice.
Assuming that id is not unique and you want ids where 'john' appears 3 or more times:
select id
from t
where name = 'john'
group by id
having count(*) > 2;
This should be more efficient than any version that uses conditional aggregation because it reduces the size of the data before doing the aggregation.
Try this;)
SELECT id FROM table HAVING COUNT(IF(name = 'john', 1, null)) > 2
SELECT name, count(*)
FROM YourTable
where name = 'john'
GROUP BY name
HAVING count(*) > 2
Consiedr the following...
SELECT * FROM my_table ORDER BY id;
+----+------+
| Id | Name |
+----+------+
| 1 | Q |
| 2 | W |
| 3 | E |
| 4 | R |
| 5 | T |
| 6 | Y |
+----+------+
INSERT INTO my_table (name) SELECT 'Q' FROM (SELECT 1) x LEFT JOIN my_table y ON y.name = 'Q' WHERE y.id IS NULL;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM my_table ORDER BY id;
+----+------+
| Id | Name |
+----+------+
| 1 | Q |
| 2 | W |
| 3 | E |
| 4 | R |
| 5 | T |
| 6 | Y |
+----+------+
INSERT INTO my_table (name) SELECT 'Z' FROM (SELECT 1) x LEFT JOIN my_table y ON y.name = 'Z' WHERE y.id IS NULL;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
SELECT * FROM my_table ORDER BY id;
+----+------+
| Id | Name |
+----+------+
| 1 | Q |
| 2 | W |
| 3 | E |
| 4 | R |
| 5 | T |
| 6 | Y |
| 7 | Z |
+----+------+
7 rows in set (0.00 sec)
Alternatively, you can just issue a simple INSERT on a UNIQUE column. And use the 'rows affected' as evidence of whether the name already exists.

MYSQL: How to fill null values in column with the previous entry?

I've got a program at work that exports to CSV but leaves blanks in the most irritable places. I want to view the carrier and destination on the same row and currently the carrier is 1 row above the destination like below:
I have a database that is like the following:
|Key|Carrier ||Destination|
|-------------------------|
| 1 | HULL2 || |
| 2 | || C14A102 |
| 3 | DONC1 || |
| 4 | || D15A012 |
What I want:
|Key|Carrier ||Destination|
|-------------------------|
| 1 | HULL2 || |
| 2 | HULL2 || C14A102 |
| 3 | DONC1 || |
| 4 | DONC1 || D15A012 |
Either that or insert a new column with the information from carrier column.
Sorry if this is confusing its confusing me to explain it!
James
Here is a solution, by cloning another table and then deleting it:
CREATE TABLE t1(Key_id INT PRIMARY KEY, Carrier CHAR(20), Destination CHAR(20));
INSERT INTO t1 VALUES(1, 'HULL2', ''),(2,'','C14A102'),(3,'DONC1',''),(4,'','D15A012');
CREATE TABLE t2 LIKE t1;
INSERT INTO t2 SELECT * FROM t1;
SELECT * FROM t1;
UPDATE t1 SET Carrier =
(
SELECT t2.Carrier
FROM t2
WHERE t2.Key_id < t1.Key_id AND t2.Carrier != ''
ORDER BY t2.Key_id DESC
LIMIT 1
)
WHERE Carrier = '';
SELECT * FROM t1;
DROP TABLE t2;
Output:
mysql> SELECT * FROM t1;
+--------+---------+-------------+
| Key_id | Carrier | Destination |
+--------+---------+-------------+
| 1 | HULL2 | |
| 2 | | C14A102 |
| 3 | DONC1 | |
| 4 | | D15A012 |
+--------+---------+-------------+
4 rows in set (0.00 sec)
mysql> UPDATE t1 SET Carrier =
-> (
-> SELECT t2.Carrier
-> FROM t2
-> WHERE t2.Key_id < t1.Key_id AND t2.Carrier != ''
-> ORDER BY t2.Key_id DESC
-> LIMIT 1
-> )
-> WHERE Carrier = '';
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> SELECT * FROM t1;
+--------+---------+-------------+
| Key_id | Carrier | Destination |
+--------+---------+-------------+
| 1 | HULL2 | |
| 2 | HULL2 | C14A102 |
| 3 | DONC1 | |
| 4 | DONC1 | D15A012 |
+--------+---------+-------------+
4 rows in set (0.00 sec)
Assuming that the column 'key' can be trusted in this way, I would update with a self join where the join uses key = key+1, and then make sure it's only affecting even rows.
UPDATE tablename as even_row JOIN tablename as odd_row
ON even_row.Key = odd_row.Key + 1
SET even_row.Carrier = odd_row.Carrier
WHERE odd_row.Key % 2;

Make new column which is incremented by it's order

I need to make new column for my table Products -> called Order (new column). And using rails migration I need to add new column and instantly set it's order number, but it's need to be done by product_id.
What I mean I need something like:
product_id | order
1 ------------> 1
1 ------------> 2
1 ------------> 3
2 ------------> 1
2 ------------> 2
Is there a way of doing it?
EDIT :
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''order' = t1.'order'' at line 15:
update product_submissions t
join (
select
id,
product_id,
'order' from (
select id,
product_id,
#rn:= if(#prev = product_id,#rn:=#rn+1,1) as 'order',
#prev:=product_id
from product_submissions,
(select #rn:=0,#prev:=0)r
order by product_id,id
)x
)t1 on t1.id=t.id set t.'order' = t1.'order'
Consider the following
mysql> create table test (id int ,product_id int);
Query OK, 0 rows affected (0.14 sec)
mysql> insert into test values (1,1),(2,1),(3,1),(4,2),(5,2);
Now lets create the order
select
product_id,
`order` from (
select
product_id,
#rn:= if(#prev = product_id,#rn:=#rn+1,1) as `order`,
#prev:=product_id from test,(select #rn:=0,#prev:=0)r
order by product_id,id
)x ;
This will give you something as
+------------+-------+
| product_id | order |
+------------+-------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
+------------+-------+
Now lets use in update command, but before that lets add the column (in your case its already there)
mysql> alter table test add column `order` int ;
Query OK, 5 rows affected (0.29 sec)
mysql> select * from test ;
+------+------------+-------+
| id | product_id | order |
+------+------------+-------+
| 1 | 1 | NULL |
| 2 | 1 | NULL |
| 3 | 1 | NULL |
| 4 | 2 | NULL |
| 5 | 2 | NULL |
+------+------------+-------+
5 rows in set (0.00 sec)
Finally the update command
update test t
join (
select
id,
product_id,
`order` from (
select id,
product_id,
#rn:= if(#prev = product_id,#rn:=#rn+1,1) as `order`,
#prev:=product_id
from test,(select #rn:=0,#prev:=0)r
order by product_id,id
)x
)t1 on t1.id=t.id set t.`order` = t1.`order`
mysql> select * from test ;
+------+------------+-------+
| id | product_id | order |
+------+------------+-------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
+------+------------+-------+
5 rows in set (0.00 sec)

List all associate's names from a referred table?

I have a table test which looks like this:
+-------+-------+
| u1_id | u2_id |
+-------+-------+
| 1 | 2 |
| 3 | 1 |
| 2 | 1 |
| 2 | 3 |
+-------+-------+
And, u1_id and u2_id are both 'foreign keys' to another table user:
+----+-------+
| id | name |
+----+-------+
| 1 | n_foo |
| 2 | n_bar |
| 3 | n_baz |
+----+-------+
Not sure how to explain this, but:
In input, I have a single user id which can be referenced in u1_id or in u2_id.
I'd like to get the associated user to it as defined in table test using a join on table user.
For user id = 1, I should get:
n_bar
n_baz
n_bar
For user id = 2, I should get:
n_foo
n_foo
n_baz
This may be a common issue but didn't find exactly how to join these two tables using:
u1_id if my input user id is in u2_id column
u2_id otherwise
I tried something like this but it doesn't seem to work:
SELECT name
FROM test
JOIN user
ON user.id = test.u1_id
WHERE test.u1_id = #guid OR
test.u2_id = #guid AND
CASE
WHEN test.u2_id = #guid
THEN test.u2_id = test.u1_id
END;
Any ideas how to achieve this? Or may be there is a better way to design these tables, I'm completely open to any suggestions.
If I correctly understood your question, I believe you need following query:
SELECT t2.`name`
FROM `t2`
INNER JOIN (
SELECT IF(#uid = 1, t1.u1_id, t1.u2_id) as `id`
FROM `t1`
) as `t1`
WHERE t2.id = t1.id and t1.id != #uid;
I tried following:
Date base create, I don't know what columns type your are using just for demo:
create table t1 (
u1_id int,
u2_id int
);
insert into t1 values
(1, 2),
(3, 1),
(2, 1),
(2, 3);
create table t2 (
id int,
name varchar(10)
);
insert into t2 values
( 1 , 'n_foo' ),
( 2 , 'n_bar' ),
( 3 , 'n_baz' );
Then Queries:
mysql> SELECT * FROM t1;
+-------+-------+
| u1_id | u2_id |
+-------+-------+
| 1 | 2 |
| 3 | 1 |
| 2 | 1 |
| 2 | 3 |
+-------+-------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM t2;
+------+-------+
| id | name |
+------+-------+
| 1 | n_foo |
| 2 | n_bar |
| 3 | n_baz |
+------+-------+
3 rows in set (0.00 sec)
mysql> SET #uid = 1;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT #uid;
+------+
| #uid |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
mysql> SELECT t2.`name`
-> FROM `t2`
-> INNER JOIN (
-> SELECT IF(#uid = 1, t1.u1_id, t1.u2_id) as `id`
-> FROM `t1`
-> ) as `t1`
-> WHERE t2.id = t1.id and t1.id != #uid;
+-------+
| name |
+-------+
| n_baz |
| n_bar |
| n_bar |
+-------+
3 rows in set (0.03 sec)
mysql> SET #uid = 2;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT #uid;
+------+
| #uid |
+------+
| 2 |
+------+
1 row in set (0.00 sec)
mysql> SELECT t2.`name`
-> FROM `t2`
-> INNER JOIN (
-> SELECT IF(#uid = 1, t1.u1_id, t1.u2_id) as `id`
-> FROM `t1`
-> ) as `t1`
-> WHERE t2.id = t1.id and t1.id != #uid;
+-------+
| name |
+-------+
| n_foo |
| n_foo |
| n_baz |
+-------+
3 rows in set (0.00 sec)
Btw, you can change join conditions if it is not what you wanted. But as it give correct results...
Give it a Try!!
What about:
SELECT IF(u1.id = #guid, u2.name, u1.name) AS name
FROM test
JOIN user u1 ON u1.id = test.u1_id
JOIN user u2 ON u2.id = test.u2_id
WHERE test.u1_id=#guid OR test.u2_id=#guid;
Using #GrijeshChauhan's schema...
SELECT * FROM
(SELECT u1_id,u2_id FROM t1
UNION ALL
SELECT u2_id,u1_id FROM t1
) x
JOIN t2
ON t2.id = x.u1_id
WHERE x.u2_id = 2;
+-------+-------+------+-------+
| u1_id | u2_id | id | name |
+-------+-------+------+-------+
| 1 | 2 | 1 | n_foo |
| 1 | 2 | 1 | n_foo |
| 3 | 2 | 3 | n_baz |
+-------+-------+------+-------+