views:

1875

answers:

4

I have a MySQL database and I would like to insert some values into one table, assuming that a particular value that I am inserting does not match a value in a different table.

Here is a simplified/example structure:

Table: invites
    id : int (auto-increment index)
    name : varchar
    message : varchar

Table: donotinvite
    name : varchar (index)

Is it possible to do a conditional insert of a 'name' and 'message' pair into the 'invites' table assuming the 'name' does not match any 'name' from the 'donotinvite' table with a single statement?

Something like this, perhaps?

INSERT INTO invites
    SET name = 'joe', message = 'This is an invite'
WHERE NOT EXISTS 
    (SELECT name 
    FROM donotinvite
    WHERE name = 'joe')
+3  A: 

(I'm an MSSQL person, so not sure if all appropriate for MySQL)

INSERT INTO invites
(
    name, message
)
SELECT name = 'joe', message = 'This is an invite'
WHERE NOT EXISTS 
    (SELECT *
    FROM donotinvite
    WHERE name = 'joe')

In practice you might put all the Name / Message in a temporary table and then do:

INSERT INTO invites
(
    name, message
)
SELECT T.name, T.message
FROM MyTempTable AS T
WHERE NOT EXISTS 
(
    SELECT *
    FROM donotinvite AS DNI
    WHERE DNI.name = T.name
)
Kristen
+1  A: 

This would do the job, but I'm not sure it would peform that well. It might work for your application:

INSERT INTO invites(name, message) 
SELECT p.name, "This is an invite" 
FROM people AS p  
WHERE p.name NOT IN (SELECT name FROM donotinvite);

Do you have a table like people, a catalog of all the people you can send invites to?

Jeremy DeGroot
Hopefully MySQL would be smart enough to boil this down to a quick hash/index check. Or, it could be slow. +1 regardless
postfuturist
Yes, ideally all tables involved would be well-indexed on name. Or better yet, your production app might use numeric IDs and foreign keys, which would lead to shorter keys and better performance.
Jeremy DeGroot
Actually, the table as described is indexed on the 'name' field, so it is up to MySQL to properly optimize the query.
postfuturist
Or just create the SQL with text strings in situ - i.e. change "FROM (SELECT @name AS name, @message AS message) a" to "FROM (SELECT 'Joe' AS name, 'This is an invite' AS message) a" - although I seem to remember reading that nested Sub-SELECTs like this are not permitted in MySQL??
Kristen
+4  A: 
INSERT
INTO invites (name, message)
SELECT a.name, a.message
FROM (SELECT @name AS name, @message AS message) a
LEFT JOIN donotinvite d
ON a.name = d.name
WHERE d.name IS NULL
Quassnoi
+1  A: 

Here is a re-posting of jonstjohn's strangely deleted answer, slightly modified by me:

INSERT INTO invites (name, message) 
    SELECT 'joe','This is an invite' 
    FROM donotinvite 
    WHERE name <> 'joe'

EDIT: this doesn't do what I want :) .

postfuturist
I prefer Quassnoi's answer, which is properly parametrised (unlike mine :( ) and thus "joe" isn't duplicated in a way that might cause human error
Kristen
This will invite Joe as many times, as many non-Joes you don't want to invite. If you have 20 people in your blacklist and none of them is Joe, Joe will be invited 20 times. If Joe is in the blacklist, he will be invited only 19 times. Is that what you want?
Quassnoi
This also means that if the blacklist is empty, you won't be able to invite ANYONE.
Quassnoi
Hmm, Quassnoi's answer looks like SQL Server style parameters. This is a question for a MySQL database, and my example merely has inline data to simplify the problem. Parameterization can be assumed in practive. It is an orthogonal issue.
postfuturist
Ah, I see the problem. Thanks. I wish his original answer had been left with a comment explaining the problem instead of just deleted.
postfuturist
These are session variables, actually. You may easily assign them in MySQL client and check if the query works, that's why I prefer to post them this way.
Quassnoi