MySql - apply same unique constraint to two different combinations of fields - mysql

How do I specify unique constraint on different combinations of fields? E.g.
id | Fld1 | Fld2 | Fld3
-------------------------
1 | A | B | C
-------------------------
2 | A | C | D
I'd like to make the example above illegal because combination (Fld1, Fld3) in row 1 has same values as combination (Fld1, Fld2) in row 2.
Is there any way to do this?

There is no way possible for this except a trigger but performance will be a constraint. You can only have combine unique key but this case will not fullfil.

Related

How to increment a field in MySql using “ON DUPLICATE KEY UPDATE” when each row increment each value?

this question like increment a field with same value
but I want to achieve each row increment each value
for example:
a is a primary key
Original data
a | share_count | read_count |
1 | 2 | 3 |
through
INSERT INTO table (a, share_count,read_count)
VALUES(1,share_count+1,read_count+2),(2,share_count+2,read_count+3)
ON DUPLICATE KEY UPDATE
a=VALUES(a),share_count=VALUES(share_count),read_count=VALUES(read_count)
Goal result
a | share_count | read_count |
1 | 3 | 5 |
2 | 2 | 3 |
I tried,but fail.Thanks for answering
Usually if you try to INSERT you insert count=1 but not share_count+2 or read_count+3.
If I guess your goal correctly you need something like:
http://sqlfiddle.com/#!9/9d4c6/1
INSERT INTO t1 (a, share_count,read_count)
VALUES
(1,1,1),
(2,1,1)
ON DUPLICATE KEY UPDATE
share_count=share_count+1,read_count=read_count+1

ON Duplicate Key for exact combination of multiple values

Let's assume we have this table:
--------------------------
| x | y | z | data |
---------------------------
| 3 | 53 | 24 | hello |
---------------------------
-
Now I only want to update "data" in case there is the exact combination of X, Y, Z.
INSERT INTO TABLE SET x=?,y=?,z=?,data=? ON DUPLICATE KEY UPDATE data=?
This obviously doesn't work. How would I do this?
You only add a composite unique key over the three fields x,y,z. the it works.
You can also use this syntax:
INSERT INTO TABLE (x,y,z,data) values (?,?,?,?) ON DUPLICATE KEY UPDATE data=?;

How to prevent race condition with INSERT?

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?

MySQL: UPDATE ... ON DUPLICATE KEY "ANOTHER UPDATE"?

I've stumbled on a problem which is supposedly should have a valid solution in a single MySQL query, yet I can't figure it out (I'm far from an expert in MySQL, alas).
The table has the following columns: A, B, C. (A, B) is a primary key (INTs). C - is a string. The table is populated with records.
Under some conditions I need to update a value x in column A to new value y. If some records do already have y in A (can be many at once, for records with different values in B), "duplicate key(s)" condition occurs. In such case, I need to concatenate values in C from old records and corresponding pending updates, for every specific b.
Example:
| A | B | C
| 1 | 2 | ABC
| 1 | 4 | DEF
| 2 | 2 | GHI
| 2 | 4 | JKL
| 2 | 5 | MNO
After update in A as 2 -> 1, I need to get:
| A | B | C
| 1 | 2 | ABCGHI
| 1 | 4 | DEFJKL
| 1 | 5 | MNO
There is a well-known INSERT ... ON DUPLICATE KEY UPDATE statement. But how to handle gracefully the same problem on updates? I'm not sure if and how REPLACE statement or REPLACE function can be used for the task.
Thanks in advance.
I think, whatever happens, you will need two statements:
ALTER TABLE myTable ADD UNIQUE INDEX (A, B);
INSERT INTO myTable (A, B, C)
SELECT 1, B, C
FROM myTable t
WHERE A = 2
ON DUPLICATE KEY UPDATE
C = CONCAT(myTable.C, VALUES(C))
;
DELETE FROM myTable WHERE A = 2;
See it on sqlfiddle.
If there is a risk of concurrency issues, you will obviously need to perform these within a transaction to preserve atomicity.

MySQL: How to fetch data with left-join if column contains multiple ids?

Assuming the following:
Table "info":
id | target_ids
----|------------
1 | 2
2 |
3 | 4,1
4 | 2,3,1
Table "targets":
id | value
----|------------
1 | dog
2 | cat
3 | tiger
4 | lion
Using left join, I'm expecting something like this:
id | target_ids | value
----|---------------------
1 | 2 | cat
2 | |
3 | 4,1 | lion,dog
4 | 2,3,1 | cat,tiger,dog
I've tried this:
select info.*, targets.value from info left join targets on info.target_ids = targets.id
The results I got is single values in "value" column
id | target_ids | value
----|---------------------
1 | 2 | cat
2 | |
3 | 4,1 | lion
4 | 2,3,1 | cat
How can I get results as it's showing in the 3rd table? Thanks
You need to use MySQL's FIND_IN_SET() function as the join criterion:
SELECT info.*, GROUP_CONCAT(targets.value) AS value
FROM info LEFT JOIN targets ON FIND_IN_SET(targets.id, info.target_ids)
GROUP BY info.id
See it on sqlfiddle.
However, you would probably be best to normalise your data structure and store your info-target relations in a separate table:
CREATE TABLE InfoTargets (
InfoID INT NOT NULL,
TargetID INT NOT NULL,
PRIMARY KEY (InfoID, TargetID),
FOREIGN KEY (InfoID) REFERENCES info (id),
FOREIGN KEY (TargetID) REFERENCES targets (id)
);
INSERT INTO InfoTargets VALUES
(1,2),
(3,4), (3,1),
(4,2), (4,3), (4,1);
ALTER TABLE Info DROP COLUMN target_ids;
Then you would do:
SELECT info.id,
GROUP_CONCAT(targets.id) AS target_ids,
GROUP_CONCAT(targets.value) AS value
FROM InfoTargets
LEFT JOIN info ON InfoID = InfoTargets.InfoID
LEFT JOIN targets ON TargetID = InfoTargets.TargetID
GROUP BY info.id
If the order of targets is important (and might differ between each info item), you would need to create an additional rank column in InfoTargets.