on duplicate key with a where condition - mysql

I am trying to use a WHERE condition on an INSERT INTO statement that contains ON DUPLICATE KEY. An example of what I'm trying to achieve is below.
This SQL statement is being called by third-party software and we want to exclude some exports based on numerical values, in this case 2. So, when X != Y perform INSERT, if X == Y, don't.
INSERT INTO satellites (name, intname) VALUES ('%SATELLITE.NAME%','%SATELLITE.INTNAME%') ON DUPLICATE KEY UPDATE name='%SATELLITE.NAME%',intname='%SATELLITE.INTNAME%' WHERE '%SATELLITE.NAME%' != 2;

Use a SELECT query rather than VALUES. Then you can add a condition to ignore the name
INSERT INTO satellites (name, intname)
SELECT '%SATELLITE.NAME%' AS name, '%SATELLITE.INTNAME%'
FROM DUAL
HAVING name != 2
ON DUPLICATE KEY UPDATE name = VALUES(name), intname = VALUES(intname)
Note that in the ON DUPLICATE KEY UPDATE clause you don't need to specify the assignment to the unique key column, since it's not going to change (since that's what is duplicate). But I didn't know which one is the unique key, so I didn't remove it.
DUAL is a placeholder for a table name when you're just selecting literal values.

I am guessing you want the internal name from the satelites and search for it in your table
INSERT INTO satellites (name, intname) VALUES ('%SATELLITE.NAME%','%SATELLITE.INTNAME%')
ON DUPLICATE KEY UPDATE name='%SATELLITE.NAME%',intname=(SELECT intname FROM satellites WHERE name != 2 ORDER BY intname LIMIT 1);

Related

mysql - INSERT... ON DUPLICATE KEY UPDATE, but not really...?

Hi I've been trying to get this to work, I thought I had it with mysql - INSERT... ON DUPLICATE KEY UPDATE, but no luck.
I have a table as such:
sessionID is unique,
productID references another table and is not unique, but not common, should be a max of 3 rows containing the same value,
sessionType is either 1, 2 or 3, and would link with productID,
I need to check if the table has a row where there is a matching pair of productID and sessionType, if there is then sessionDate & sessionCapacity in that row should be UPDATED, if there isn't then a new row inserted.
$vals = array($pID,$data['pSessionDate'],'1',$data['pQty'],$pID,$data['pSessionDate'],'1',$data['pQty']);
$db->Execute("INSERT INTO VividStoreSessions (pID,sDate,sType,sCapacity) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE pID=?,sDate=?,sType=?,sCapacity=?",$vals);
Hope that makes sense to someone and thanks in advance for any help!
Your insert looks valid. But, first you need a unique index/constraint:
create unique index unq_VividStoreSessions_productId_sessionType
on VividStoreSessions, productId, sessionType)
Then you can write the code to only use four parameters:
INSERT INTO VividStoreSessions (pID, sDate, sType, sCapacity)
VALUES (? ,?, ?, ?)
ON DUPLICATE KEY UPDATE sDate = VALUES(sDate), Capacity = VALUES(Capacity);
Finally, you need to ensure that sType only takes on the values of 1, 2, or 3. Perhaps you want to enforce this at the application layer. Otherwise, you need a trigger or foreign key constraint to ensure that there are only three rows.

MySQL on duplicate key... get existing ID?

I'm using ON DUPLICATE KEY UPDATE to handle duplicate inserts on a table, in order that they are discarded.
In my case it's a simple table storing tags:
id (int, PK, AI, unsigned, not null)
tag (varchar 25, not null, unique)
This is working fine, but I need to retrieve the ID - either the insert ID, on successful insert, or the existing ID, if it's a duplicate.
I'm getting insert ID = 0 where ON DUPLICATE KEY UPDATE fires, which I guess is expected behaviour since no insert took place.
Is there anyway I can get the existing ID, or am I headed to a separate read query?
You could add a third column ModifiedDate and use that:
insert into t(id, tag)
select id, tag
on duplicate key update ModifiedDate = now();
This will ensure that an update really occurs, and in turn, that LAST_INSERT_ID() returns a value.

MySQL update if exists

I have been trying to do insert / update records in a mysql table. Cannot use ON DUPLICATE KEY because i have nothing to do with the primary key.
Basically i have to update a record in the database
INSERT INTO table (city, state, gender, value) VALUES ("delhi","delhi","M",22)
If a record of that city, state, gender exists, then simply overwrite the value.
Can i achieve this without sending two queries from the programming language
actually you can still use ON DUPLICATE KEY, just add a unique index on the following columns, eg
ALTER TABLE tbl_name ADD UNIQUE index_name (city, state, gender)
your query now will be,
INSERT INTO table (city, state, gender, value)
VALUES ('delhi','delhi','M', 22)
ON DUPLICATE KEY UPDATE value = 22
Keep in mind that constructs such as ON DUPLICATE KEY and REPLACE INTO were specifically designed to prevent exactly that. The only other way to prevent two queries from your application layer is by declaring a database function that does the same things.
Therefore, add either a UNIQUE(city, state, gender) key or a primary key that spans the same columns. The difference between the two lies in the value range of each column; primary keys force NOT NULL whereas UNIQUE allows for columns to be NULL.
The difference is subtle but can sometimes lead to unexpected results, because NULL values are considered to be unique. For example, let's say you have this data in your database:
nr | name
123 | NULL
If you try to insert another (123, NULL) it will not complain when you use UNIQUE(nr,name); this may seem like a bug, but it's not.

MySQL: Advanced insert if not exists

I have a table with with essentially three columns: user_id, setting, and value. I'm trying to use the following code:
INSERT INTO 'user_settings'(user_id, setting, value)
VALUES (1234, setting_1, 500)
ON DUPLICATE KEY UPDATE user_id = 1234, setting = setting_1'
This works great when creating a new setting, and it doen't generate duplicate records. The problem comes when I want to change the value- this won't work after the previous query has run:
INSERT INTO 'user_settings'(user_id, setting, value)
VALUES (1234, setting_1, 999)
ON DUPLICATE KEY UPDATE user_id = 1234, setting = setting_1'
No rows are affected. Clearly I'm missing something...
IMPORTANT: I am not able to alter the database (new primary keys or something).
UPDATE: It seems my understanding of ON DUPLICATE KEY is wrong. But the question remains- what is the most efficient way way to accomplish this?
Answered in a comment below: "If the Primary (or Unique) key is (user_id, setting), then use: ... ON DUPLICATE KEY UPDATE value=999".
Assuming you actually have a unique key on user_id, you are getting "no rows affected" because you aren't changing anything in the second query. I think what you want to do is update the value field as well:
INSERT INTO 'user_settings'(user_id, setting, value)
VALUES (1234, setting_1, 999)
ON DUPLICATE KEY UPDATE setting = setting_1,value=999
Without value in there, you're just setting the user_id and the setting field to the same values they were before, and MySQL doesn't need to update the record.
If you don't have a unique key on user_id, you'll have to find a different approach, as the ON DUPLICATE KEY UPDATE won't trigger.

MySQL INSERT only if row doesn't exist, otherwise select the duplicate row

I am looking for a statement that will try to insert a row into a table, but return the primary key of the duplicate row if one is encountered. One field in the table is the auto incrementing primary key, the other is unique.
This should, at least in theory, work for you:
First extend your table to have an additional column dummy of type tinyint. Then you can use the following query when inserting/updating:
INSERT INTO yourtable (a, b) VALUES (1, 2) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id), dummy = NOT dummy
(I'm assuming here that the column a has a unique index and a row with a=1 exists.)
You can then get the ID of the new row (in case of an INSERT) or the existing row (in case of an UPDATE) via
SELECT LAST_INSERT_ID()
This should work in DB2, dont know if it will in MySQL or if there is special MySQL syntax for it:
SELECT pk, 'inserted' FROM FINAL TABLE (
INSERT INTO table (Col1)
SELECT Val1
FROM table
WHERE col1 != Val1
FETCH FIRST ROW ONLY
)
UNION
SELECT pk, 'existing'
FROM table
WHERE col1 = val1
The idea here is to select one row from the table when there is not a unique value in there, inserting the new value and returning the generated primary key from the table. This is then combined with the select that returns the corresponding key if the unique values is already in the table. Only one of those statements should return a row, the second column indicating if the primary key is new or exisiting.