"on duplicate key update" with multi-field key - mysql

According to the docs:
If [columns a and b are] unique, the INSERT is equivalent to this UPDATE statement instead:
UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;
If a=1 OR b=2 matches several rows, only one row is updated. In general, you should try to avoid using an ON DUPLICATE KEY UPDATE clause on tables with multiple unique indexes.
This is fair enough, but what if I have this as the only key:
PRIMARY KEY (`a`,`b`)
Since the duplicate key is dependant on both fields simultaneously, would the update reliably affect the specific row where the duplicate occurs, or does it do the same as if the fields were individually unique?

Assuming you're using the same query as in your example, it wouldn't reliably update the row with the duplicate key. It would still find the first row in data order that has either of the matching values. Consider the example below.
a | b
1. 1 | 1
2. 1 | 2
3. 1 | 3
4. 1 | 4
5. 2 | 1
6. 2 | 2
the query UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1; would update the first row, not the desired second row. So in a few words, it's the same as if the columns were individually unique.

If the on duplicate concerns a column witch is define as unique or primary, or the SAME set of columns defined in a unique or primary key, an insert ... on duplicate update ... statement will update the row where ALL the columns in this PK or unique key have the same values.
To answer your comment on G-Nugget answer, only the row 2 will be updated.
Hope that helps ;-)

Related

MySQL Integer Column with Unique values in it, however default value is 2( not NULL) ? Is it Possible?

I want a table with an integer column, that must be filled with a default value 1111 when no input is received. But if we receive input it should be filled and I want it to be UNIQUE : there cannot be two entries of the same number(except default value 111). Ex :-
I know we can achieve the objective if our default value is NULL but here in my case I need to have a integer default value and unique check in all other integer added.
Please guide me if this can be achieved or not ?
A UNIQUE KEY can't hold the value 1111 multiple times.
So use NULL and replace it in the queries
CREATE TABLE tab1(col1 int,col2 int UNIQUe )
INSERT INTO tab1 VALUES (1,NULL),(2,1)
INSERT INTO tab1 VALUES (2,1)
Duplicate entry '1' for key 'tab1.col2'
SELECT col1,IFNULL(col2,1111) FROm tab1
col1 | IFNULL(col2,1111)
---: | ----------------:
1 | 1111
2 | 1
db<>fiddle here
Actually you could not use unique with default value. because the point of unique in MySql is preventing duplicates in column. Which making conflicts in that logic.
You must handle the duplication before sending the insert query to DB (in Backend) or you may use techniques other than unique like:
INSERT IGNORE: will insert rows in the same way as INSERT, but with the exception that it will ignore rows with duplicate values and continue execution without creating an error. Any row that contains a duplicate value will not be inserted.
INSERT ... ON DUPLICATE KEY UPDATE: will insert any non-duplicate rows as normal. However, when it encounters a duplicate row, it will perform an UPDATE on the original row.
REPLACE: works the same as INSERT, except that when it encounters a duplicate row, it deletes the original row and then continues with the insert. Any row with a duplicate unique index value will replace the row that originally contained the value.

Insert into mysql 2 records with the second record referencing the newly created id from record 1?

I need to insert data into a mysql table in one query. The query inserts more than 1 record, and the 2nd record needs to get the id of the first one and populate it in a parentid column. I'm new at scripting queries, and I have no idea how to accomplish this.
example:
| id | parentid |
| 1 | null |
| 2 | 1 |
You could use LAST_INSERT_ID, but I don't think this would be considered "one query":
START TRANSACTION;
BEGIN;
INSERT INTO tablename (parent_id) VALUES
(NULL);
INSERT INTO tablename (parent_id) VALUES
(LAST_INSERT_ID());
COMMIT;
No, it cannot be done in a single query.
MySQL does not implement the standard SQL feature of "deferrable constraints" that would be necessary for this query (INSERT) to succeed. A solution is possible in PostgreSQL or Oracle, however.
This is not possible to achieve in MySQL since during the insertion of the second row, its foreign key constraint will fail because the first row does not yet "officially" exist -- though was inserted. However, if the FK constraint check is deferred until the end on the SQL statement (or until the end of the transaction), the query would complete successfully... but that's not implemented in MySQL.

Mysql, insert if all columns don't exist

I have a table with 3 columns. None of the columns are unique key.
I want to run an insert only if a row doesn't exists already with the exact same values in each column.
given the following table:
a b c
----------
1 3 5
7 1 3
9 49 4
a=3 b=4 c=3 should insert
a=7 b=1 c=3 should not insert (a row with these exact values exists)
The solutions I have found so far need a unique primary key.
The most efficient way is adding a UNIQUE KEY to your table. You can also make an algorithm for comparing the values but you do not want to do that if you have many columns in your table.
I'm not sure, I get your point correctly. But hope this help.
First of all you have to SELECT the row with WHERE clause
SELECT * FROM table WHERE a=$a && b=$b && c=$c
After that you fetch_array or fetch_row if the array or row exist, that means 'not insert'.

Pitfall to avoid by not doing duplicate key update on tables with multiple unique indexes

From insert-on-duplicate:
If a=1 OR b=2 matches several rows, only one row is updated. In
general, you should try to avoid using an ON DUPLICATE KEY UPDATE
clause on tables with multiple unique indexes.
I am confused on the bold part (my emphasis).
First of all a unique index can be composite, right? So the recommendation includes these as well?
What would be a practical example of what pitfall we avoid following the recommendation?
Is a composite primary key related in any way with this recommendation?
I think the comment refers to different unique indexes rather than composites: e.g. if you have a table with two unique indexes:
unique index on column A with values:
1
2
3
and a second unique index on column B with values:
a
b
c
and you insert a row with colA = 1 and colB = b, which existing row will be updated?

UNIQUE Constraint, only when a field contains a specific value

I'm trying to create a UNIQUE INDEX constraint for two columns, but only when another column contains the value 1. For example, column_1 and column_2 should be UNIQUE only when active = 1. Any rows that contain active = 0 can share values for column_1 and column_2 with another row, regardless of what the other row's value for active is. But rows where active = 1 cannot share values of column_1 or column_2 with another row that has active = 1.
What I mean by "share" is two rows having the same value(s) in the same column(s). Example: row1.a = row2.a AND row1.b = row2.b. Values would be shared only if both columns in row1 matched the other two columns in row2.
I hope I made myself clear. :\
You can try to make multi-column UNIQUE index with column_1, column_2 and active, and then set active=NULL for the rows where uniqueness not required. Alternatively, you can use triggers (see MySQL trigger syntax)
and check for each inserted/updated row if such values are already in the table - but I think it would be rather slow.
I'm trying to create a UNIQUE INDEX constraint for two columns, but only when another column contains the value 1
You can set the value of "another column" to a unique value that does not equal to 1. for example the id of a record.
Then the unique index constraint could be applied to all three columns including the "another column". Let's call the "another column" columnX.
Set the value of columnX to 1 if you want to apply the unique constraint to a record. Set the value of columnX to a unique value if you don't want to apply the unique constraint.
Then no extra work/triggers needed. The unique index to all three columns could solve your problem.
I am not sure about MySQL syntax, but it should have pretty much the same thing that SQL Server has:
CREATE UNIQUE INDEX [UNQ_Column1Column2OnActive_MyTable]
ON dbo.[MyTable]([column1,column2)
WHERE ([active] = 1);
This index will make sure if active=1 then column1 and column2 combination is unique across the table.
In SQL Server this could be accomplished with check constraints, however I do not know if MySQL supports anything similar.
What will work on any database, is that you can split the table in two. If the records where active =0 are just history records, and will never become active again, you could just move them to another table, and set a simple unique constraint on the original table.
I am not sure I understand you 100% but lets say you have a table that has a status column and you want to make sure there is only one raw with a status of 'A' (Active). You are OK with many rows with statuses of 'I' or 'Z' or anything else. Only one row is allowed with status of 'A'.
This will do the trick.
CREATE UNIQUE INDEX [Idx_EvalHeaderOnlyOneActive]
ON [dbo].[EvalHeader]([Hdr Status])
WHERE [Hdr Status] = 'A';
indexes are agnostic of external influences. This kind of constraint would have to be implemented outside your database.