Update Table by getting maximum value from another table - mysql

I have the following configuration:
CREATE TABLE `extRef` (
`id` bigint(20) NOT NULL,
`ref` varchar(100) NOT NULL,
`extType` tinyint(4) NOT NULL,
`extId` bigint(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
I would like to migrate some data from this table, effectively,
For reach unique (extType,extId) pair, get the maximum Id value.
I have the following setup already:
CREATE TABLE cleanupTbl(
retainableId BIGINT(20),
extId BIGINT(20),
extType BIGINT(20),
PRIMARY KEY (retainableId, extId, extType)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO cleanupTbl(extId, extType )
SELECT r.`extId`, r.`extType `
FROM `extRef` r
GROUP BY r.`extType `, r.`extId`
HAVING COUNT(*) > 1;
Now, when I try to insert the Maximum Id i have tried the following setups but none seem to be working due to errors. Can someone please help with a working statement? Thanks
UPDATE `cleanupTbl` cl
SET cl.`retainableId` = temp.`largestId`
FROM (
SELECT MAX(r.`id`) AS largestId
FROM `extRef` r
JOIN `cleanupTbl` c
ON c.`extId` = r.`extId` AND c.`extType ` = r.`extType `
) temp;
or
UPDATE cl
SET cl.`retainableId` = MAX(r.`id`)
FROM `cleanupTbl` AS cl
INNER JOIN `extRef` AS r
ON cl.`extId` = r.`extId` AND cl.`extType` = r.`extType`;

Try joining to an already filtered (maxID,extID,extType) table and then update accordingly:
UPDATE `cleanupTbl` cl
INNER JOIN(SELECT MAX(r.`id`) AS largestId, r.`extId`, r.`extType `
FROM `extRef` r
GROUP BY r.`extType `,r.`extId`) temp
ON cl.`extId` = temp.`extId` AND cl.`extType ` = temp.`extType `
SET cl.`retainableId` = temp.`largestId`

Related

Speed up the following queries by merging them into one

I need to find a way for merging two queries into one.
This is the structure of the tables I am using:
(there are also other fields on contents and ratings but I didn't add them, since they aren't needed for this.
-- Create syntax for TABLE 'contents'
CREATE TABLE `contents` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`rating` decimal(5,4) DEFAULT '0.0000',
`ratingsCount` int(8) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
-- Create syntax for TABLE 'ratings'
CREATE TABLE `ratings` (
`what` int(11) DEFAULT NULL,
`time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`rating` decimal(3,2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Since last time I asked something here on stack overflow someone told me to write the code I'm using right now. Here it is:
db.query("SELECT AVG(rating) `avg`, COUNT(rating) cnt FROM `ratings` WHERE what = ?", [req.params.id], function(err, avg) {
db.query("UPDATE contents SET `rating` = ?, `ratingsCount` = ? WHERE id = ?", [avg[0].avg, avg[0].cnt, req.params.id], function() { });
});
You could use an UPDATE/JOIN combination to do it in a single round trip to the database;
UPDATE contents c
JOIN (
SELECT what, AVG(rating) rating, COUNT(rating) ratingsCount
FROM ratings WHERE what = ? GROUP BY what
) r
ON c.id = r.what
SET c.rating = r.rating, c.ratingsCount = r.ratingsCount
An SQLfiddle to test with.
The subquery will find the average/count for the value of "what", the outer query will just join that information to update contents.
This one will do the work:
UPDATE contents c SET
rating=(SELECT AVG(rating) FROM ratings r WHERE r.what=c.id),
ratingsCount=(SELECT COUNT(rating) FROM ratings r WHERE r.what=c.id);
You'll need to add index for id and what columns.

MySQL update a table and select from the same table in a subquery

I have table of link
CREATE TABLE `linktable` (
`id ` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`idParent` BIGINT(20) UNSIGNED NOT NULL,
`Role` ENUM('Contacts','Expert','...') NULL DEFAULT NULL,
`idChild` BIGINT(20) UNSIGNED NOT NULL,
PRIMARY KEY (`idt`),
UNIQUE INDEX `UK_Parent_Child_Role` (`idParent`, `idChild`, `Role`)
)
I want to update this table and don’t break the unique key.
With other database I make something like this :
Update linktable lt1 Set lt1.Parent = :ziNew Where lt1.idParent = :ziOld
and not exists (select * from linktable lt2 where lt2.idParent = :ziNew and lt1.role = lt2.role and lt1.idChild = lt2.idChild);
How to make this with MySQL ?
Using your same syntax for variables, you would do this with a join:
Update linktable lt1 left outer join
(select *
from linktable lt2
where lt2.idParent = :ziNew
) lt2
on lt1.role = lt2.role and lt1.idChild = lt2.idChild
Set lt1.Parent = :ziNew
Where lt1.Parent =:ziOld and lt2.idParent is null;
The problem in MySQL is that the subquery is one the same table as the updated table. If it were a different table, then the original form with not exists would still work.

Update with select in mysql

I am going update table_a with variable stored in table_b. but when i trying update with select query, i got errors, please help me. Thank you alot.
This is struct of 2 tables:
CREATE TABLE IF NOT EXISTS `table_a` (
`fk1` int(11) DEFAULT NULL,
`avg_100` int(11) DEFAULT NULL,
`avg_score` int(11) DEFAULT NULL,
`cvg_date` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `table_b` (
`fk1` int(11) NOT NULL DEFAULT '0',
`avg_100` int(11) DEFAULT NULL,
`avg_score` int(11) DEFAULT NULL,
`cvg_date` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
and when i try execute query
UPDATE table_a a LEFT JOIN ((
SELECT fk1, SUM(avg_100) as avg_100, SUM(avg_score) as avg_score, MAX(cvg_date) as cvg_date
FROM table_b
GROUP BY fk1
) AS b1 ) AS b ON a.fk1= b.fk1
SET
a.avg_score = b.avg_score,
a.avg_100 = b.avg_100,
a.cvg_date = b.cvg_date
i got a error:
[Err] 1064 - 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 'b ON a.fk1= b.fk1
SET
a.avg_score = b.avg_score,
a.avg_100 = b.avg_100,
' at line 4
You are setting alias "b" and "b1" to the table returned by select. You just need one. Try this query:
UPDATE table_a a
LEFT JOIN (
SELECT fk1, SUM(avg_100) as avg_100, SUM(avg_score) as avg_score, MAX(cvg_date) as cvg_date
FROM table_b GROUP BY fk1
) AS b
ON a.fk1= b.fk1
SET
a.avg_score = b.avg_score,
a.avg_100 = b.avg_100,
a.cvg_date = b.cvg_date
I think you have a syntax error by adding a select just after the left join.
I found a stack overflow post with a update that maybe you could use as example to rearrange your query:
UPDATE multiple tables in MySQL using LEFT JOIN
I solved this problem using rownum
UPDATE TABLE1 set TABLE1.COLUMN1 = (select T2.COLUMN1 from TABLE1 AS T2
where T2.PK = TABLE1.PK
and rownum = 1 )

MySQL: Update rows in table by iterating and joining with another one

I have a table papers
CREATE TABLE `papers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(1000) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
`my_count` int(11) NOT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `title_fulltext` (`title`),
) ENGINE=MyISAM AUTO_INCREMENT=1617432 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
and another table link_table
CREATE TABLE `auth2paper2loc` (
`auth_id` int(11) NOT NULL,
`paper_id` int(11) NOT NULL,
`loc_id` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
The id papers.id from the upper table is the same one like the link_table.paper_id in the second table. I want to iterate through every row in the upper table and count how many times this its id appears in the second table and store the "count" into the column "my_count" in the upper table.
Example: If The paper with tid = 1 = paper_id appears 5 times in the table link_table, then my_count = 5.
I can do that by a Python script but it results in too many querys and I have millions of entrys so it is really slow. And I can't figure out the right syntax to make this right inside of MySQL.
This is what I am iterating about in a for-loop in Python (too slow):
SELECT count(link_table.auth_id) FROM link_table
WHERE link_table.paper_id = %s
UPDATE papers SET auth_count = %s WHERE id = %s
Could someone please tell me how to create this one? There must be a way to nest this and put it directly in MySQL so it is faster, isn't there?
How does this perform for you?
update papers a
set my_count = (select count(*)
from auth2paper2loc b
where b.paper_id = a.id);
Use either:
UPDATE PAPERS
SET my_count = (SELECT COUNT(b.paper_id)
FROM AUTH2PAPERLOC b
WHERE b.paper_id = PAPERS.id)
...or:
UPDATE PAPERS
LEFT JOIN (SELECT b.paper_id,
COUNT(b.paper_id) AS numCount
FROM AUTH2PAPERLOC b
GROUP BY b.paper_id) x ON x.paper_id = PAPERS.id
SET my_count = COALESCE(x.numCount, 0)
The COALESCE is necessary to convert the NULL to a zero when there aren't any instances of PAPERS.id in the AUTH2PAPERLOC table.
update papers left join
(select paper_id, count(*) total from auth2paper2loc group by paper_id) X
on papers.id = X.paper_id
set papers.my_count = IFNULL(X.total, 0)

MySQL: UPDATE with SUM and JOIN

I'm trying to do a SUM and store it in another table. The SUM is simple :
SELECT award.alias_id,
SUM(award.points) AS points
FROM award
INNER JOIN achiever ON award.id = achiever.award_id
I now want to store that. I figured out how to do it on a row-by-row basis :
UPDATE aliaspoint
SET points = (SELECT SUM(award.points) AS points
FROM award
INNER JOIN achiever ON award.id = achiever.award_id
WHERE achiever.alias_id = 2000)
WHERE alias_id = 2000;
I thought something like this might work but I get:
ERROR 1111 (HY000): Invalid use of group function
UPDATE aliaspoint
INNER JOIN achiever ON aliaspoint.alias_id = achiever.alias_id
INNER JOIN award ON achiever.award_id = award.id
SET aliaspoint.points = SUM(award.points)
And some table definitions to help :
mysql> show create table aliaspoint;
| metaward_aliaspoint | CREATE TABLE `aliaspoint` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`alias_id` int(11) NOT NULL,
`points` double DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `alias_id` (`alias_id`),
KEY `aliaspoint_points` (`points`)
) ENGINE=MyISAM AUTO_INCREMENT=932081 DEFAULT CHARSET=latin1 |
mysql> show create table achiever;
| metaward_achiever | CREATE TABLE `achiever` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`modified` datetime NOT NULL,
`created` datetime NOT NULL,
`award_id` int(11) NOT NULL,
`alias_id` int(11) NOT NULL,
`count` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `achiever_award_id` (`award_id`),
KEY `achiever_alias_id` (`alias_id`)
) ENGINE=MyISAM AUTO_INCREMENT=87784996 DEFAULT CHARSET=utf8 |
mysql> show create table award;
| metaward_award | CREATE TABLE `award` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`points` double DEFAULT NULL,
PRIMARY KEY (`id`),
) ENGINE=MyISAM AUTO_INCREMENT=131398 DEFAULT CHARSET=utf8 |
You're missing the GROUP BY clause in:
SET points = (SELECT SUM(award.points) AS points
FROM award
INNER JOIN achiever ON award.id = achiever.award_id
WHERE achiever.alias_id = 2000)
There isn't enough information on the AWARD and ACHIEVER tables, so I recommend testing this before updating the UPDATE statement:
SELECT t.id, -- omit once confirmed data is correct
a.alias_id, -- omit once confirmed data is correct
SUM(t.points) AS points
FROM AWARD t
JOIN ACHIEVER a ON a.award_id = t.id
GROUP BY t.id, a.alias_id
Once you know the summing is correct, update the INSERT statement:
SET points = (SELECT SUM(t.points)
FROM AWARD t
JOIN ACHIEVER a ON a.award_id = t.id
WHERE a.alias_id = 2000 --don't include if you don't need it
GROUP BY t.id, a.alias_id)