Updating each row separately - mysql

I'm trying to update some rows in my database.
I have a table like the following :
id | subid | creation_date
1 | 1/1 | 2011-06-23
1 | 1/2 | 0000-00-00
2 | 2/1 | 2011-06-20
2 | 2/2 | 0000-00-00
WHat i want is to update the entries having the creation_date set to "0000-00-00" with the creation_date of the one who have a real date.
The result after the request would be :
id | subid | creation_date
1 | 1/1 | 2011-06-23
1 | 1/2 | 2011-06-23
2 | 2/1 | 2011-06-20
2 | 2/2 | 2011-06-20
Can someone out there have an idea to help me ? Il would be perfet to make this with a single request.
Thanks ;)
B.

to get around the problem with that other answer of not being able to have the table in the sub query that you are updating. let's just create at temp table and use that...
CREATE TEMPORARY TABLE foo SELECT id, MAX(creation_date) FROM yo_table GROUP BY id;
UPDATE yo_table SET creation_date = ( SELECT foo.creation_date FROM foo WHERE foo.id = yo_table.id )
WHERE creation_date = '0000-00-00';

update yo_table outter
set creation_date =
(select min(creation date) from yo_table iner where iner.id = outter.id)
where creation_date = '0000-00-00' --note that you'll have to edit this according to the data type of your creation_date column
Edit: with temp. table
create table yo_table_tmp as select * from yo_table;
update yo_table outter
set creation_date =
(select min(creation date) from yo_table_tmp iner where iner.id = outter.id)
where creation_date = '0000-00-00' --note that you'll have to edit this according to the data type of your creation_date column
;
drop table yo_table_tmp;

update table_a as t1, table_a as t2
set t1.creation_date=t2.creation_date
where t1.id=t2.id and (t1.creation_date=0 and t2.creation_date>0);

I think this should work for you:
UPDATE `tableA` `ta`
INNER JOIN (
SELECT `id`, `creation_date`
FROM `tableA`
WHERE `creation_date` > '0000-00-00'
GROUP BY id
) `tb` ON `ta`.`id` = `tb`.`id`
SET `ta`.`creation_date` = `tb`.`creation_date`
WHERE `ta`.`creation_date` = '0000-00-00';
Hope this helps.

Create a temporary table.
I modified your subid for simplicity you can always combine them in the query result.
mysql> update table1 set creation_date = (SELECT x.creation_date
from (SELECT * from table1 WHERE subid=1) AS X
WHERE x.id =table1.id) WHERE subid=2;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> select * from table1;
+----+-------+---------------+
| id | subid | creation_date |
+----+-------+---------------+
| 1 | 1 | 2011-06-23 |
| 1 | 2 | 2011-06-23 |
| 2 | 1 | 2011-06-20 |
| 2 | 2 | 2011-06-20 |
+----+-------+---------------+
4 rows in set (0.00 sec)

Related

select data from two rows as single row sequentially

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

Odd behavior of max and having in MySQL when max==0

I have the following table:
mysql> select * from foo;
| id | value | bar |
+----+-------+------+
| 1 | 2 | 3 |
| 2 | 0 | 3 |
| 1 | 1 | 5 |
I want to select the tuple with the maximum value for each id. However, when max(value) is 0, I don't get a result.
mysql> select id,max(value),bar from foo group by id having max(value);
| id | max(value) | bar |
+----+------------+------+
| 1 | 2 | 3 |
Is this supposed to behave like that and if so, why?
HAVING cannot be used in any way to pick a record out of a group of records as defined by the fields used in the GROUP BY clause. It is rather applied to the group as a whole.
So, in your case, you have to do a self-join to get the rest of the table fields:
select t1.id, t1.value, t1...
from foo as t1
join (
select id, max(value) as max_value
from foo
group by id
) as t2 on t1.id = t2.id and t1.value = t2.max_value
IMHO you can get MAX couple by multiplying (id x value).
create table foo(id int, value int);
insert into foo values
(2,0),
(1,0),
(2,1),
(3,0),
(2,2);
select id, value
from foo
order by (id * value) desc
limit 1;
id | value
2 | 2
drop table foo;

Simplifying mysql calls into 1 update

I am trying to simplify multiple queries into 1 and for some reason I am having issues. I would like to update a reference count in a table while counting the ref in another table. Currently all I have is the _Doc_ID from the first table. I would like to look up the _FilePath and then count the number of rows that have the same _FilePath. Then Update the Ref_Count by the number found.
table 1
| _Doc_ID | Ref_Count |
| 1 | |
table 2
| ID | _FilePath |
| 1 | 123/123 |
| 2 | 123/123 |
Expected Results Table 1
| _Doc_ID | Ref_Count |
| 1 | 2 |
first query
SELECT _FilePath AS FilePathResult from database.tableName where _Doc_ID = '1'
second
SELECT count(*) AS TotalCount from database.tableName where _FilePath = FilePathResult
Third
Update table1 SET Ref_Count = TotalCount where _Doc_ID = 1
UPDATE with sub-query will do.
Update table1
SET Ref_Count =
(
SELECT count(*) AS TotalCount from database.tableName
where _FilePath = (SELECT _FilePath AS FilePathResult from database.tableName where _Doc_ID = '1')
)
where _Doc_ID = 1

Query for looping values in column

I need to make a query that moves values of only one column one row up ↑ at a time:
+------------+----------------+
| anotherCOL | values_to_loop |
+------------+----------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | 8 |
| 9 | 9 |
| 10 | 10 |
+------------+----------------+
So, the next time i run the query, it should look like this
+------------+----------------+
| anotherCOL | values_to_loop |
+------------+----------------+
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
| 4 | 5 |
| 5 | 6 |
| 6 | 7 |
| 7 | 8 |
| 8 | 9 |
| 9 | 10 |
| 10 | 1 |
+------------+----------------+
I need to loop the values of only one MYSQL COLUMN, as in move the values one ROW UP ↑ each time I run the query.
Notice: Tables provided are just illustrative, the data is different.
Here's how you can do it within a single UPDATE query:
UPDATE tbl a
INNER JOIN (
SELECT values_to_loop
FROM (SELECT * FROM tbl) c
ORDER BY anotherCOL
LIMIT 1
) b ON 1 = 1
SET a.values_to_loop =
IFNULL(
(SELECT values_to_loop
FROM (SELECT * FROM tbl) c
WHERE c.anotherCOL > a.anotherCOL
ORDER BY c.anotherCOL
LIMIT 1),
b.values_to_loop
)
It works as follows:
Updates all records from tbl
Joins with a temporary table to retrieve the top value of values_to_loop (the one that will go to the bottom)
Set the new value for values_to_loop to the corresponding value from the next row (c.anotherCOL > a.anotherCOL ... LIMIT 1)
Notes:
This works even if there are gaps in anotherCOL (eg: 1, 2, 3, 6, 9, 15)
It is required to use (SELECT * FROM tbl) instead of tbl because you're not allowed to use the table that you're updating in the update query
Faster query when there are no gaps in anotherCOL
If there are no gaps for values in anotherCOL you can use the query below that should work quite fast if you have an index on anotherCOL:
UPDATE tbl a
LEFT JOIN tbl b on b.anotherCOL = a.anotherCOL + 1
LEFT JOIN (
SELECT values_to_loop
FROM tbl
WHERE anotherCOL = (select min(anotherCOL) from tbl)
) c ON 1 = 1
SET a.values_to_loop = ifnull(
b.values_to_loop,
c.values_to_loop
)
I`ve created a sample table and added both a select to get the looped values and update to loop the values in the table. Also, using a #start_value variable to know the "1" which might be other. Try this:
CREATE TEMPORARY TABLE IF NOT EXISTS temp_table
(other_col INT, loop_col int);
INSERT INTO temp_table (other_col, loop_col) VALUES (1,1);
INSERT INTO temp_table (other_col, loop_col) VALUES (2,2);
INSERT INTO temp_table (other_col, loop_col) VALUES (3,3);
INSERT INTO temp_table (other_col, loop_col) VALUES (4,4);
INSERT INTO temp_table (other_col, loop_col) VALUES (5,5);
DECLARE start_value INT;
SELECT start_value = MIN(loop_col) FROM temp_table;
SELECT T1.other_col, ISNULL(T2.loop_col, start_value)
FROM temp_table T1
LEFT JOIN temp_table T2
ON T1.loop_col = T2.loop_col - 1;
UPDATE T1 SET
T1.loop_col = ISNULL(T2.loop_col, #start_value)
FROM temp_table T1
LEFT JOIN temp_table T2
ON T1.loop_col = T2.loop_col - 1;
SELECT *
FROM temp_table;
Let me know if it works for you.
Step by step:
1 - created a temp_table with values 1 to 5
2 - declared a start_value which will keep the lowest value for the column you to need to loop through
3 - select all rows from temp_table self left join with same temp_table. join condition is on loop_col - 1 so it can shift the rows up
4 - the same self left join, but this time update the values in place too.
please note that in case i get a null value, it should be the start_value there, because it cannot match
Perhaps these are what you had in mind:
update T
set values_to_loop = mod(values_to_loop, 10) + 1
update T
set values_to_loop =
coalesce(
(
select min(t2.values_to_loop) from T t2
where t2.values_to_loop > T.values_to_loop
),
(
select min(values_to_loop) from T
)
)

mysql delete from query using special id and date field

What i have is two columns specialid and date in tblSpecialTable, my table has duplicate specialID's, i want to delete from the table where date column is the older date and where specialid's are duplicated.
See my example:
mysql> SELECT * FROM test;
+------+---------------------+
| id | d |
+------+---------------------+
| 1 | 2011-06-29 10:48:41 |
| 2 | 2011-06-29 10:48:44 |
| 3 | 2011-06-29 10:48:46 |
| 1 | 2011-06-29 10:48:52 |
| 2 | 2011-06-29 10:48:53 |
| 3 | 2011-06-29 10:48:55 |
+------+---------------------+
mysql> DELETE t1 FROM test t1 INNER JOIN test t2 ON t1.id = t2.id AND t1.d < t2.d;
Query OK, 3 rows affected (0.00 sec)
mysql> SELECT * FROM test;
+------+---------------------+
| id | d |
+------+---------------------+
| 1 | 2011-06-29 10:48:52 |
| 2 | 2011-06-29 10:48:53 |
| 3 | 2011-06-29 10:48:55 |
+------+---------------------+
See also http://dev.mysql.com/doc/refman/5.0/en/delete.html
You have to use a "double-barrelled" match on the combination of fields from another query.
DELETE FROM tblSpecialTable
WHERE CONCAT(specialid, date) IN (
SELECT CONCAT(specialid, date)
FROM (
SELECT specialid, MAX(date) AS DATE, COUNT(*)
FROM tblSpecialTable
GROUP BY 1
HAVING COUNT(*) > 1) x
)
use a tmp table , set specialid column is unique. then use below sql:
insert into tmp(specailid,date) values(select specialid,date from tplSpecialTable order by date desc)
DELETE FROM tblSpecialTable
WHERE specialid NOT IN
(SELECT specialid FROM tblSpecialTable
GROUP BY specialid
HAVING COUNT(table.date) > 1
ORDER BY date
LIMIT COUNT(table.date) - 1 )
This isn't a fancy single query, but it does the trick:
CREATE TABLE tmp as SELECT * FROM tblspecialtable ORDER BY date DESC;
DELETE FROM tblspecialtable WHERE 1;
INSERT INTO tblspecialtable SELECT * FROM tmp GROUP BY specialid;
DROP TABLE tmp;
The first line creates a temporary table where the values are ordered by date, most recent first. The second makes room in the original table for the fixed values. The third consolidates the values, and since the GROUP BY command goes from the top down, it takes the most recent first. The final line removes the temporary table. The end result is the original table containing unique values of specialid with only the most recent dates.
Also, if you are programatically accessing your mysql table, it would be best to check if an id exists first, and then use the update command to change the date, or else add a new row if there is no existing specialID. Also, you should consider making specialID UNIQUE if you don't want duplicates.