Коррелированный подзапрос (или эквивалентный) в операторе SQLite UPDATE? - PullRequest
2 голосов
/ 27 ноября 2010

У меня есть база данных SQLite3, которая для оптимизации производительности использует вычисляемые столбцы, которые обновляются триггерами.

Я сейчас пытаюсь добавить триггер, который был бы аналогичен этому (непроверенному, но, вероятно, действительному) коду SQLAlchemy ORM

story.read_free = any(link.link_type.read_free for link in story.links)

... но мне трудно понять, как выразить это как UPDATE предложение. Вот что у меня так далеко:

CREATE TRIGGER IF NOT EXISTS update_link_type AFTER UPDATE ON link_types
  FOR EACH ROW WHEN old.read_free <> new.read_free BEGIN
    UPDATE stories SET
      read_free = CASE WHEN (
        SELECT 1 FROM links as l, link_types as lt WHERE lt.id = new.id AND l.link_type_id = lt.id AND l.story_id = stories.id
      ) THEN 1 ELSE 0 END
    WHERE id = (SELECT story_id from links as l, link_types as lt WHERE  l.link_type_id = lt.id AND lt.id = new.id)
  ;
END;

Моя конкретная проблема заключается в том, что я не могу понять, как обеспечить корреляцию подзапроса в CASE.

Либо SQLite отклоняет синтаксис (такие вещи, как UPDATE foo AS bar и UPDATE INNER JOIN ..., которые, очевидно, как вы это делаете на других БД), либо, как в приведенном мной примере, он действителен, но имеет неверное значение. (В этом случае «Установите read_free для этой истории, если существует какой-либо тип ссылки с read_free, независимо от того, есть ли в истории ссылки этого типа)

Если существует более чистая и краткая формулировка этого UPDATE, помимо простого решения проблемы, я также был бы признателен, если бы знал об этом. Даже если бы это сработало, это было бы очень уродливое решение по сравнению с худшим из остальных моих триггеров.

Ответы [ 2 ]

1 голос
/ 16 декабря 2010

Вместо UPDATE, вы могли бы использовать INSERT OR REPLACE вместо этого? В отличие от UPDATE, INSERT OR REPLACE принимает встроенный SELECT, так что вы можете использовать стиль UPDATE foo AS bar или UPDATE INNER JOIN Ваш SELECT может создать дубликаты строк в stories только с нужными вам столбцами.

0 голосов
/ 18 декабря 2010

Составляя предложение INSERT OR REPLACE, предложенное Роби (используя псевдоним REPLACE для упрощения любого потенциального будущего порта для MySQL), я понял, что мой разум застрял в колее, делая неправильные предположения и усложняя проблему. (Вероятно, начал работать над этим, когда сон лишен, а затем никогда не ставил под сомнение мои первоначальные выводы)

Затем я смог переформулировать мой UPDATE, чтобы потребовать только один JOIN (также не поддерживается SQLite), а затем переписать его как WHERE подзапрос.

Вот последний триггер, который привел:

CREATE TRIGGER IF NOT EXISTS update_link_type AFTER UPDATE ON link_types
FOR EACH ROW WHEN old.read_free <> new.read_free BEGIN
    UPDATE stories SET read_free = new.read_free
        WHERE id IN (SELECT story_id FROM links WHERE link_type_id = new.id)
    ;
END;

Гораздо чище и удобнее в обслуживании.

Я присуждаю награду Роби по двум причинам: во-первых, потому что я бы никогда не придумал этот ответ, если бы он не выбил меня из этой колеи. Во-вторых, потому что, если бы мои требования были такими, как я изначально полагал, его ответ был бы лучшим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...