My database is composed by individual job contracts. I am updating some information to enhance the quality of the data. More precisely, I am updating information regarding workers' residence codes. In the following image I am showing an example of my database in the following image (the .csv version could be found here).
While variables are explained here below.
id -----------> "Primary key" [indexed]
worker_id ----> "Id associated ot each individual/worker" [indexed]
dt_start -----> "Starting date of the job contract"
dt_end -------> "End date of the job contract"
cod_res ------> "Old residence code"
cod_res_rev --> "New residence code"
id_lag -------> "Previous id, if the 'worker_id' is the same" [indexed]
id_lead ------> "Subsequent id, it the 'worker_id' is the same" [indexed]
As you can notice, the column cod_res_rev is characterized is full of NULL values. This is because the reconstruction of the variable cod_res_rev with the updated residence values it was based solely on specific contracts (those for which the worker had had an actual change of residence - but this is redundant for the purposes of my question). Therefore, my goal is to fill each NULL value of the column cod_res_rev with the previous one, if not missing, until the next non-empty value is reached and continue like this for each worker. The result should be something like this.
I attempted to achieve my goal through the following procedure.
-- The loop is performed based on the maximum number of entries per worker in the database identified through the table 'max_count'.
drop table if exists max_count;
create table max_count
as select worker_id, count(*) n
from ml_arm
group by worker_id;
alter table max_count add unique index (worker_id);
DROP PROCEDURE IF EXISTS doiterate;
delimiter //
CREATE PROCEDURE doiterate()
BEGIN
DECLARE total INT unsigned DEFAULT 0;
WHILE total <= (select MAX(n) from max_count) DO
update ml_arm a
left outer join ml_arm b on a.id_lag = b.id
set a.cod_res_rev =
case
when a.cod_res_rev is NULL and a.worker_id = b.worker_id and b.cod_res_rev is not NULL
then b.cod_res_rev
else a.cod_res_rev
end;
SET total = total + 1;
END WHILE;
END//
delimiter ;
CALL doiterate();
However, I do not believe this is the optimal way to update my table. In fact, by database if composed by about 25 million of rows and the value from select MAX(n) from max_count is about 4,000. I kindly ask you for any suggestion on faster approaches to update my table. I am using MySQL 8.0.22. Thank you in advance.
Eventually, here below there is a command to create a sample table of my database with a bunch of entries.
drop table if exists ml_arm;
create table ml_arm (
id MEDIUMINT NOT NULL AUTO_INCREMENT,
worker_id int,
dt_start date,
dt_end date,
cod_res varchar(50),
cod_res_rev varchar(50),
id_lag int,
id_lead int,
PRIMARY KEY (id)
);
insert into
ml_arm(id, worker_id, dt_start, dt_end, cod_res, cod_res_rev, id_lag, id_lead)
values
('12', '20', '2014-05-02', '2014-07-08', '', 'I040', NULL, '13'),
('13', '20', '2017-01-14', '2017-01-31', '', NULL, '12', '14'),
('14', '20', '2017-11-06', '2017-12-15', 'I040', NULL, '13', NULL),
('20', '29', '2014-11-24', '2017-02-11', '', 'N.D.', NULL, NULL),
('21', '42', '2016-01-22', '2016-05-05', 'G582', 'G582', NULL, NULL),
('23', '45', '2013-08-07', '2014-04-06', 'G582', 'G582', NULL, '24'),
('24', '45', '2014-05-07', '2014-05-10', 'G582', NULL, '23', NULL),
('25', '48', '2012-08-11', '2012-08-31', 'G582', 'G582', NULL, '26'),
('26', '48', '2013-08-10', '2013-08-31', 'G582', NULL, '25', NULL),
('53', '71', '2016-12-01', '2017-05-31', '', 'N.D.', NULL, '54'),
('54', '71', '2017-06-01', '2020-05-29', '', NULL, '53', '55'),
('55', '71', '2020-06-01', '2099-01-01', '', NULL, '54', NULL)
;
By following Gordon Linoff's answer on this thread it seems to work:
UPDATE ml_arm t1
JOIN (
SELECT id, #s:=IF(cod_res_rev IS NULL, #s, cod_res_rev) cod_res_rev
FROM (SELECT * FROM ml_arm ORDER BY id) r,
(SELECT #s:= NULL) t
) t2
ON t1.id = t2.id
SET t1.cod_res_rev = t2.cod_res_rev;
I have an database with alot of users (schema's) for example:
user_1
user_2
user_3
...
user_303
All of those got the same tables, for example:
CREATE TABLE `messages` (
`id` int(11) NOT NULL,
`content` text COLLATE utf8mb3_unicode_ci NOT NULL,
`date` datetime NOT NULL,
`viewed` int(11) NOT NULL,
`forId` int(11) NOT NULL,
`fromId` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
INSERT INTO `messages` (`id`, `content`, `date`, `viewed`, `forId`, `fromId`) VALUES
(1, 'Hello World', '2020-06-04 14:49:17', 1, 2106, 1842),
(2, 'Hi there', '2020-06-04 14:49:39', 1, 2106, 1842),
(3, 'test 1', '2022-01-03 11:40:43', 1, 3006, 3006),
(4, 'Test 2', '2022-01-20 12:01:52', 1, 1842, 1842);
What I want is a query for example:
USE user_1, user_2, user_3;
SELECT * FROM `messages` WHERE `content` LIKE `%Hi%`;
I don't know if this is possible as a SQL Query, an other option is to write a small PHP code with a for each loop but than I want a command so I get an list of all users: user_1 till user_303
The users are not from 1 till 303 there are some users deleted, to it can be that user_200 doesn't exist any more.
Hope someone here can help me out
You can use the following to write the query you want.
USE information_schema;
SELECT concat("SELECT * FROM ", table_schema,".",table_name, " UNION ALL ")
FROM tables WHERE table_name = 'messages';
You will obtain something like this;
SELECT * FROM base.messages UNION ALL
SELECT * FROM c.messages UNION ALL
You can then run this query to obtain what you want.
In Oracle you can concatenate only 2 arguments, so you have to use nesting to concatenate more than two arguments.
Also you should use ALL_TABLES instead of information_schema
SELECT
concat('SELECT MESSAGE FROM ', concat(OWNER, concat('.', concat(TABLE_NAME, ' UNION ALL '))))
FROM
ALL_TABLES
WHERE
OWNER LIKE 'user_%';
Don't forget to delete the last UNION ALL from result.
I have a website and I want to update some empty values for some IDs.
In phpMyAdmin, editing a single row gives me this result:
UPDATE `sample_dir`.`page` SET `votes` = '4', `rating` = '7.00'
WHERE `page`.`id` =12676170;
However, if I try to update multiple rows at once (I was thinking putting a comma between the IDs will do it but it doesn't). I used this sql command:
UPDATE "sample_dir`.`page` SET `votes` = '1', `rating` = '9.00'
WHERE `page`.`id` =2042085451,12676170,733543897;
What am I doing wrong?
Thanks
Use the IN() operator
http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in
UPDATE `sample_dir`.`page` SET `votes` = '1', `rating` = '9.00'
WHERE `page`.`id` IN (2042085451,12676170,733543897);
CREATE TABLE myCTGlobalFootprint (
geoID INT NOT NULL AUTO_INCREMENT,
geoName VARCHAR(20) NOT NULL,
PRIMARY KEY (geoID)
);
INSERT INTO myCTGlobalFootprint
(geoName)
VALUES
('Canada'),
('United States'),
('Europe'),
('International Misc.');
It's throwing an error at line 15... any insight would be DEEPLY APPRECIATED!!
Use UNION like:
INSERT INTO myCTGlobalFootprint (geoName)
select 'Canada'
UNION
select 'United States'
UNION
select 'Europe'
UNION
select 'International Misc.';
Otherwise you have to write four INSERT INTO statements like:
INSERT INTO myCTGlobalFootprint(geoName) VALUES('Canada');
INSERT INTO myCTGlobalFootprint(geoName) VALUES('United States');
INSERT INTO myCTGlobalFootprint(geoName) VALUES('Europe');
INSERT INTO myCTGlobalFootprint(geoName) VALUES('International Misc.');
I'm trying to write a MySQL query which will update a blog post view counter if the user has not visited the post in the last 24 hours. I'm trying to write something like this (but this does not work):
IF EXISTS (
SELECT 1
FROM `posts-views`
WHERE
`ip` = '".$_SERVER['REMOTE_ADDR']."'
AND
`time` > ".($time-60*60*24)."
AND
`post` = $id
) THEN
NULL
ELSE
INSERT INTO `posts-views`
(`post`, `time`, `ip`, `user`)
VALUES
($id, $time, '".$_SERVER['REMOTE_ADDR']."', $me)
What's the correct way to fix the query?
From what I see you cannot use INSERT IGNORE in that case, but something like following should do the job :
INSERT INTO `posts-views`
(`post`, `time`, `ip`, `user`)
SELECT $id, $time, '".$_SERVER['REMOTE_ADDR']."', $me
FROM dual
WHERE NOT EXISTS (
SELECT 1
FROM `posts-views`
WHERE
`ip` = '".$_SERVER['REMOTE_ADDR']."'
AND
`time` > ".$time-60*60*24."
AND
`post` = $id
)
I completely omit escaping variables which definitely should be done in real code.
UPDATED - added from dual to avoid syntax error