【问题标题】:Postgres : Complex Multiple Update query for one to many relationshipPostgres:一对多关系的复杂多次更新查询
【发布时间】:2019-08-30 22:33:40
【问题描述】:

我的数据库看起来像这样 https://dbfiddle.uk/?rdbms=postgres_10&fiddle=7e0cf7ad1e5bf9f4e0321a2e5ec970f7

所以

  • 一个用户可以拥有多本书
  • 基本的一对多关系

假设如果用户更新了现有书籍并添加了更多书籍, 我将如何对此进行查询?

我做了一些研究,得出的结论是,cte 或函数都可以帮助我。

我的请求正文 (JSON) 数据 FOR PATCH QUERY 看起来像这样

{
   // user data
      user_id: 1,
      name : 'Ryan',
      books : [
      {
        book_id : 1,
        stock : 500
      },
      {
        book_id : 2,
        stock : 500
      },
      {
        // this book should be added to the users_books table
        name: 'My new book 1',
        stock : 500
      }

      ]

}

The postgresql update queries for the above data should look like ->


UPDATE users_books(stock) VALUES(500) WHERE user_id = 1 AND book_id 1;
UPDATE users_books(stock) VALUES(500) WHERE user_id = 1 AND book_id 2;
INSERT INTO users_books(user_id,book_id,stock) VALUES(1,3,500);

所以看看上面的结构,我需要相应地更新 books_users 表。

我目前的理解是将书籍对象作为 jsonb 传递给 postgresql 的函数。然后在相应地更新/添加书籍的同时循环遍历它。我不确定如何知道用户是否已经拥有一本书。

你们如何将此请求正文转换为上述复杂的更新查询? 在函数中执行此操作是否完全是事务性的?

【问题讨论】:

  • 所以 users_books.user_id 和 users_books.book_id 是唯一的组合?
  • @madflow 是的。但我确实需要保持一对多的关系

标签: node.js postgresql plpgsql pg


【解决方案1】:

你可以在一个语句中完成这一切,但最好有一些独特的约束来防止它做坏事。 users_books(book_id, user_id) 应该是唯一的,而 books(name) 应该是唯一的。

这是fiddle

这是重要的部分:

-- The test data
with data(d) as (VALUES ('
{
      "user_id": 1,
      "name" : "Ryan",
      "books" : [
      {
        "book_id" : 1,
        "stock" : 500
      },
      {
        "book_id" : 2,
        "stock" : 500
      },
      {
        "name": "My new book 1",
        "stock" : 500
      }

      ]

}'::jsonb)
-- Parse the json to get user_id, book_id, stock, and name for each book
), normalized_data as (
    select (d ->> 'user_id')::int as user_id,
       book_id, stock, name
    FROM data
    JOIN LATERAL (SELECT * FROM jsonb_to_recordset(d -> 'books') 
                    as books(book_id int, stock int, name text)
    ) sub ON TRUE
-- Update existing stock
), update_existing as (
  UPDATE users_books set stock = normalized_data.stock
  FROM normalized_data
  WHERE users_books.user_id = normalized_data.user_id
    AND users_books.book_id = normalized_data.book_id
    AND normalized_data.book_id IS NOT NULL
-- insert any new books
), insert_new_book as (
INSERT INTO books (name)
  SELECT name from normalized_data
  WHERE book_id IS NULL
  RETURNING id, name
)
-- insert a record into users_books for new books
INSERT INTO users_books (user_id, book_id, stock)
SELECT user_id, id, stock
FROM insert_new_book
JOIN normalized_data ON normalized_data.name = insert_new_book.name;

【讨论】:

  • 我想制作书籍和用户 ID 唯一会破坏一对多的关系,对吧?
  • 不,它只会强制每个用户每本书只能有一个条目。不要让 book_id 和 user_id 唯一,使用 (book_id, user_id) 的组合。让它们都不是 null 可能是值得的。
  • 工作得很好@jeremy 你会推荐哪本书来更好地理解postgresql?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-08
  • 1970-01-01
  • 1970-01-01
  • 2017-06-15
相关资源
最近更新 更多