I have two tables: second table have foreign key, that references primary key of the first table. And when I insert data in the second table, I want to check first, if a row with iputed key exists in the first table. In T-SQL it would look like this:
create procedure insert_order_products
# order_id int
# product_id int
AS
IF EXISTS (SELECT * FROM order where order.id=order_id)
IF EXISTS (SELECT * FROM product where product.id=product_id)
INSERT INTO order_products values(some values)
How to check IF EXISTS in mysql?
I think you can try to use the following query (INSERT with SELECT and WHERE)
INSERT order_products(col1,col2,...,colN)
SELECT #val1,#val2,...,#valN
WHERE EXISTS(SELECT * FROM order WHERE id=#order_id)
AND EXISTS(SELECT * FROM product WHERE id=#product_id)
In MySQL I think it'll be like following
INSERT order_products(col1,col2,...,colN)
SELECT #val1,#val2,...,#valN
FROM DUAL
WHERE EXISTS(SELECT * FROM order WHERE id=#order_id)
AND EXISTS(SELECT * FROM product WHERE id=#product_id)
Or you can use
INSERT order_products(col1,col2,...,colN)
SELECT #val1,#val2,...,#valN
FROM (SELECT * FROM order WHERE id=#order_id) o
CROSS JOIN (SELECT * FROM product WHERE id=#product_id) p
I think the last variant is better.
Related
Consider these example tables
E_id in Table1 is a primary key. From and Assign_to are foreign keys referenced with E_id.
I want to show a table like this:
I am not sure how I can implement it. Please share the SQL query which returns the desired table.
You could JOIN to Table1 twice:
SELECT
t2.work_name,
t1f.E_name AS `From`,
t1a.E_Name AS `Assign_to`
FROM Table2 t2
INNER JOIN Table1 t1f
ON t1f.E_id = t2.`from`
INNER JOIN Table1 t1a
ON t1a.E_id =t2.Assign_to
You can solve that problem with a simple temp table. It is not the most sophisticated way to solve it, but the solution is easy to comprehend.
The step are as followed:
Create a table with all data from table2
Add 2 columns to that table to store the name values for from and Assign_to
Update the columns with the name values from table1
Select your Data
MySQL-Code
-- create temp-table
CREATE TABLE table2_temp
SELECT * FROM table2;
-- add columns to enrich table with E_name from table1
ALTER TABLE table2_temp
ADD COLUMN E_name_from VARCHAR (125),
ADD COLUMN E_name_assign_to VARCHAR (125);
-- update temp-table with names from table1
-- for E_name_from
UPDATE table2_temp A
INNER JOIN table1 B ON (A.`from` = E_id)
SET A.E_name_from = B.E_name;
-- for E_name_assign_to
UPDATE table2_temp A
INNER JOIN table1.B ON (A.Assign_to = E_id)
SET A.E_name_assign_to = B.E_name;
-- now you can select your date from the temp-table
SELECT
work_name,
E_name_from AS `From`,
E_name_assign_to AS `Assign_to`
FROM
table2_temp;
-- drop table after work is done
drop table if exists table2_temp ;
I have two tables A and B, in the B there is a foreign key from A, what I want to do is to delete all the rows from A that they don't have an occurrence in B, I execute the following query but it's not working :
DELETE from A
WHERE id_A
not in (select DISTINCT(foreign_key_of_A_in_B) from B)
Any idea ?
My first recommendation is to try not exists rather than not in:
DELETE a FROM a
WHERE NOT EXISTS (SELECT 1 FROM b WHERE b.foreign_key_of_A_in_B = a.id_A);
NOT IN returns false or NULL if any value in the subquery is NULL. That is how the operator is defined. NOT EXISTS has more expected behavior. So, if you have any NULL values in the subquery, this will work (i.e. delete rows) but the NOT IN version will not.
I would recommend that you try the logic out using SELECT before doing a DELETE:
SELECT A.*
FROM A
WHERE NOT EXISTS (SELECT 1 FROM b WHERE b.foreign_key_of_A_in_B = A.id_A);
A standard for DELETE FROM table WHERE id NOT IN would look like this:
DELETE from Table_A
WHERE id -- ID of Table_A
not in (select ID FROM Table_B)
This should find the IDs not in Table A from Table B, as your question states
Try this in a SELECT statement first to see if it returns the correct rows:
SELECT * from Table_A
WHERE id -- ID of Table_A
not in (select ID FROM Table_B)
Don't forget to cross-reference some rows to double check.
I need to update a table, and the Where clause should contain the last (or max) from a certain column, so I made this query:
UPDATE Orders
SET Ordermethod='Pickup'
WHERE orderid IN (
SELECT MAX(orderid)
FROM Orders);
But, for some reason I don't understand, mysql returns this error:
1093 - You can't specify target table 'Bestellingen' for update in FROM clause
I tried different queries, which aren't working either...
Can someone help??
Sorry for the crappy english
This is a MySQL limitation. (As the documentation puts it: "Currently, you cannot update a table and select from the same table in a subquery.") You can work around the limitation by writing your subquery as (SELECT * FROM (SELECT ...) t), so that MySQL will create a temporary table for you:
UPDATE Orders
SET Ordermethod='Pickup'
WHERE orderid IN
( SELECT *
FROM ( SELECT MAX(orderid)
FROM Orders
) t
)
;
UPDATE Orders
SET Ordermethod='Pickup'
WHERE orderid IN( SELECT MAX(orderid) FROM
(
SELECT * FROM Orders
)
AS c1
)
I am having problem with selecting values from table a (id, room_name) where there are no corresponding events in table b (room_id, room_start, room_finish)
my query looks following
SELECT id, room_name FROM rooms
WHERE NOT EXISTS
(SELECT * FROM room_events
WHERE room_start BETWEEN '1294727400' AND '1294729200'
OR
room_finish BETWEEN '1294727400' AND '1294729200')
table a contains multiple rooms, table b contains room events
I am getting no results in case there is any event for any of the rooms within the timestamps. I am expecting all rooms having NO events.
Here is the prototype for what you want to do:
SELECT * FROM table1 t1
WHERE NOT EXISTS (SELECT 1 FROM table2 t2 WHERE t1.id = t2.id)
Here, id is assumed to be the PK and FK in both tables. You should adjust accordingly. Notice also that it is important to compare PK and FK in this case.
So, here is how your query should look like:
SELECT id, room_name FROM rooms r
WHERE NOT EXISTS
(SELECT * FROM room_events re
WHERE
r.room_id = re.room_id
AND
(
room_start BETWEEN '1294727400' AND '1294729200'
OR
room_finish BETWEEN '1294727400' AND '1294729200')
)
If you want, you check the parts of your query by executing them in mysql client. For example, you can make sure if the following returns any records or not:
SELECT * FROM room_events
WHERE room_start BETWEEN '1294727400' AND '1294729200'
OR
room_finish BETWEEN '1294727400' AND '1294729200'
If it doesn't, you have found the culprit and act accordingly with other parts :)
You are missing to use only the events from that room. That is done by matching the id.
SELECT id, room_name FROM rooms r
WHERE NOT EXISTS
(SELECT * FROM room_events re
WHERE r.id = re.room_id AND
room_start BETWEEN '1294727400' AND '1294729200'
OR
room_finish BETWEEN '1294727400' AND '1294729200')
I have a table with some ids + titles. I want to make the title column unique, but it has over 600k records already, some of which are duplicates (sometimes several dozen times over).
How do I remove all duplicates, except one, so I can add a UNIQUE key to the title column after?
This command adds a unique key, and drops all rows that generate errors (due to the unique key). This removes duplicates.
ALTER IGNORE TABLE table ADD UNIQUE KEY idx1(title);
Edit: Note that this command may not work for InnoDB tables for some versions of MySQL. See this post for a workaround. (Thanks to "an anonymous user" for this information.)
Create a new table with just the distinct rows of the original table. There may be other ways but I find this the cleanest.
CREATE TABLE tmp_table AS SELECT DISTINCT [....] FROM main_table
More specifically:
The faster way is to insert distinct rows into a temporary table. Using delete, it took me a few hours to remove duplicates from a table of 8 million rows. Using insert and distinct, it took just 13 minutes.
CREATE TABLE tempTableName LIKE tableName;
CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value);
INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName;
DROP TABLE tableName;
INSERT tableName SELECT * FROM tempTableName;
DROP TABLE tempTableName;
Since the MySql ALTER IGNORE TABLE has been deprecated, you need to actually delete the duplicate date before adding an index.
First write a query that finds all the duplicates. Here I'm assuming that email is the field that contains duplicates.
SELECT
s1.email
s1.id,
s1.created
s2.id,
s2.created
FROM
student AS s1
INNER JOIN
student AS s2
WHERE
/* Emails are the same */
s1.email = s2.email AND
/* DON'T select both accounts,
only select the one created later.
The serial id could also be used here */
s2.created > s1.created
;
Next select only the unique duplicate ids:
SELECT
DISTINCT s2.id
FROM
student AS s1
INNER JOIN
student AS s2
WHERE
s1.email = s2.email AND
s2.created > s1.created
;
Once you are sure that only contains the duplicate ids you want to delete, run the delete. You have to add (SELECT * FROM tblname) so that MySql doesn't complain.
DELETE FROM
student
WHERE
id
IN (
SELECT
DISTINCT s2.id
FROM
(SELECT * FROM student) AS s1
INNER JOIN
(SELECT * FROM student) AS s2
WHERE
s1.email = s2.email AND
s2.created > s1.created
);
Then create the unique index:
ALTER TABLE
student
ADD UNIQUE INDEX
idx_student_unique_email(email)
;
Below query can be used to delete all the duplicate except the one row with lowest "id" field value
DELETE t1 FROM table_name t1, table_name t2 WHERE t1.id > t2.id AND t1.name = t2.name
In the similar way, we can keep the row with the highest value in 'id' as follows
DELETE t1 FROM table_name t1, table_name t2 WHERE t1.id < t2.id AND t1.name = t2.name
This shows how to do it in SQL2000. I'm not completely familiar with MySQL syntax but I'm sure there's something comparable
create table #titles (iid int identity (1, 1), title varchar(200))
-- Repeat this step many times to create duplicates
insert into #titles(title) values ('bob')
insert into #titles(title) values ('bob1')
insert into #titles(title) values ('bob2')
insert into #titles(title) values ('bob3')
insert into #titles(title) values ('bob4')
DELETE T FROM
#titles T left join
(
select title, min(iid) as minid from #titles group by title
) D on T.title = D.title and T.iid = D.minid
WHERE D.minid is null
Select * FROM #titles
delete from student where id in (
SELECT distinct(s1.`student_id`) from student as s1 inner join student as s2
where s1.`sex` = s2.`sex` and
s1.`student_id` > s2.`student_id` and
s1.`sex` = 'M'
ORDER BY `s1`.`student_id` ASC
)
The solution posted by Nitin seems to be the most elegant / logical one.
However it has one issue:
ERROR 1093 (HY000): You can't specify target table 'student' for
update in FROM clause
This can however be resolved by using (SELECT * FROM student) instead of student:
DELETE FROM student WHERE id IN (
SELECT distinct(s1.`student_id`) FROM (SELECT * FROM student) AS s1 INNER JOIN (SELECT * FROM student) AS s2
WHERE s1.`sex` = s2.`sex` AND
s1.`student_id` > s2.`student_id` AND
s1.`sex` = 'M'
ORDER BY `s1`.`student_id` ASC
)
Give your +1's to Nitin for coming up with the original solution.
Deleting duplicates on MySQL tables is a common issue, that usually comes with specific needs. In case anyone is interested, here (Remove duplicate rows in MySQL) I explain how to use a temporary table to delete MySQL duplicates in a reliable and fast way (with examples for different use cases).
In this case, something like this should work:
-- create a new temporary table
CREATE TABLE tmp_table1 LIKE table1;
-- add a unique constraint
ALTER TABLE tmp_table1 ADD UNIQUE(id, title);
-- scan over the table to insert entries
INSERT IGNORE INTO tmp_table1 SELECT * FROM table1 ORDER BY sid;
-- rename tables
RENAME TABLE table1 TO backup_table1, tmp_table1 TO table1;