Если существующая запись, строка возвращается, но если вставлена ​​новая запись, строка не возвращается - PullRequest
0 голосов
/ 23 декабря 2018

Две таблицы.автор и книга

Я добавляю книгу в таблицу книг.Если перечисленный автор уже находится в таблице авторов, получите идентификатор автора и вставьте его в строку «Книга».Если автора нет в таблице авторов, вставьте нового автора и используйте идентификатор для вставки в строку «Книга».

Эта функция работает нормально.База данных отвечает соответствующим образом и с помощью приведенного ниже кода (не фактического кода, а более уточненной версии), и на соответствующие строки или ссылки создаются соответствующие ссылки.

Я также хочу, чтобы запрос возвращал строку Book, и это нормально.Строка «Книга» всегда возвращается во всех проверенных условиях, будь то книга с существующим автором или книга с известным автором.

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

СЕЙЧАС -> Если я вставлю Книгу с известным Автором, функциональность будет идеальной, и строка будет возвращена в соответствии с ожиданиями.Если я вставлю книгу с новым автором, новый автор все еще будет создан, новая книга все еще будет вставлена, НО НУЛЕВЫЕ строки возвращаются.

Я не уверен, почему это происходит или как я получу получениеряд.

CREATE TABLE author (id PRIMARY KEY, name VARCHAR (255));
CREATE TABLE book (id PRIMARY KEY, title VARCAR (255), author REFERENCES author (id));

WITH
s AS (
    SELECT id FROM author
    WHERE name = 'British Col'
),

i AS (
    INSERT INTO author(name)
    SELECT ('Eoin Colfer')
    WHERE NOT EXISTS (select 1 from s)
    RETURNING id
),

j AS (
    SELECT id FROM s
    UNION ALL
    SELECT id FROM i
),

ins AS (
    INSERT INTO book
            (title, author)
    SELECT 'Artemis Fowl', j.id
    FROM j
    RETURNING *
)

SELECT ins.*, author.*
FROM ins
JOIN author
ON ins.author = author.id 
;

1 Ответ

0 голосов
/ 23 декабря 2018

Объяснение

Это связано с поведением общих табличных выражений в PostgreSQL.

По документам (https://www.postgresql.org/docs/current/queries-with.html):

Подразделенияв WITH выполняются одновременно друг с другом и с основным запросом. Поэтому при использовании операторов модификации данных в WITH порядок, в котором фактически происходят указанные обновления, непредсказуем. Все операторы выполняются с одним и тем же снимком (см. главу 13).), поэтому они не могут «видеть» влияние друг друга на целевые таблицы. Это смягчает последствия непредсказуемости фактического порядка обновлений строк и означает, что данные RETURNING являются единственным способом передачи изменений между различными под-операторами WITH иосновной запрос. Примером этого является то, что в

WITH t AS (
    UPDATE products SET price = price * 1.05
    RETURNING *
)
SELECT * FROM products;

внешний SELECT будет возвращать исходные цены до действия ОБНОВЛЕНИЕ ...

последнее предложение (ниже фрагмента кода) имеет решающее значение.

Ваш запрос к auВ конце таблицы возвращаются данные, которые были до операторов вставки в CTE.


Альтернативный подход

Альтернативный подход заключается в выполнении этой работы.в функции, где вы можете использовать переменные.

Сначала предложим некоторые изменения в ваших таблицах:

CREATE TABLE author
(
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL UNIQUE -- Unique for ON CONFLICT later
);

CREATE TABLE book
(
  id SERIAL PRIMARY KEY,
  title TEXT NOT NULL,
  author_id INT NOT NULL REFERENCES author (id),
  UNIQUE (title, author_id) -- Prevent duplicates
);

Пример функции:

CREATE OR REPLACE FUNCTION add_book (in_book_title TEXT, in_author_name TEXT)
RETURNS TABLE
  (
    author_id INT,
    book_id INT,
    author_name TEXT,
    book_title TEXT
  )
AS $$

#variable_conflict use_column

DECLARE
  var_author_id INT;
  var_book_id INT;

BEGIN

-- Upsert author, return id
INSERT INTO author (name)
VALUES (in_author_name)
ON CONFLICT (name) DO
  UPDATE SET name = EXCLUDED.name -- Do update to allow use of returning
RETURNING id INTO var_author_id;

-- Upsert book, return id
INSERT INTO book (title, author_id)
VALUES (in_book_title, var_author_id)
ON CONFLICT (title, author_id) DO
  UPDATE SET title = EXCLUDED.title -- Do update to allow use of returning
RETURNING id INTO var_book_id;

-- Return the record using your join (similar)
RETURN QUERY
  SELECT a.id, b.id, a.name, b.title
  FROM author a
  INNER JOIN book b
  ON a.id = b.author_id
  WHERE b.id = var_book_id;

END;
$$ LANGUAGE PLPGSQL VOLATILE;

Использование:

SELECT * FROM add_book('Artemis Fowl', 'Eoin Colfer');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...