Update with select in mysql - 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 )

Related

Mysql 1093 - Table is specified twice

I have really searched and this question has been answered here
1093 Error in MySQL table is specified twice
but the answer doesn't help me
I have this accounts table
But I am facing error 1093 - Table is specified twice, when trying to update account balance
Although I give the table two names t1 and t2
UPDATE accounts t1
SET Account_Balance = Account_Balance+(
SELECT SUM(Credit)-SUM(Debit)
FROM accounts t2
WHERE Account_Id=1
)
Create accounts table statement
CREATE TABLE `accounts` (
`Account_Id` int(11) NOT NULL AUTO_INCREMENT,
`Account_Name` varchar(100) NOT NULL,
`Account_Name_English` varchar(50) NOT NULL,
`Account_Balance` decimal(15,2) NOT NULL DEFAULT '0.00',
`Credit` decimal(15,2) NOT NULL DEFAULT '0.00',
`Debit` decimal(15,2) NOT NULL DEFAULT '0.00',
PRIMARY KEY (`Account_Id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8
Using an alias doesn't solve the problem of not being able to specify a table that is being updated in a SELECT on the right hand side of an expression. One way to work around this issue is to use a multi-table UPDATE:
UPDATE accounts t1
CROSS JOIN (SELECT SUM(Credit)-SUM(Debit) AS `change`
FROM accounts
WHERE Account_Id=1) t2
SET t1.Account_Balance = t1.Account_Balance + t2.change
Note I'm not sure the location of the WHERE Account_Id = 1 is correct; this will update all Account_Balance fields in accounts to their old balance plus the change from Account_Id 1. If that is what you want, this is fine, otherwise you might need an additional WHERE clause on the UPDATE i.e.
UPDATE accounts t1
CROSS JOIN (SELECT SUM(Credit)-SUM(Debit) AS `change`
FROM accounts
WHERE Account_Id=1) t2
SET t1.Account_Balance = t1.Account_Balance + t2.change
WHERE Account_Id = 1
Or to update all accounts with their own change:
UPDATE accounts t1
JOIN (SELECT Account_Id, SUM(Credit)-SUM(Debit) AS `change`
FROM accounts
GROUP BY Account_Id) t2 ON t2.Account_Id = t1.Account_Id
SET t1.Account_Balance = t1.Account_Balance + t2.change
Here's a demo of all three queries in operation.

mysql dependent subquery stops working when using a constant

Using MySQL 5.7.17-log
We have a number of report queries using a dependent subquery in the select statement that is returning null when there should be a value. I know this style can be refactored into a left join but I wanted to understand the reason we are having this problem and possibly file a bug with MySQL. Here is the simplest way to reproduce this:
CREATE TABLE tableA (
id varchar(36) NOT NULL,
col2 int(10) unsigned zerofill NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
;
CREATE TABLE tableB (
id varchar(36) NOT NULL,
col2 int(10) unsigned zerofill NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE tableC (
refA varchar(36) NOT NULL,
refB varchar(36) NOT NULL,
PRIMARY KEY (refA, refB),
CONSTRAINT fkCA FOREIGN KEY (refA) REFERENCES tableA (id),
CONSTRAINT fkCB FOREIGN KEY (refB) REFERENCES tableB (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE tableD (
refA varchar(36) NOT NULL,
refB varchar(36) NOT NULL,
col3 int(10) unsigned zerofill NOT NULL,
PRIMARY KEY (refA, refB),
CONSTRAINT fkDA FOREIGN KEY (refA) REFERENCES tableA (id),
CONSTRAINT fkDB FOREIGN KEY (refB) REFERENCES tableB (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
insert into tableA values ('123',5)
;
insert into tableB values ('234',6)
;
insert into tableC values ('123','234')
;
insert into tableD values ('123','234',7)
;
select a.id as 'aid',
b.id as 'bib',
( select d.col3 from tableD d where d.refA=a.id and d.refB=b.id ) as 'shouldBe7'
from tableA a
inner join tableC c on c.refA = a.id
inner join tableB b on c.refB = b.id
where a.id='123'
group by a.id, b.id
;
The select statement produces ['123','234',null] although I would expect ['123','234',7]. If you remove the where clause in the statement (where a.id='123'), the expected result - ['123','234',7] is what you get.
I did an explain on the whole select statement and saw that the "ref" uses a func which I did a SHOW WARNINGS and the dependent subquery is comparing the id against an empty string.
(/* select#2 */ select dev.d.col3 from dev.tableD d where ((dev.d.refA = '') and (dev.d.refB = dev.b.id))) AS shouldBe7
Seems like a 5.7 bug...I've filed http://bugs.mysql.com/87915 . the db-fiddle tool was helpful - thanks James!
This ran out of the box for me on 10.1.25-MariaDB locally:
Tried this 5.6 fiddle and it worked.
Tried this 5.7 fiddle and it also worked
I had a look at your code but couldn't see any obvious causes of this error, have you tried on other 5.7 instances to rule out any possible local causes?
Regards,
James
Try this instead...there's always more than one way to skin a cat.
select a.id as 'aid',
b.id as 'bib',
d.col3 as 'shouldBe7'
from tableA a
inner join tableC c on c.refA = a.id
inner join tableB b on c.refB = b.id
inner join ( select col3, refA, refB from tableD ) as d
on d.refA=a.id and d.refB=b.id
where a.id='123'
group by a.id, b.id
;

Update Table by getting maximum value from another table

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`

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 statement causes fields to be updated with NULL or maximum value

If you had to pick one of the two following queries, which would you choose and why:
UPDATE `table1` AS e
SET e.points = e.points+(
SELECT points FROM `table2` AS ep WHERE e.cardnbr=ep.cardnbr);
or:
UPDATE `table1` AS e
INNER JOIN
(
SELECT points, cardnbr
FROM `table2`
) AS ep ON (e.cardnbr=ep.cardnbr)
SET e.points = e.points+ep.points;
Tables' definitions:
CREATE TABLE `table1` (
`cardnbr` int(10) DEFAULT NULL,
`name` varchar(50) DEFAULT NULL,
`points` decimal(7,3) DEFAULT '0.000',
`email` varchar(50) NOT NULL DEFAULT 'user#company.com',
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=25205 DEFAULT CHARSET=latin1$$
CREATE TABLE `table2` (
`cardnbr` int(10) DEFAULT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
`points` decimal(7,3) DEFAULT '0.000',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci$$
UPDATE: BOTH are causing problems the first is causing non matched rows to update into NULL.
The second is causing them to update into the max value 999.9999 (decimal 7,3).
PS the cardnbr field is NOT a key
I prefer the second one..reason for that is
When using JOIN the databse can create an execution plan that is better for your query and save time whereas subqueries (like your first one ) will run all the queries and load all the datas which may take time.
i think subqueries is easy to read but performance wise JOIN is faster...
First, the two statements are not equivalent, as you found out yourself. The first one will update all rows of table1, putting NULL values for those rows that have no related rows in table2.
So the second query looks better because it doesn't update all rows of table1. It could be written in a more simpel way, like this though:
UPDATE table1 AS e
INNER JOIN table2 AS ep
ON e.cardnbr = ep.cardnbr
SET e.points = e.points + ep.points ;
So, the 2nd query would be the best to use, if cardnbr was the primary key of table2. Is it?
If it isn't, then which values from table2 should be used for the update of table1 (added to points)? All of them? You could use this:
UPDATE table1 AS e
INNER JOIN
( SELECT SUM(points) AS points, cardnbr
FROM table2
GROUP BY cardnbr
) AS ep ON e.cardnbr = ep.cardnbr
SET
e.points = e.points + ep.points ;
Just one of them? That would require some other derived table, depending on what you want.