【问题标题】:Stored procedure works on MySQL workbench, but not in python存储过程适用于 MySQL 工作台,但不适用于 python
【发布时间】:2018-12-12 21:07:47
【问题描述】:

我正在测试一个数据库,其中我有 3 个表,数字 1 存储用户信息,数字 2 存储不同城市的纬度和经度,还有一个存储用户位置和距离的第三个表最近的城市。第三个表具有来自其他两个表的主键的复合键。 我在 mysql 工作台中编写了一个存储过程,它接受 5 个变量,然后将数据插入到第三个表中,这是使用一些随机变量的代码:

SET @lat55 = 36.8451995849609;
SET @lng55 = 54.428798675537;
SET @city55 = 'Rasht';
SET @state55 = 'Gilan';
SET @user_id55 = 70440675;


DELIMITER //  
DROP PROCEDURE IF EXISTS do1 //
CREATE PROCEDURE do1 (IN id INT, IN state VARCHAR(25), IN city VARCHAR(25),             
IN lat DECIMAL(15,13),IN lng DECIMAL(15,12))
BEGIN

`  `DECLARE dmini DECIMAL(5,1);
    DECLARE lmini INT;

    SELECT location_id, ST_Distance_Sphere(POINT(lng,lat), geopoint)/1000 AS 
    distance INTO lmini, dmini FROM locations ORDER BY distance ASC LIMIT 1;

    INSERT INTO user_has_loc (user_id, location_id, distance, state, city, 
    lat, lng) VALUES (id, lmini, dmini, state, city, lat, lng);
END;
//

CALL do1(@user_id55,@state55,@city55,@lat55,@lng55);

它工作得很好并插入到表中,但是当我尝试使用来自 python 的相同变量调用相同的过程时,它什么也不做:

try:
    mydb = mysql.connector.connect(
        host="localhost",
        user="root",
        password="123456",
        database="v21")
    c = mydb.cursor()

    lat = 36.8451995849609
    lng = 54.428798675537
    city = "Rasht"
    state = "Gilan"
    user = 70440675

    arg = (user, state, city, lat, lng)

    c.callproc('do1', arg)

except mysql.connector.Error as err:
    print("Something went wrong: {}".format(err))

当我使用它时

c.execute("CALL do1({},{},{},{},{})".format(user, state, city, lat, lng))

它给出了另一个错误,说“'字段列表'中的未知列'Gilan'”。有趣的是,如果我手动将相同的数据插入到表中,那么当我尝试从 python 调用该过程时,它会引发错误:“重复条目 '70440675-883' for key 'PRIMARY'”。所以它似乎试图插入到表中,但它没有保存它! 有人可以告诉我我在这里做错了什么吗?

【问题讨论】:

  • 我没有使用 MySQL 的经验,但真的应该有一个变量 @pt1 没有在其他任何地方引用吗?
  • 我从我正在研究的早期版本中复制了上面的代码,应该是@pointt,我会在我的问题中编辑它,谢谢

标签: python mysql mysql-python


【解决方案1】:

Answer ----->> 所以最后我能够让它工作,诀窍是在我从 python 调用过程之后添加 mydb.commit()

try:
    mydb = mysql.connector.connect(
        host="localhost",
        user="root",
        password="123456",
        database="v21")
    c = mydb.cursor()

    lat = 36.8451995849609
    lng = 54.428798675537
    city = "Rasht"
    state = "Gilan"
    user = 70440675

    arg = (user, state, city, lat, lng)

    c.callproc('do1', arg)
    mydb.commit()

except mysql.connector.Error as err:
    print("Something went wrong: {}".format(err))

文档中没有提到我们在使用.callproc()方法后需要使用.commit(),尤其是在数据库端完成所有更新和插入时。但是,.commit() 文档中提到

由于默认情况下连接器/Python 不会自动提交,因此在修改使用事务存储引擎的表的数据的每个事务之后调用此方法很重要。

所以我的猜测是因为该过程试图操作数据库上的数据并且它是从 python 客户端调用的,所以我们需要在使用 .callproc() 之后使用 .commit()。

【讨论】:

    【解决方案2】:

    我的猜测是存储过程的第二个和第三个查询之间可能存在一些舍入问题。您可能会考虑完全消除第二个查询,只需将第三个查询更改为如下所示:

    SELECT location_id, ST_Distance_Sphere(@pt1, geopoint)/1000 AS distance
    INTO @lmini, @mini
    FROM locations
    ORDER BY distance ASC
    LIMIT 1;
    

    *我说“类似”是因为我最近主要在 MSSQL 中工作,并且在我使用 MySQL 时并没有做很多 SELECT INTO。 (具体来说,我不记得你是否可以像这样使用别名。)

    【讨论】:

    • 它尝试了你所说的,但仍然无法在 python 中工作,有趣的是它不再引发错误,它只是什么都不做
    • 也许仔细检查 proc 从两个调用方法中获取的值,您可以在 proc 的开头放置一个 insert into somelog 并查看传入的值是否看起来不同;听起来 proc 几乎没有找到任何关闭的东西。
    • 另外,在存储过程中使用 session/@ 变量要小心一点;它们具有连接范围,因此 proc 调用最终可能会在连接的其他地方和/或更早时设置初始值。并确保您在我的回答中将@pt1 更正为@pointt,我从您更正问题中的错字(?)之前开始。
    • 好吧,我更改了@变量并在过程中声明了两个单独的变量,我还检查了过程是否接收到输入变量,这表明它可以,但它仍然没有插入桌子和以前一样
    猜你喜欢
    • 1970-01-01
    • 2018-05-21
    • 2020-05-30
    • 2017-12-27
    • 2016-10-16
    • 2020-08-27
    • 1970-01-01
    • 2011-01-23
    • 1970-01-01
    相关资源
    最近更新 更多