I wanna insert a row when the name not exists in the table.
When the table is empty,it cannot insert anything, anyone can help me?
Here is my code:
INSERT INTO `ediftpdb`.`users`(
name
,passwd
,vendor
)
SELECT
'L001'
,'12345678a'
,'MKTPLS'
FROM `ediftpdb`.`users`
WHERE NOT EXISTS (SELECT * FROM `ediftpdb`.`users` WHERE name='L001' AND vendor = 'MKTPLS' ) LIMIT 1;
P.S.
I found a funny stuff, when ediftpdb.users is empty, code like below returns nothing.
SELECT
'L001'
,'12345678a'
,'MKTPLS'
FROM `ediftpdb`.`users`
The better way to do this is to create a unique multi-part index on name and vendor columns:
CREATE UNIQUE INDEX name_vendor ON ediftpdb.users( name, vendor )
Then:
INSERT IGNORE INTO ediftpdb.users ( name, passwd, vendor )
VALUES ( 'L001', '12345678a', 'MKTPLS' )
will do exactly what you want to do.
As #Martin Smith pointed, when the table ediftpdb.users is empty the FROM ediftpdb.users
results in no rows. If it had 100 rows, then your statement would try to INSERT 100 (identical) records into the table.
Try this:
INSERT INTO
...
SELECT
'L001'
,'12345678a'
,'MKTPLS'
FROM (SELECT 1) AS dummy
WHERE NOT EXISTS ...
Related
I would like to write a SQL statement that inserts a new row into the database if there isn't already a row for it. The unique identifier of a row is the id and url. Let's say the table schema looks like this:
LinkClicks: (id, url, clicks)
So now let's say I've got a row with a parameterized SQL insert. I'm attempting to do something like this:
INSERT (id, url, clicks)
INTO LinkClicks Values(#id, #url, #clicks)
WHERE #url NOT IN
(SELECT url FROM LinkClicks WHERE id=#id);
I think you want something like this:
INSERT INTO LinkClicks(id, url, clicks)
SELECT id, url, clicks
FROM (SELECT #id as id, #url as url, #clicks as clicks) t
WHERE t.url NOT IN (SELECT url FROM LinkClicks WHERE id = #id);
You can add a unique index on the id and url columns:
ALTER TABLE LinkClicks ADD UNIQUE u_idx (id, url);
With this constraint in place, attempts to insert a record whose id and url combination of values already appears will fail at the database level.
This might be preferable to the query you are attempting, because it guarantees that MySQL will reject a duplicate attempt to insert. A query could also be used to this effect, but later on perhaps someone else using your code base might forget this.
In fact you should take Tim's advice and put the unique index on the table but in doing so you need a fail safe way of ensuring that you don't attempt to put duplicates (id and url) into the table (otherwise loads of red-ink messages). This way seems ok:
DROP TABLE LINKCLICKS
DROP TABLE LINKCLICKS1
CREATE TABLE LINKCLICKS
(
[ID] INT,
[URL] CHAR(11),
CLICKS BIGINT
)
GO
INSERT INTO LINKCLICKS VALUES (1001,'www.abc.com',40000)
INSERT INTO LINKCLICKS VALUES (1002,'www.def.com',40000)
INSERT INTO LINKCLICKS VALUES (1003,'www.ghi.com',40000)
GO
CREATE TABLE LINKCLICKS1
(
[ID] INT,
[URL] CHAR(11),
CLICKS BIGINT
)
GO
INSERT INTO LINKCLICKS1 VALUES (1001,'www.abc.com',40000)
INSERT INTO LINKCLICKS1 VALUES (1003,'www.def.com',40000)
INSERT INTO LINKCLICKS1 VALUES (1004,'www.ghi.com',40000)
GO
WITH CTE1 AS
(
SELECT *,'d' AS [Source] FROM LINKCLICKS
UNION ALL
SELECT *,'s' AS [Source] FROM LINKCLICKS1
)
,
CTE2 AS
(
SELECT ID,[URL] FROM CTE1 GROUP BY ID,[URL] HAVING COUNT(ID) =1 AND COUNT([URL]) =1
)
INSERT INTO LINKCLICKS
SELECT ID,[URL],CLICKS
FROM CTE1
WHERE [Source] <> 'd'
AND
(
ID IN (SELECT ID FROM CTE2) AND [URL] IN (SELECT [URL] FROM CTE2)
)
SELECT * FROM LINKCLICKS ORDER BY [ID],URL
GO
The INSERT statement only inserts those rows where the ID and URL combined are not the same as rows already in the destination table. It quite happily inserts rows where either the IDs are the same but the URLs are different or where the IDs are different but the URLs are the same.
My only reservation is the question of 'dupes' in the source table (in this case LINKCLICKS1). If there are duplicates in the source table, none of them will be inserted into the destination table. This will defeat the object of the query.
The answer is, if you have duplicates, or any risk of duplication in the source table, then you should apply 'de-dupe code' to the source table before you run this.
If you need any de-dupe code, put a comment below.
I have 2 tables
test_table:
id data_text
1 *some text*
undo_test_table:
id data_text modification_date
.
CREATE TRIGGER undo_trigger BEFORE UPDATE
ON test_table
FOR EACH ROW
INSERT INTO undo_test_table SELECT *,NOW() AS modification_date
FROM test_table
WHERE id = NEW.id
What I try with that, is if one column on first table is modified then the trigger (undo_trigger) is fired and copy entire row to another table (undo_test_table )
But in the second table (undo_test_table ) I have one more column (modification_date)
The problem:
The above example working good but I don't know how to make that working if I change the (modification_date) column at first place instead as last place in (undo_test_table)
like this:
undo_test_table:
modification_date id data_text
I have tried :
SELECT NOW() AS modification_date,* FROM test_table ...
instead
SELECT *,NOW() AS modification_date FROM test_table ...
But got sintax error.
I think i need some like an UNION but I don't know how I can use NOW() AS modification_date in one UNION
You need to qualify the * with the table's name:
SELECT NOW() AS modification_date, t.*
-- Here ---------------------------^
FROM test_table
-- etc...
I am trying to populate a products table on MySQL with latest products, which are retrieved and stored in products_temp table.
So the method for this is straight forward, simply doing an INSERT to products from products_temp, as such:
INSERT INTO products ( select products_temp.* FROM products_temp )
Problem is, it results in a duplicate primary key error, because of the id from products_temp clashing with the id in products.
Can someone tell me how to fix this please?
I tried declaring the fields in the select statement without the id, but that results in "Column count doesn't match value count at row 1"
Any help would be appreciated.
Thanks!
You'll need to declare the columns except the ID on both the INSERT and the SELECT, since the number of fields need to match, and id (as you noticed) can't be inserted as is into the destination table.
INSERT INTO DestTable (field1, field2, field3)
SELECT field1, field2, field3 FROM SourceTable;
An SQLfiddle to test with.
EDIT: You could do it in a bit more hacky way to simplify the insert. You can create a trigger that simply forces the primary key to NULL on insert.
CREATE TRIGGER t_DT BEFORE INSERT ON DestTable
FOR EACH ROW
SET NEW.id = NULL;
then a copy from table to table can be done as simply;
INSERT INTO DestTable SELECT * FROM SourceTable;
Another SQLfiddle.
How about something like:
INSERT INTO products
(
select products_temp.* FROM products_temp
where key not in (select key from products)
)
I'm trying to insert an ingredient to an ingredients table if it doesn't exist.
I'm using the following syntax:
INSERT INTO ingredient(Name)
(
SELECT 'ingName' FROM dummytable WHERE
(SELECT count(*) FROM ingredient WHERE Name = 'ingName')=0)
This does not seem to work (0 rows affected), even though the SELECT query seem to return the desired result (an entry which contains "ingName").
The "ingredient" table has 2 columns: Name, id (id is auto incremented)
Thanks,
Li
Its better to add unique index on the name column:
ALTER TABLE `ingredient` ADD UNIQUE(`Name`)
After doing that you can use INSERT IGNORE:
INSERT IGNORE INTO `ingredient` ... /* anything */
That's because your inner query SELECT count(*) FROM ingredient WHERE Name = 'ingName' is returning a value > 0 and hence the upper query SELECT 'ingName' FROM dummytable WHERE is not selecting any rows and so no insert is happening.
I tried the same with a test table having 2 column name|value and it did worked fine
INSERT INTO test1(name) (
SELECT 'name' FROM test2 WHERE
(
SELECT count(*) FROM test2 WHERE name = 'bilboa'
)
=0
)
Inserted 2 rows with value name cause that's what I am selecting in select query and my test table 2 rows.
I'm having trouble getting an INSERT query to execute properly, and I can't seem to find anything on Google or Stack Overflow that solves this particular issue.
I'm trying to create a simple table for featured entries, where the entry_id is saved to the table along with it's current order.
My desired output is this:
If the featured table currently has these three entries:
featured_id entry_id featured_order
1 27 0
2 54 1
4 23 2
I want the next entry to save with featured_order=3.
I'm trying to get the following query to work with no luck:
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
VALUES
(
200,
(SELECT COUNT(*) AS `the_count` FROM `featured`)
)
The error I'm getting is: You can't specify target table 'featured' for update in FROM clause.
Can anyone help with a solution that gets the count without causing an error?
Thanks in advance!
Here is a cool thing: MySQL's INSERT . . . SELECT:
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
SELECT 200, COUNT(*) + 1
FROM `featured`
No subquery required.
#Bohemian has a good point:
Better to use max(featured_order) + 1 if you use this approach
So a better query would probably be:
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
SELECT 200, MAX(`featured_order`) + 1
FROM `featured`
His trigger method describe in his answer is also a good way to accomplish what you want.
The potential problem with query 1 is if you ever delete a row the rank will be thrown off, and you'll have a duplicate in featured_order. With the second query this is not a problem, but you will have gaps, just as if you were using an auto-increment column.
If you absolutely must have an order with no gaps the best solution I know of is to run this series of queries:
SET #pos:=0;
DROP TABLE IF EXISTS temp1;
CREATE TEMPORARY TABLE temp1 LIKE featured;
ALTER TABLE featured ORDER BY featured_order ASC;
INSERT INTO temp1 (featured_id, entry_id, featured_order)
SELECT featured_id, entry_id, #pos:=#pos+1 FROM words;
UPDATE featured
JOIN temp1 ON featured.featured_id = temp1.featured_id
SET featured.rank = temp1.rank;
DROP TABLE temp1;
Whenever you delete a row
Use a trigger:
drop trigger if exists featured_insert_trigger;
delimiter //
create trigger featured_insert_trigger before insert on featured
for each row
begin
set new.featured_order = ifnull((select max(featured_order) from featured), -1) + 1;
end; //
delimiter ;
Now your inserts look like this:
insert into featured (entry_id) values (200);
featured_order will be set to the highest featured_order value plus one. This caters for rows being deleted/updated and always guarantee uniqueness.
The ifnull is there in case there are no rows in the table, in which case the first value will be zero.
This code has been tested as works correctly.
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
VALUES
(
200,
(SELECT COUNT(*) AS `the_count` FROM `featured` F1)
)
Correction is just adding "F1" table alias.
This standard sql solution works fine on various dbms (not only mysql)
I also suggest an improvement over:
SELECT COUNT(*) +1 (Problem: if some row gets deleted you may collide with existing index)
SELECT MAX(featured_order)+1 (Problem: the first insert with empty table gets error)
SELECT (COALESCE(MAX(featured_order), 0)+1) (no Problem)
You have to simpley use alias that will solve the problem :
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
VALUES
(
200,
(SELECT COUNT(*) AS `the_count` FROM `featured` as f1)
)
From the MySQL manual regarding subqueries:
Another restriction is that currently you cannot modify a table and select from the same table in a subquery.
Perhaps an alias or a join (otherwise useless) in the subquery would help here.
EDIT: It turns out that there's a work-around. The work-around is described http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/.