0

我有一个附加到表的触发器,当某些列组合不唯一时,该触发器应该引发异常。

CREATE TRIGGER uniqueness BEFORE INSERT ON a
  BEGIN
    SELECT RAISE(FAIL, 'Record is not unique !')
    FROM a
    WHERE ((NEW.st <> 1) 
      AND (p = NEW.p)
      AND ((name = NEW.name) OR (safe_name = NEW.safe_name)));
  END;

但它似乎有时会在不必要的时候被触发。

例如,如果 safe_name 是foo5,并且存在具有 safe_name 的现有记录foo-5。但是foo5!=foo-5那么为什么会这样呢?

==================================================== ===========

好的,我发现它为什么会发生。这是您在 PHP 中重现它的方法:

$pdo = new PDO('sqlite::memory:');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);      
$pdo->sqliteCreateCollation('NS', 'strnatcasecmp');      

$pdo->query('CREATE TABLE a(
   id INTEGER PRIMARY KEY AUTOINCREMENT,
   st INTEGER NOT NULL,
   p  INTEGER NOT NULL,
   name TEXT NOT NULL COLLATE NS,
   safe_name NOT NULL COLLATE NS)');

$pdo->query('CREATE TRIGGER uniqueness BEFORE INSERT ON a
  BEGIN
    SELECT RAISE(FAIL, "Record is not unique !")
    FROM a
    WHERE ((NEW.st <> 1) 
      AND (p = NEW.p)
      AND ((name = NEW.name) OR (safe_name = NEW.safe_name)));
  END;');

// success
$pdo->query('INSERT INTO a(st, p, name, safe_name) VALUES(2, 2, "Foo 5", "foo-5")');

// fail :(
$pdo->query('INSERT INTO a(st, p, name, safe_name) VALUES(2, 2, "foo  5", "foo5")');

显然,当整理事物处于活动状态时,Foo 5名称是相等的。foo 5

如果我删除sqliteCreateCollation调用和 COLLATE NS 语句,它会起作用:/

有什么解决方案可以让我保留整理功能吗?我只需要它来订购,但显然它也用于比较......

4

2 回答 2

1

您已专门设置排序规则以进行不区分大小写的比较。尝试将其更改为:

$pdo->sqliteCreateCollation('NS', 'strnatcmp');

看看这是否有帮助。

于 2013-10-15T17:10:45.790 回答
1

您应该能够保留排序规则,但仅将其切换为二进制以用于触发器查询。

$pdo = new PDO('sqlite::memory:');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);      
$pdo->sqliteCreateCollation('NS', 'strnatcasecmp');      

$pdo->query('CREATE TABLE a(
   id INTEGER PRIMARY KEY AUTOINCREMENT,
   st INTEGER NOT NULL,
   p  INTEGER NOT NULL,
   name TEXT NOT NULL COLLATE NS,
   safe_name NOT NULL COLLATE NS)');

$pdo->query('CREATE TRIGGER uniqueness BEFORE INSERT ON a
  BEGIN
    SELECT RAISE(FAIL, "Record is not unique !")
    FROM a
    WHERE ((NEW.st <> 1) 
      AND (p = NEW.p)
      AND ((name COLLATE BINARY = NEW.name) OR (safe_name COLLATE BINARY = NEW.safe_name)));
  END;');

// success
$pdo->query('INSERT INTO a(st, p, name, safe_name) VALUES(2, 2, "Foo 5", "foo-5")');

// should work now
$pdo->query('INSERT INTO a(st, p, name, safe_name) VALUES(2, 2, "foo  5", "foo5")');
于 2013-10-15T17:26:51.397 回答