MYSQL update into select 3 tables - mysql

I use this query (insert into select 3 tables) to insert my rows in the mysql table.
"INSERT INTO test (catid_1, descat_1, catid_2, descat_2, id_user, user)
SELECT '$_POST[cat_1]',t1.desc AS descat_1, '$_POST[cat_2]', t2.desc AS descat_2,
$_POST[id_user]',t3.user FROM t1, t2, t3
WHERE t1.idcat_1='$_POST[cat_1]' and t2.idcat_2='$_POST[cat_2]'
and t3.id_user='$_POST[id_user]'";
Now I'd like to use the same logic to UPDATE my rows (update into select 3 table) in the mysql table.
tables structure
t1
`idcat_1` int(11) NOT NULL AUTO_INCREMENT,
`desc` varchar(100) NOT NULL,
PRIMARY KEY (`idcat_1`)
t2
`idcat_2` int(11) NOT NULL AUTO_INCREMENT,
`idcat_1` int(11) NOT NULL,
`desc` varchar(100) NOT NULL,
PRIMARY KEY (`idcat_2`)
t3
`id_user` int(11) NOT NULL AUTO_INCREMENT,
`user` varchar(40) NOT NULL,
PRIMARY KEY (`id_user`)
Is it possible to do?
Thanks

Like this:
UPDATE test AS t
INNER JOIN t1 ON -- join conditon
INNER JOIN t2 ON ...
INNER JOIN t3 ON ...
SET t.catid_1 = '$_POST[cat_1]',
t.descat_1 = t1.desc,
....
WHERE t1.idcat_1='$_POST[cat_1]'
and t2.idcat_2='$_POST[cat_2]'
and t3.id_user='$_POST[id_user]'
It is not clear how the four tables are joined, you will need to supply the join condition for each JOIN.
Update 1
From the tables' structures that you just posted in your updated question, it seems like neither of the three tables test, t1 nor t2 related to the table t3 by any keys. In this key you didn't need to join with this table t3 and only join the tables test, t1 and t2. Assuming that:
test relates to t1 with test.catid_1 = t1.idcat_1.
t1 relates to t2 with t1.idcat_1 = t2.idcat_1.
Like this:
UPDATE test AS t
INNER JOIN t1 ON t.catid_1 = t1.idcat_1
INNER JOIN t2 ON t1.idcat_1 = t2.idcat_1
SET t.catid_1 = '$_POST[cat_1]',
t.descat_1 = t1.desc,
....
WHERE t1.idcat_1='$_POST[cat_1]'
and t2.idcat_2='$_POST[cat_2]'

Related

SQL - Left Join and Group By causes row data from second table to get mixed up

I have two tables, the first table has a reference to the id from the second table, I want to make a query involving a left join with fields from the second table as well as with a COUNT function in the select, because of the COUNT function, I am using an GROUP BY clause.
So my query looks something like:
SELECT t1.id, t1.txt, t2.id, t2.txt, COUNT(t2.id)
FROM test_data1 t1
LEFT JOIN test_data2 t2 ON (t1.ref_col = t2.id)
GROUP BY t1.id
In my tables, only the second row of test_data1 has an entry in ref_col, so I would expect that for the first row in the results, the value for t2.id would be NULL, however that is not the case (in my example I see the value 2, but I'm not sure if there might be an element of randomness here).
If I use
SELECT MAX(t1.id), MAX(t1.txt), MAX(t2.id), MAX(t2.txt), COUNT(t2.id)
FROM test_data1 t1
LEFT JOIN test_data2 t2 ON (t1.ref_col = t2.id)
GROUP BY t1.id
I get my expected results, however I am surprised this is necessary given that there will at most only be one entry in test_data2 matching ref_col in test_data1.
Does anyone know why LEFT JOIN + GROUP BY is behaving this way? This is using MySQL version 8 on Linux.
If you want to reproduce this here are the table definitions:
CREATE TABLE test_data1 (id int unsigned NOT NULL AUTO_INCREMENT,
txt VARCHAR(45) DEFAULT NULL,
ref_col int unsigned DEFAULT NULL, PRIMARY KEY (id));
CREATE TABLE test_data1 (id int unsigned NOT NULL AUTO_INCREMENT,
txt VARCHAR(45) DEFAULT NULL,
ref_col int unsigned DEFAULT NULL, PRIMARY KEY (id));
INSERT INTO test_data1 (id, txt, ref_col)
VALUES
(1,'zz',NULL),
(2,'yy',2),
(3,'xx',NULL);
INSERT INTO test_data2 (id, txt)
VALUES
(1,'aa'),
(2,'bb'),
(3,'cc'),
(4,'dd');

compare data in a table

I have a scenario in which I have to check whether a data already exist in a table or not. If a user n application already exists then we don't need to perform any operation else perform insertion.
CREATE TABLE `table1` (
`ID` INT(11) NOT NULL AUTO_INCREMENT,
`GroupName` VARCHAR(100) DEFAULT NULL,
`UserName` VARCHAR(100) DEFAULT NULL,
`ApplicationName` VARCHAR(100) DEFAULT NULL,
`UserDeleted` BIT DEFAULT 0,
PRIMARY KEY (`ID`)
)
CREATE TABLE `temp_table` (
`ID` INT(11) NOT NULL AUTO_INCREMENT,
`GroupName` VARCHAR(100) DEFAULT NULL,
`UserName` VARCHAR(100) DEFAULT NULL,
`ApplicationName` VARCHAR(100) DEFAULT NULL,
PRIMARY KEY (`ID`)
)
table1 is the main table while temp_table from which I have to perform comparision.
Sample date script:
INSERT INTO `table1`(`ID`,`GroupName`,`UserName`,`ApplicationName`,`userdeleted`)
VALUES
('MidasSQLUsers','Kevin Nikkhoo','MySql Application',0),
('MidasSQLUsers','adtest','MySql Application',0),
('Salesforce','Kevin Nikkhoo','Salesforce',0),
('Salesforce','devendra talmale','Salesforce',0);
INSERT INTO `temp_table`(`ID`,`GroupName`,`UserName`,`ApplicationName`,`userdeleted`)
VALUES
('MidasSQLUsers','Kevin Nikkhoo','MySql Application',0),
('MidasSQLUsers','adtest','MySql Application',0),
('Salesforce','Kevin Nikkhoo','Salesforce',0),
('Salesforce','Kapil Singh','Salesforce',0);
Also if a row of temp_table does not exist int table1 then its status should be as userdeleted 1 as i mentioned in desired output.
Result: table1
ID GroupName UserName ApplicationName Deleted
1 MidasSQLUsers Kevin Nikkhoo MySql Application 0
2 MidasSQLUsers adtest MySql ApplicationName 0
3 Salesforce Kevin Nikkhoo Salesforce 0
4 Salesforce devendra talmale Salesforce 1
5 SalesForce Kapil Singh Salesforce 0
Please help
this should do the trick, change whatever is inside the concat, to met your specification.
first do one update to "delete" the rows that are not in tempTable:
update table t1 set deleted = 'YES'
where concat( t1.groupName, t1.Username, t1.application) NOT IN
(select concat( t2.groupName, t2.Username, t2.application) from tempTable t2);
second: insert the new records
insert into table1 t1 (t1.groupName, t1.username, t1.application_name, t1.deleted)
(select t2.groupName, t2.Username, t2.application, t2.deleted from tempTable t2
where concat(t2.userName, t2.application, t2.groupName, t2.deleted) **not in**
(select concat(t3.userName, t3.application, t3.groupName, t3.deleted)
from table1 t3)
the concat function will make a new row from existing rows... this way I can compare multiple fields at same time as if I was comparing only one...
the "not in" lets make you a query inside a query...
Slight variation on the above queries.
Using JOINs, which if you have an index on the userName, application and groupName fields will likely be faster
UPDATE table1 t1
LEFT OUTER JOIN temp_table t2
ON t1.userName = t2.userName
AND t1.application = t2.application
AND t1.groupName = t2.groupName
SET t1.deleted = CASE WHEN t2.ID IS NULL THEN 1 ELSE 0 END
For the normal insert
INSERT INTO table1 t1 (t1.groupName, t1.username, t1.application_name, t1.deleted)
(SELECT t2.groupName, t2.Username, t2.application, t2.deleted
FROM tempTable t2
LEFT OUTER JOIN table1 t3
ON t2.userName = t3.userName
AND t2.application = t3.application
AND t2.groupName = t3.groupName
WHERE t3.ID IS NULL)

MySQL Join Slow Query

I have 2 table t1 -> t2 (common one to many relationship) with 140.000 records on table t2 reffering 50.000 records on t1, foreing key some times is null (no parent).
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`),
KEY `name_idx` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=125666 DEFAULT CHARSET=utf8
CREATE TABLE `t2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`t1_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `t1_id_idx` (`t1_id`)
CONSTRAINT `t1_fk` FOREIGN KEY (`t1_id`) REFERENCES `t1` (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=125666 DEFAULT CHARSET=utf8
This query running on 15 seconds:
SELECT * FROM t2
LEFT JOIN t1 ON t2.t1_id = t1.id
ORDER BY t1.name ASC
LIMIT 10;
This query running on 0.5 seconds:
SELECT * FROM t2
LEFT JOIN t1 ON t2.t1_id = t1.id
WHERE t1.name <> 'any not found value'
ORDER BY t1.name ASC
LIMIT 10;
Can any body explain to me why this occurs?
Obs: Edited.
News:
This query running on 0.06 seconds: (WHAT'S CHANGE? inner join!!)
SELECT * FROM t2
INNER JOIN t1 ON t2.t1_id = t1.id
ORDER BY t1.name ASC
LIMIT 10;
but above query does not is a solution for my, in my case t2.t1_id can be null some times.
Any Idea??
News:
Running explain with left and inner join:
Mysql show: Using temporary; Using filesort; Rows: 140.000
With Inner Join:
Mysql show: Using Where; Rows: 8
Solved!
The Problem is on order by, when using order by mysql create a temporaty file (Explain...Using Temporary), this temporary file is too big causing the lag.
Tips:
Avoid Using Tempoaray
When Using temporary don't load much data.
I suspect you already have an index on t1.name but it is descending not ascending. That explains why the second query is so much faster.
The other explanation is the first query was not cached but the second query found data in the cache and ran faster.

How to optimize MySQL UPDATE

Please is there any way how to optimize this update query in MySql?
UPDATE table1 t1
SET t1.column =
(SELECT MIN(t2.column)
FROM table2 t2 WHERE t1.id = t2.id
);
Both tables have around 250 000 records.
Table structure:
CREATE TABLE `table1` (
`id` int(11) NOT NULL,
`column` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `table2` (
`code` int(11) NOT NULL,
`id` int(11) NOT NULL,
`column` datetime NOT NULL,
PRIMARY KEY (`code, `id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
ALTER TABLE table2 ADD CONSTRAINT FK_id
FOREIGN KEY (id) REFERENCES table1 (id)
;
Thank you for help.
this is how I would do it :
create a temporary table to hold aggregated values
CREATE TEMPORARY TABLE tmp_operation
SELECT id, MIN(`column`) as cln FROM table2 GROUP BY id;
add index to temporary table for faster join to table 1 (can omit this step depending on data size)
ALTER TABLE tmp_operation ADD UNIQUE INDEX (id);
update with simple join. you can use left or inner join depending if you want to update columns to nulls)
UPDATE table1
SET table1.`column` = tmp_operation.cln
INNER JOIN tmp_operation ON table1.id = tmp_operation.id;
drop temporary table after done
DROP TABLE tmp_operation;
You could do it by first grouping table t2 and then use JOIN (this is similar to #frail's answer but without the temporary table):
UPDATE
table1 t1
JOIN
( SELECT id
, MIN(column) AS min_column
FROM table2
GROUP BY id
) AS t2
ON t2.id = t1.id
SET t1.column = t2.min_column ;
An index at table2, on (id, column) would help performance.
Add forign key in table2 of table1 primary key
UPDATE table1 t1
INNER JOIN table2 t2
ON t1.id = t2.id
SET t1.column = t2.column
having MIN(t2.column)
examples

delete rows from multiple tables

I'm trying to use SQL to delete multiple rows from multiple tables that are
joined together.
Table A is joined to Table B
Table B is joined to Table C
I want to delete all rows in table B & C that correspond to a row in Table A
CREATE TABLE `boards` (
`boardid` int(2) NOT NULL AUTO_INCREMENT,
`boardname` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`boardid`)
);
-- --------------------------------------------------------
--
-- Table structure for table `messages`
--
CREATE TABLE `messages` (
`messageid` int(6) NOT NULL AUTO_INCREMENT,
`boardid` int(2) NOT NULL DEFAULT '0',
`topicid` int(4) NOT NULL DEFAULT '0',
`message` text NOT NULL,
`author` varchar(255) NOT NULL DEFAULT '',
`date` datetime DEFAULT NULL,
PRIMARY KEY (`messageid`)
);
-- --------------------------------------------------------
--
-- Table structure for table `topics`
--
CREATE TABLE `topics` (
`topicid` int(4) NOT NULL AUTO_INCREMENT,
`boardid` int(2) NOT NULL DEFAULT '0',
`topicname` varchar(255) NOT NULL DEFAULT '',
`author` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`topicid`)
);
Well, if you had used InnoDB tables, you could set up a cascading delete with foreign keys that would do it all automatically. But if you have some reason for using MyISAM, You just use a multiple-table DELETE:
DELETE FROM boards, topics, messages
USING boards INNER JOIN topics INNER JOIN messages
WHERE boards.boardid = $boardid
AND topics.boardid = boards.boardid
AND messages.boardid = boards.boardid;
this can be done by your db-system if you are using foreign keys with "on delete cascade".
Take a look here:
http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html
You could either just check for presence
delete from topics where boardid in (select boardid from boards)
delete from messages where boardid in (select boardid from boards)
but this would only make sense if this behaviour should not always apply. When the behaviour should always apply, implement foreign keys with delete on cascade
explained on a zillion sites, in your helpfiles and here
Deleting rows from multiple tables can be done in two ways :
Delete rows from one table, determining which rows to delete by referring to another
table
Delete rows from multiple tables with a single statement
Multiple-table DELETE statements can be written in two formats. The following example demonstrates one syntax, for a query that deletes rows from a table t1 where the id values match those in a table t2:
DELETE t1 FROM t1, t2 WHERE t1.id = t2.id;
The second syntax is slightly different:
DELETE FROM t1 USING t1, t2 WHERE t1.id = t2.id;
To delete the matching records from both tables, the statements are:
DELETE t1, t2 FROM t1, t2 WHERE t1.id = t2.id;
DELETE FROM t1, t2 USING t1, t2 WHERE t1.id = t2.id;
The ORDER BY and LIMIT clauses normally supported by UPDATE and DELETE aren’t allowed when these statements are used for multiple-table operations.