【问题标题】:MySQL: save JSON data via stored procedure in Node.jsMySQL:通过 Node.js 中的存储过程保存 JSON 数据
【发布时间】:2020-05-21 11:54:00
【问题描述】:

我正在尝试使用 MySQL 和 Node 中的存储过程保存一些 JSON 数据。

我有 postpost_tagtag 表。

DROP TABLE IF EXISTS post_tag;
DROP TABLE IF EXISTS post;
DROP TABLE IF EXISTS tag;
DROP PROCEDURE IF EXISTS select_all_posts;
DROP PROCEDURE IF EXISTS insert_post;

CREATE TABLE post (
  id INT NOT NULL AUTO_INCREMENT,
  title VARCHAR(45) NULL,
  body TEXT NULL,
  my_data TEXT NULL,
  PRIMARY KEY (id));

CREATE TABLE tag (
  id INT NOT NULL AUTO_INCREMENT,
  tag VARCHAR(45) NULL UNIQUE,
  PRIMARY KEY (id));

CREATE TABLE post_tag (
  post_id INT NOT NULL,
  tag_id INT NOT NULL,
  PRIMARY KEY (post_id, tag_id),
  INDEX fk_post_tag_tag1_idx (tag_id ASC) VISIBLE,
  INDEX fk_post_tag_post_idx (post_id ASC) VISIBLE,
  CONSTRAINT fk_post_tag_post
    FOREIGN KEY (post_id)
    REFERENCES post (id),
  CONSTRAINT fk_post_tag_tag1
    FOREIGN KEY (tag_id)
    REFERENCES tag (id));

INSERT INTO post (id, title, body) VALUES (1, 'post 1', "Post body");
INSERT INTO post (id, title, body) VALUES (2, 'post 2', "Post body");
INSERT INTO tag (id, tag) VALUES (1, 'tag 1');
INSERT INTO tag (id, tag) VALUES (2, 'tag 2');
INSERT INTO post_tag (post_id, tag_id) VALUES (1, 1);
INSERT INTO post_tag (post_id, tag_id) VALUES (1, 2);
INSERT INTO post_tag (post_id, tag_id) VALUES (2, 1);

现在我想用两个标签保存一篇文章,所以我创建了这个存储过程:

-- Stored procedure to insert post and tags
DROP PROCEDURE IF EXISTS insert_post;
DELIMITER $$
CREATE PROCEDURE insert_post(
  IN my_data JSON
)
BEGIN
  -- Declare iterator variable to use it later on in the loop
  DECLARE i INT DEFAULT 0;

  -- Retrieve values from JSON
  SET @title = JSON_UNQUOTE(JSON_EXTRACT(my_data, '$.title'));
  SET @body = JSON_UNQUOTE(JSON_EXTRACT(my_data, '$.body'));
  SET @tags = JSON_EXTRACT(my_data, '$.tags');
  SET @json = JSON_UNQUOTE(my_data);
  -- Insert post
  INSERT INTO post (title, body, my_data) VALUES (
    @title,
    @body,
    @json);
  -- Retrieve inserted id to reuse it in post_tag
  SET @last_post = LAST_INSERT_ID();

  -- Get tags length for the loop
  SET @tags_length = JSON_LENGTH(@tags);
  -- Execute loop over tags length
  WHILE i < @tags_length DO
    -- Retrieve current tag from tags array
    SET @tag = JSON_UNQUOTE(JSON_EXTRACT(my_data, CONCAT('$.tags[',i,'].tag')));

    -- Insert tag
    INSERT INTO tag (tag) VALUES (
    @tag
    ) ON DUPLICATE KEY UPDATE tag = @tag;
    -- -- Retrieve inserted tag to reuse it on post_tag
    SET @last_tag = LAST_INSERT_ID();
    -- Insert retrieved post_id and tag_id into post_tag
    INSERT INTO post_tag (post_id, tag_id) VALUES (
      @last_post,
      @last_tag
    ) ON DUPLICATE KEY UPDATE post_id = @last_post, tag_id = @last_tag;
    -- -- Add step to iterator
    SELECT i + 1 INTO i;
  END WHILE;
END $$
DELIMITER ;

我可以直接用SQL测试一下:

CALL insert_post('{"title":"My post","body":"postbody","tags":[{"tag":"tag 3"}]}');

这样会成功,因为没有重复的标签。

CALL insert_post('{"title":"My post","body":"postbody","tags":[{"tag":"tag 1"}]}');

这将失败,因为已经有一个tag 1

我该如何解决这个问题?

【问题讨论】:

  • JSON_UNQUOTE()?替换()?
  • 嗨@Akina,不明白你的意思。你会如何在这里使用 REPLACE?
  • 刚刚发现它现在是 JSON_UNQUOTE 的问题,但是 post_tag 有两个键并且 ON DUPLICATE KEY UPDATE

标签: mysql sql json stored-procedures mysql-json


【解决方案1】:
CREATE PROCEDURE insert_post(
  IN my_data JSON
)
BEGIN
  -- Declare iterator variable to use it later on in the loop
  DECLARE i INT DEFAULT 0;

  -- Retrieve values from JSON
  SET @title = JSON_EXTRACT(my_data, '$.title');
  SET @body = JSON_EXTRACT(my_data, '$.body');
  SET @tags = JSON_EXTRACT(my_data, '$.tags');
  SET @json = JSON_UNQUOTE(my_data);
  -- Insert post
  INSERT INTO post (title, body, my_data) VALUES (
-- ****    UNQUOTE values    ****
    JSON_UNQUOTE(@title),
    JSON_UNQUOTE(@body),
    @json);
  -- Retrieve inserted id to reuse it in post_tag
  SET @last_post = LAST_INSERT_ID();

  -- Get tags length for the loop
  SET @tags_length = JSON_LENGTH(@tags);
  -- Execute loop over tags length
  WHILE i < @tags_length DO
    -- Retrieve current tag from tags array
    SET @tag = JSON_EXTRACT(my_data, CONCAT('$.tags[',i,'].tag'));

    -- Insert tag
    INSERT INTO tag (tag) VALUES (
-- ****    UNQUOTE value    ****
      JSON_UNQUOTE(@tag)
    ) ON DUPLICATE KEY UPDATE tag = JSON_UNQUOTE(@tag);
    -- Retrieve inserted tag to reuse it on post_tag
-- ****    ODKU and LAST_INSERT_ID are not relative!!! removed.    ****
--    SET @last_tag = LAST_INSERT_ID();
-- ****    Retrieve according `id`    ****
    SELECT id INTO @last_tag
    FROM tag
    WHERE tag = JSON_UNQUOTE(@tag);
    -- Insert retrieved post_id and tag_id into post_tag
    INSERT INTO post_tag (post_id, tag_id) VALUES (
      @last_post,
      @last_tag
    ) ON DUPLICATE KEY UPDATE post_id = @last_post, tag_id = @last_tag;
    -- Add step to iterator
    SELECT i + 1 INTO i;
  END WHILE;
END

fiddle

PS。您可以使用ON DUPLICATE KEY UPDATE tag = VALUES(tag); 代替ON DUPLICATE KEY UPDATE tag = JSON_UNQUOTE(@tag);post_tag 也是如此。 fiddle.

【讨论】:

  • 有趣! «LAST_INSERT_ID are not relative» 是什么意思?
  • 还有,ODKU 是什么?
  • @EmilleC。你尝试插入。如果没有重复,则执行插入,生成新的id,然后检索。但是如果检测到重复怎么办?而是执行了更新。是否执行了 INSERT?不。最后插入的id 是否已生成并且现在存在?不。 LAST_INSERT_ID() 将返回零。这导致了关键的小提琴。 什么是 ODKU ON DUPLICATE KEY UPDATE 缩写。
  • 很好的解释:更新不会生成LAST_INSERT_ID()...谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-01
  • 1970-01-01
  • 2020-01-14
  • 1970-01-01
  • 2022-01-26
相关资源
最近更新 更多