Reputation: 6758
My SQL table has the following DDL
CREATE TABLE `new_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`family_id` int(11) NOT NULL,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
)
I want to hold the family names in this simple table. In order to do this I have a microservice where the caller sends via JSON the family details:
{
"family_id" : 1,
"names": ["name1", "name2"]
}
The id is generated via auto increment from MySQL.
So the above JSON will finally trigger two insert statements:
The problem arises when a new request comes with a family_id that exists in the table. This should not be allowed, and I am doing a query in order to search if the family_id exists or not. If it exists an exception is raised. How can I avoid this query? The table schema can be altered if needed. Would it be OK if a could add something like a "request id", or a guid to establish uniqueness per request?
All data should be on the same table.
Below an example of the table with some data
(from Comment) I cannot create a second table. Eveything should be kept in one table.
Upvotes: 0
Views: 241
Reputation: 142208
You need two tables.
CREATE TABLE Families (
family_id MEDIUMINT UNSIGNED AUTO_INCREMENT,
...
PRIMARY KEY(family_id)
);
CREATE TABLE FamilyNames (
family_id MEDIUMINT UNSIGNED, -- not auto-inc here
name VARCHAR(66) NOT NULL,
...
PRIMARY KEY(family_id, name) -- note "composite"
);
A PRIMARY KEY
is a UNIQUE KEY
is a KEY
.
You say you cannot add a second table. But why? You mention needing to generate a particular JSON? Can't that simply be done via a JOIN
of the two tables if necessary?
Upvotes: 3
Reputation: 10066
This is a workaround for a design problem, but I figured I might as well post it. You can generate a query such as the following:
INSERT INTO `new_table` (`family_id`, `name`)
SELECT * FROM (
SELECT 1, 'name1'
UNION ALL
SELECT 1, 'name2'
) x
LEFT JOIN `new_table` n ON n.family_id = 1
WHERE n.family_id IS NULL
Then check the number of rows affected to determine if it was successful or not.
Upvotes: 0
Reputation: 562240
If you can't create a second table to model the constraint properly, then you will have to resort to serializing inserts:
LOCK TABLES new_table WRITE;
SELECT
to check if the family id exists in the table.INSERT
your new data.UNLOCK TABLES;
It's necessary to lock the table because otherwise you will have a race condition. Two sessions could check if the family id exists, both find that it does not exist, and then both proceed with their INSERT
. If you lock the table, then one session will acquire the lock and do its work, while the other session must wait for the lock, and by the time it acquires the lock, its check will find that the family id has been inserted by the first session.
This method is usually considered bad for concurrency, which can limit your throughput if you have many requests. But if you have infrequent requests, the impact to throughput will be minimal.
Upvotes: 2
Reputation: 501
You should normalize your schema and use two tables.
Family and (I assume) Person. Then you can use a UNIQUE
constraint for the family_id
and add the family_id as foreign key into the Person table.
Upvotes: 6