How to prevent race condition with INSERT? - mysql

How would i go about preventing race conditions when INSERTing a row into a table that contains no unique index. For example say my table is....
key | slot | label
------------------
1 | 1 | some
1 | 2 | some
2 | 1 | some
2 | 2 | some
... is the only way to prevent such race conditions to create a composite unique field such as "key:slot" e.g.
id | key | slot | label
------------------------
1:1 | 1 | 1 | some
1:2 | 1 | 2 | some
2:1 | 2 | 1 | some
2:2 | 2 | 2 | some
...or is there a more efficient way that has escaped me? What about if i was to check for duplicate rows after the insert has been performed and roll the transaction back if there are any found?

actually you can do it without the key:slot column. You can define a unique compound key on the table. eg,
ALTER TABLE tableName ADD CONTRAINT tb_uq UNIQUE (`key`, slot)

How about using LOCK TABLES syntax to prevent race conditions when inserting?

Related

Is it possible to delete a single row using JPA repository where the rows are not unique?

This is a bad database design.
The table is as follows where both the columns are foreign keys. The design was created by someone else.
I know this is a violation and should not be done. I will be changing the entities.
+---------+---------------+
| cart_id | item_id |
+---------+---------------+
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 3 | 3 |
+---------+---------------+
Before changing, I just want to know whether it is possible to delete a single row in this case where the matching results are many.
#Query(value = "delete FROM cart_items where cart_id =:cartId AND item_id =:itemId", nativeQuery = true)
#Transactional
int deleteCartItem(long cartId, long itemId);
For the above query, it will delete multiple records, I just want to delete single or none.
You can try using the LIMIT clause of SQL. For your case you can use LIMIT 1 at the end of your query. It's going to delete the first row of your resultset.
Hope this helps!

MySQL: delete duplicate rows, keep none

newbie here, for this table I would like to remove all ID's (rows) that don't have a unique number in Event. So far I found only solutions that will keep one ID, but remove the duplicates.
+-----------+--------------+----------+--------+
| ID | Costs | Date | Event |
+-----------+--------------+----------+--------+
| 1 | 100 |2012/09/10| 5 |
+-----------+--------------+----------+--------+
| 2 | 300 |2012/09/20| 5 |
+-----------+--------------+----------+--------+
| 3 | 400 |2012/10/01| 4 |
+-----------+--------------+----------+--------+
I have tried the ALTER IGNORE TABLE ADD UNIQUE INDEX function, but i don't want to keep one ID. For example, in this table I would like to remove the rows from ID 1 and 2, but keep ID 3.
Note: all ID's are unique.
Thank you.
you can use HAVING to get Event that has duplicate value, then use it in DELETE query instead of using the ID in WHERE criteria, isn't it?

SQL ON DUPLICATE KEY with 2 unique keys?

I have a MySQL table that goes like so:
+----+--------+-------+-------------+
| id | userID | month | lastUpdated |
+----+--------+-------+-------------+
| 1 | 5 | 1 | 2017-03-27 |
| 2 | 5 | 2 | 2017-03-22 |
| 3 | 5 | 3 | 2017-03-21 |
| 4 | 9 | 1 | 2017-03-27 |
| 5 | 9 | 2 | 2017-03-22 |
| 6 | 9 | 3 | 2017-03-21 |
+----+--------+-------+-------------+
I want to make an INSERT statement to this table but use ON DUPLICATE KEY UPDATE like this:
INSERT INTO users_last_updated
(userID, month, lastUpdated)
VALUES
(:userID, :month, :lastUpdated)
ON DUPLICATE KEY UPDATE lastUpdated = :lastUpdated
The thing is, a userID can show up multiple times and a month value can show up multiple times BUT, the uniqueness of each row is a combination of userID & month (e.g: userID = 1 & month = 3 can only appear once).
Is there a way to make a combination of 2 columns to be unique?
Thanks :)
If the unique key is userid/month, then use both of those for a unique index or constraint:
create index unq_users_last_updated_2 on users_last_updated(userId, month);
I would add that it seems strange to have month without a year.
The on duplicate key uses any and all available unique indexes, including primary keys (but not limited only to primary keys).

How to select multiple entries with the same value in one column in T-SQL

So, I am working in Visual Studio 2013. And I have a table like this:
id | fk | data
----------------------
1 | 1 | something1
2 | 1 | something2
3 | 1 | something3
. | . | ...
. | . | ...
6 | 2 | ...
The fk is a foreign key to another table. I want to select all the rows which have the same fk. There is an undefined number of the same fk entries (there could be 5 rows with value 1 and 3 rows with value 2, etc.) But, I want to be able to switch said fk in my program so that when i put the DB in a Form in Visual Studio, clicking a button next would get me the next value of the fk. For example, I would like the first result to come out like this:
id | fk | data
----------------------
1 | 1 | something1
2 | 1 | something2
3 | 1 | something3
And when I click next to get me to the next entry, the result would be:
id | fk | data
----------------------
6 | 2 | ....
7 | 2 | ....
Is there a way in SQL to combine just the results with the same fk value? All of the solutions I have found so far gave me all of the fk values (all entries). I haven't found a way to get just all the entries with a single, unique value in the fk column.
You're looking for a basic SELECT statement with a WHERE clause:
SELECT
id, fk, data
FROM
your_table_name
WHERE
fk = 1
I can't help you with the VisualStudio stuff though, but you'll just have to repeat the same query incrementing the fk value in the WHERE clause

Sort table records in special order

I have table:
+----+--------+----------+
| id | doc_id | next_req |
+----+--------+----------+
| 1 | 1 | 4 |
| 2 | 1 | 3 |
| 3 | 1 | 0 |
| 4 | 1 | 2 |
+----+--------+----------+
id - auto incerement primary key.
nex_req - represent an order of records. (next_req = id of record)
How can I build a SQL query get records in this order:
+----+--------+----------+
| id | doc_id | next_req |
+----+--------+----------+
| 1 | 1 | 4 |
| 4 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 1 | 0 |
+----+--------+----------+
Explains:
record1 with id=1 and next_req=4 means: next must be record4 with id=4 and next_req=2
record4 with id=5 and next_req=2 means: next must be record2 with id=2 and next_req=3
record2 with id=2 and next_req=3 means: next must be record3 with id=1 and next_req=0
record3 with id=3 and next_req=0: means that this is a last record
I need to store an order of records in table. It's important fo me.
If you can, change your table format. Rather than naming the next record, mark the records in order so you can use a natural SQL sort:
+----+--------+------+
| id | doc_id | sort |
+----+--------+------+
| 1 | 1 | 1 |
| 4 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 1 | 4 |
+----+--------+------+
Then you can even cluster-index on doc_id,sort for if you need to for performance issues. And honestly, if you need to re-order rows, it is not any more work than a linked-list like you were working with.
Am able to give you a solution in Oracle,
select id,doc_id,next_req from table2
start with id =
(select id from table2 where rowid=(select min(rowid) from table2))
connect by prior next_req=id
fiddle_demo
I'd suggest to modify your table and add another column OrderNumber, so eventually it would be easy to order by this column.
Though there may be problems with this approach:
1) You have existing table and need to set OrderNumber column values. I guess this part is easy. You can simply set initial zero values and add a CURSOR for example moving through your records and incrementing your order number value.
2) When new row appears in your table, you have to modify your OrderNumber, but here it depends on your particular situation. If you only need to add items to the end of the list then you can set your new value as MAX + 1. In another situation you may try writing TRIGGER on inserting new items and calling similar steps to point 1). This may cause very bad hit on performance, so you have to carefully investigate your architecture and maybe modify this unusual construction.