Oprettet fre. d. 28. januar 2011 kl. 01:04:36

dennism
dennism (5.356 point. Point ude: 0)
www.demaweb.dk

MySQL: UNIQUE KEY

Jeg har følgende tabel:
CREATE TABLE IF NOT EXISTS `articles` (
    `id` int(11) NOT NULL auto_increment,
    `active` tinyint(1) NOT NULL DEFAULT 1,
    `date` DATE NOT NULL,
    PRIMARY KEY  (`id`),
    UNIQUE KEY (`active`,`date`),
);


Ideen med min unique key er, at jeg ikke vil have rækker, der har den samme dato og hvor den er active på samme tid (active=1). Dette fungerer naturligvis fint, men problemet er, at når en række bliver slettet, er jeg ikke interesseret i at fjerne fra tabellen - men bare sætte active=0. Dette betyder så, at hvis jeg forsøger at "slette" en række ved at sætte active=0 på en række, som har samme dato som en anden række der tidligere er blevet "slettet", så kan jeg ikke få lov til at "slette" den.

Er der nogen smart løsning på det?

Skrevet fre. d. 28. januar 2011 kl. 01:47:40| #1

arne_v
arne_v (1.016.169 point)
Jeg tror at du skal droppe UNIQUE INDEX og kigge på TRIGGER i.s.f..

Skrevet fre. d. 28. januar 2011 kl. 02:09:38| #2

dennism
dennism (5.356 point)
www.demaweb.dk
Kan man bruge en TRIGGER til at afvise en INSERT/UPDATE, hvis der i forvejen findes en række med samme date og active=1?

Hvis jeg nemt kan sige hvordan, så må du godt lige fortælle hvordan - har ikke lige umiddelbart kunne finde løsningen vha. Google.

Skrevet fre. d. 28. januar 2011 kl. 02:18:54| #3

arne_v
arne_v (1.016.169 point)
Det burde man kunne.

Jeg kan prøve og se om jeg kan bixe et eksempel.

Skrevet fre. d. 28. januar 2011 kl. 03:14:03| #4

arne_v
arne_v (1.016.169 point)
Eksempel:

mysql> CREATE TABLE fun (
    ->    id INTEGER NOT NULL,
    ->    val INTEGER,
    ->    PRIMARY KEY(id)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql>
mysql> DELIMITER //
mysql>
mysql> CREATE TRIGGER duplcheck
    -> BEFORE INSERT
    -> ON fun
    -> FOR EACH ROW BEGIN
    ->    DECLARE n INT;
    ->    SET n = (SELECT COUNT(*) FROM fun WHERE val = new.val);
    ->    IF(n > 0) THEN
    ->        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Ooops - Houston we have a problem!';
    ->    END IF;
    -> END//
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> DELIMITER ;
mysql>
mysql> INSERT INTO fun VALUES(1, 1);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO fun VALUES(2, 2);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO fun VALUES(3, 2);
ERROR 1644 (45000): Ooops - Houston we have a problem!
mysql>
mysql> DROP TABLE fun;
Query OK, 0 rows affected (0.02 sec)

Skrevet fre. d. 28. januar 2011 kl. 03:14:35| #5

arne_v
arne_v (1.016.169 point)
Jeg mener at SIGNAL kræver version 5.5 og trigger kræver version 5.0!

Skrevet fre. d. 28. januar 2011 kl. 16:07:33| #6

dennism
dennism (5.356 point)
www.demaweb.dk
Mit webhost kører mySQL 5.0, så det er desværre ikke en løsning. Så er der ikke andet for, end at man må kode sig ud af det - og altså selv tjekke for denne precondition inden. Smider du et svar?

Skrevet fre. d. 28. januar 2011 kl. 16:26:51| #7

arne_v
arne_v (1.016.169 point)
MySQL 5.0 har support for triggers.

Så den grundliggende logik kan bruges i 5.0.

SIGNAL findes ikke i 5.0, så du skal bruge et workaround for at afbryde operationen.

Der er masser af eksmepler omkring dette på nettet.

Skrevet fre. d. 28. januar 2011 kl. 16:31:05| #8


Skrevet fre. d. 28. januar 2011 kl. 16:35:57| #9

dennism
dennism (5.356 point)
www.demaweb.dk
Jeg sidder og søger, man kan ikke rigtigt finde noget - du må meget gerne smide et link, hvis du ved hvad jeg skal bruge.

Skrevet fre. d. 28. januar 2011 kl. 16:49:52| #10


Skrevet fre. d. 28. januar 2011 kl. 17:15:29| #11

dennism
dennism (5.356 point)
www.demaweb.dk
Jeg har nu forsøgt mig med følgende:


CREATE TABLE fun (
    id INTEGER NOT NULL auto_increment,
    val INTEGER,
    PRIMARY KEY(id)
);

DELIMITER DROP TRIGGER IF EXISTS duplcheck CREATE TRIGGER duplcheck BEFORE INSERT ON fun FOR EACH ROW BEGIN DECLARE n INT; SET n = (SELECT COUNT(*) FROM fun WHERE val = new.val); IF(n > 0) THEN SET NEW='Error'; END IF; END;

INSERT INTO `fun` ( `val`) VALUES ('1')


Jeg kan dog blive ved med at tilføje rækker med val=1. Det var måske det forkerte jeg fandt?

Skrevet fre. d. 28. januar 2011 kl. 17:16:54| #12

dennism
dennism (5.356 point)
www.demaweb.dk
Læsbar udgave:


CREATE TABLE fun (
    id INTEGER NOT NULL auto_increment,
    val INTEGER,
    PRIMARY KEY(id)
);

DELIMITER DROP TRIGGER IF EXISTS duplcheck
CREATE TRIGGER duplcheck
    BEFORE INSERT ON fun
    FOR EACH ROW BEGIN
        DECLARE n INT;
        SET n = (SELECT COUNT(*) FROM fun WHERE val = new.val);
        IF(n > 0) THEN
            SET NEW='Error';
        END IF;
    END;

INSERT INTO `fun` ( `val`) VALUES ('1');

Skrevet fre. d. 28. januar 2011 kl. 21:49:08| #13

arne_v
arne_v (1.016.169 point)
SET NEW='Error';

giver vel ingen fejl.

Det skal være noget som giver en fejl.

Skrevet fre. d. 28. januar 2011 kl. 22:05:57| #14

dennism
dennism (5.356 point)
www.demaweb.dk
Hvad er det så du specifikt foreslår?

Skrevet lør. d. 29. januar 2011 kl. 00:19:53| #15

arne_v
arne_v (1.016.169 point)
Normalt er det ikke et problem at lave noget som giver fejl.

Første ide:

mysql> CREATE TABLE fun (
    ->    id INTEGER NOT NULL,
    ->    val INTEGER,
    ->    PRIMARY KEY(id)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql> DELIMITER //
mysql>
mysql> CREATE TRIGGER duplcheck
    -> BEFORE INSERT
    -> ON fun
    -> FOR EACH ROW BEGIN
    ->    DECLARE n INT;
    ->    SET n = (SELECT COUNT(*) FROM fun WHERE val = new.val);
    ->    IF(n > 0) THEN
    ->        INSERT INTO fun VALUES('This is not an integer',NULL);  -- this will cause an error
    ->    END IF;
    -> END//
Query OK, 0 rows affected (0.01 sec)

mysql>
mysql> DELIMITER ;
mysql>
mysql> INSERT INTO fun VALUES(1, 1);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO fun VALUES(2, 2);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO fun VALUES(3, 2);
ERROR 1442 (HY000): Can't update table 'fun' in stored function/trigger because
it is already used by statement which invoked this stored function/trigger.
mysql>
mysql> SELECT * FROM fun;
+----+------+
| id | val  |
+----+------+
|  1 |    1 |
|  2 |    2 |
+----+------+
2 rows in set (0.00 sec)

mysql>
mysql> DROP TABLE fun;
Query OK, 0 rows affected (0.02 sec)

Skrevet lør. d. 29. januar 2011 kl. 10:59:38| #16


Skriv et indlæg




Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] [img]link til billede[/img]
Web- og emailadresser omdannes automatisk til links

Log ind

   

   

Seneste spørgsmål

Kopier alt fra een column til en anden med streng foran

Oprettet den 25. maj 2012 kl. 04.55
dmg giver 30 point for svar | Giv et svar »

Unique varchar

Oprettet den 25. maj 2012 kl. 04.34
dmg giver 30 point for svar | Giv et svar »

hvem kan flytte min webside fra MySQL 3 database til en...

Oprettet den 24. maj 2012 kl. 11.18
runebase giver 30 point for svar | Giv et svar »



   




Tips & Tricks fra PC World

Teaser billede

Læserne: Her er vores værste it-indkøb

Det er ikke al it-udstyr, som er det rene guld. Her er nogle af læsernes skrækhistorier.


Anmeldelser fra PC World

Teaser billede

Test: Mobil med Ferrari-design - og en Trabant-motor

Motorola har begået endnu en smartphone med lækkert design og potentiale til at være blandt de bedste. Men den når ikke i mål. Se her hvorfor.


Seneste blogindlæg

Teaser billede

Tvangslukke spørgsmål: Hvad er den bedste løsning?

Hej Vi har mange åbne spørgsmål på Eksperten. Vi ville gerne tvangslukke dem - så et spørgsmål efter f.eks. 6 måneder lukkes. Men der er et par uklarheder som ville være gode at få lidt input til:...


Nyheder fra PC World

Teaser billede

Sådan siger du farvel til Facebook

Læs her, hvordan du dropper Facebook og i stedet anvender nogle brugervenlige alternativer, så du stadig kan være social på nettet.


Nyheder fra Computerworld

Teaser billede

Galleri: De fedeste håndholdte gennem 40 år

Her har du de mest banebrydende håndholdte computere gennem alle tider.


Kurser
Samarbejdspartnere

Udgiver · © 2012 IDG Danmark A/S · Hørkær 18 · 2730 Herlev · Tlf.: 77 300 300 · Fax: 77 300 301 · Brug af personoplysninger