You could try and do this with a TRIGGER
.
CREATE TRIGGER check_unique BEFORE UPDATE ON `images`
FOR EACH ROW
SET NEW.isMain = IF(NEW.isMain = 0, 0,
CASE WHEN ( SELECT MAX(isMain) FROM images AS q WHERE q.prod = NEW.prod ) = 1
THEN NULL ELSE NEW.isMain END);
or, faster (especially if indexed)
CREATE TRIGGER check_unique BEFORE UPDATE ON `images`
FOR EACH ROW
SET NEW.isMain = IF(NEW.isMain = 0, 0,
IF (EXISTS ( SELECT * FROM images AS q WHERE q.prod = NEW.prod AND q.isMain = 1), NULL, 1));
This will allow setting isMain to 0 always; if you want to set it to 1, then it will check that there are no other rows for the same product for which isMain is 1.
Example
In the example below, I cannot set isMain = 1
where prod=3
until I set isMain=0
on the other image which had isMain = 1
.
CREATE TABLE images (
image_id integer not null primary key auto_increment,
prod integer not null, isMain integer not null );
INSERT INTO images VALUES (1, 1, 0), (2, 1, 1), (3, 2, 0), (4, 2, 1);
select * from images;
+----------+------+--------+
| image_id | prod | isMain |
+----------+------+--------+
| 1 | 1 | 0 |
| 2 | 1 | 1 |
| 3 | 2 | 0 |
| 4 | 2 | 1 |
+----------+------+--------+
CREATE TRIGGER check_unique BEFORE UPDATE
ON `images` FOR EACH ROW
SET NEW.isMain = IF(NEW.isMain = 0, 0, IF (EXISTS ( SELECT * FROM images AS q WHERE q.prod = NEW.prod AND q.isMain = 1), NULL, 1));
UPDATE images SET isMain = 1 WHERE image_id = 3;
ERROR 1048 (23000): Column 'isMain' cannot be null
UPDATE images SET isMain = 0 WHERE image_id = 4;
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 1
UPDATE images SET isMain = 1 WHERE image_id = 3;
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 1
You could extend this approach so that you can always set to 1 the isMain of any row... but the row that was isMain before for that product gets zeroed.