【问题标题】:mariadb-connector executemany throws DataErrormariadb-connector executemany 抛出 DataError
【发布时间】:2020-05-03 15:14:04
【问题描述】:

我正在尝试使用 python-mariadb-connector 实现一些简单的 SQL 插入语句,但无法弄清楚我做错了什么。

数据库如下所示:

SET FOREIGN_KEY_CHECKS = false;

CREATE OR REPLACE TABLE `forums` (
  `id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE OR REPLACE TABLE `accounts` (
  `id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE OR REPLACE TABLE `posts` (
  `id` int(10) unsigned NOT NULL,
  `forum_id` int(10) unsigned NOT NULL,
  `account_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `posts_forum_fk` (`forum_id`),
  KEY `posts_account_fk` (`account_id`),
  CONSTRAINT `posts_account_fk` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`),
  CONSTRAINT `posts_forum_fk` FOREIGN KEY (`forum_id`) REFERENCES `forums` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE OR REPLACE TABLE `comments` (
  `id` int(10) unsigned NOT NULL,
  `post_id` int(10) unsigned NOT NULL,
  `account_id` int(10) unsigned NOT NULL,
  `parent_id` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `comments_post_fk` (`post_id`),
  KEY `comments_account_fk` (`account_id`),
--  KEY `comments_comments_fk` (`parent_id`),
--  CONSTRAINT `comments_comments_fk` FOREIGN KEY (`parent_id`) REFERENCES `comments` (`id`),
  CONSTRAINT `comments_account_fk` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`),
  CONSTRAINT `comments_post_fk` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

SET FOREIGN_KEY_CHECKS = true;

插入数据的代码如下:

import mariadb


config = {
    "user": "db_user_name",
    "password": "db_passwd",
    "host": "db_host",
    "port": 3306,
    "database": "db_name"
}


if __name__ == '__main__':
    with mariadb.connect(**config) as conn:
        cur = conn.cursor()
        cur.executemany(
            "INSERT INTO `forums` (`id`) VALUES (?)",
            [(1,), (2,), (3,)]
        )
        cur.executemany(
            "INSERT INTO `accounts` (`id`) VALUES (?)",
            [(1,), (2,), (3,), (4,)]
        )
        cur.executemany(
            "INSERT INTO `posts` (`id`, `forum_id`, `account_id`) VALUES (?, ?, ?)",
            [(6, 3, 1)]
        )
        cur.executemany(
            "INSERT INTO `comments` (`id`, `post_id`, `account_id`, `parent_id`) VALUES (?, ?, ?, ?)",
            [(1, 6, 1, None), (2, 6, 2, 1)]
        ) # exception happens here

执行此操作时,我收到以下错误:

Traceback (most recent call last):
  File ".../db_test.py", line 28, in <module>
    cur.executemany(
mariadb.DatabaseError.DataError: Invalid parameter type at row 2, column 4

我不确定 executemany 是如何实现的,但我认为它应该执行类似于以下 SQL 查询的操作:

INSERT INTO `forums` (`id`) VALUES (1), (2), (3);

INSERT INTO `accounts` (`id`) VALUES (1), (2), (3), (4);

INSERT INTO `posts` (`id`, `forum_id`, `account_id`) VALUES (6, 3, 1);

INSERT INTO `comments` (`id`, `post_id`, `account_id`, `parent_id`)
VALUES (1, 6, 1, NULL), (2, 6, 2, 1);

这对我来说很好......

这是一个错误还是我在这里做错了什么?

【问题讨论】:

    标签: python mysql database mariadb sql-insert


    【解决方案1】:

    我花了一点时间

        cur.executemany(
            "INSERT INTO `comments` (`id`, `post_id`, `account_id`, `parent_id`) VALUES (?, ?, ?, ?)",
            [(1, 6, 1, None), (2, 6, 2, 1)]
        ) 
    

    但是在你的评论表中你有这个限制

    CONSTRAINT `comments_comments_fk` FOREIGN KEY (`parent_id`) REFERENCES `comments` (`id`),
    

    在您可以输入 (2, 6, 2, 1) 之前,元组 (1, 6, 1, None) 必须已经提交到数据库中,并且在批量插入中,提交是在所有插入都在数据库中之后进行的,但第一个元组当时不存在

    所以如果你这样做,两行都会出现在数据库中(我还在批量插入后提交了所有其他表):

    MAriaDB

     mycursor.execute(
        "INSERT INTO `comments` (`id`, `post_id`, `account_id`, `parent_id`) VALUES (?, ?, ?, ?)",
        (1, 6, 1,None ))
     mydb.commit()    
     mycursor.executemany(
        "INSERT INTO `comments` (`id`, `post_id`, `account_id`, `parent_id`) VALUES (?, ?, ?, ?)",
        [ (2, 6, 2, 1)])    
     mydb.commit()
    

    MySQL

     sql = """INSERT INTO forums (id) VALUES (%s)"""
     val = [("1",), ("2",), ("3",)]
     mycursor.executemany(sql,val)
     mydb.commit()
     mycursor.executemany( 
        "INSERT INTO accounts (id) VALUES (%s)",
        [(1,), (2,), (3,), (4,)]
     )
     mydb.commit()
     mycursor.executemany(
        "INSERT INTO posts (id, forum_id, account_id) VALUES (%s, %s, %s)",
        [(6, 3, 1)]
     )
     mydb.commit()
     mycursor.execute(
        "INSERT INTO `comments` (`id`, `post_id`, `account_id`, `parent_id`) VALUES (%s, %s, %s, %s)",
        (1, 6, 1,None ))
     mydb.commit()    
     mycursor.executemany(
        "INSERT INTO `comments` (`id`, `post_id`, `account_id`, `parent_id`) VALUES (%s, %s, %s, %s)",
        [ (2, 6, 2, 1)])    
     mydb.commit()
    

    【讨论】:

    • 这是我的第一个猜测,这就是我注释掉这些行的原因。错误仍然出现,我 100% 确定这个约束实际上并不存在:
    • 正如我在回答中所写,您还必须提交用作参考的其他插入。在 VS 代码中,它很简单,只需一个一个地进行调试,它就会向您显示它退出的位置。我添加了 io 在 mysql 上使用的整个代码。论坛现在不同了,因为我不明白在这种情况下 python 是如何工作的
    • 我认为您误解了...您所指的约束从未存在过。在此示例中将其注释掉而不是简单地将其从代码中删除是我的错。为了更清楚,我做了一个简单的反例并偶然发现了错误(我认为是一个)executemany() 似乎无法在一列中处理混合类型。如果我更改我的代码,以便所有 parent_id 条目都是 None 或某个整数,它就可以正常工作。这也是您的代码有效的原因。您在两个单独的语句中将该列中的不同类型分开。
    • 是的,这是正确的,除了我的代码之外,连接器会引发无法解决的错误。在我的数据库中,所有约束都处于活动状态。我认为这是一个错误,因此您应该返回开发人员并报告它。我正在监视我的服务器,它根本没有收到任何插入。然后我添加了提交,所以它一直运行到那里的 cmets 唯一的解决方案就是我向你展示的内容。
    • 我创建了一张票。
    猜你喜欢
    • 2023-01-31
    • 2021-10-24
    • 1970-01-01
    • 2019-04-01
    • 1970-01-01
    • 2016-01-04
    • 2016-05-18
    • 2019-03-25
    • 2018-04-19
    相关资源
    最近更新 更多