Php 使用另一个表中另一行的值的行上的PDO事务更新错误

Php 使用另一个表中另一行的值的行上的PDO事务更新错误,php,mysql,if-statement,pdo,Php,Mysql,If Statement,Pdo,使用当前尝试代码更新 您好,我正在尝试对行值进行PDO检查,然后对表中的行执行Update语句,使用来自数据库中不同表的行的值,在事务内部执行,但我一直收到错误消息 我有两个表,它们是table1和bank table1包含列userid和ticketamount bank包含列userid和goldbalance ticketamount和goldbalance是整数。 这两行永远不会为NULL,创建用户帐户时,会在这些行中输入0的值,因此这些行中始终会有一个值 userid是唯一的列 我想做

使用当前尝试代码更新

您好,我正在尝试对行值进行PDO检查,然后对表中的行执行Update语句,使用来自数据库中不同表的行的值,在事务内部执行,但我一直收到错误消息

我有两个表,它们是
table1
bank

table1
包含列
userid
ticketamount

bank
包含列
userid
goldbalance

ticketamount
goldbalance
是整数。 这两行永远不会为
NULL
,创建用户帐户时,会在这些行中输入
0
的值,因此这些行中始终会有一个值

userid
是唯一的列

我想做的是运行一个PDO事务,它将通过添加存储在
goldbalance
中的任何值来更新
ticketamount
,我正试图通过将其设置为
ticketamount+(一些代码在这里获取goldbalance金额)

这是我的完整代码:

<?php
$servername = "myservername";
$username = "myusername";
$password = "mypassword";
$dbname = "mydbname";

try {
    $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    // set the PDO error mode to exception
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);


// first, find out if bank.goldbalance is > 0, if it is, then run Update statements and echo "1", else echo "0":

    $stmt = $conn->prepare("SELECT 'goldbalance' FROM 'bank' WHERE 'userid' = :id");
    $stmt->bindParam(':id', $userid);
    $userid = $_POST['userid'];

    $stmt->execute();

 if (($result['goldbalance']) > 0){

// if bank.goldbalance is greater than 0, then run this transaction:
    $conn->beginTransaction();

    // prepare UPDATE statement
    $sql = 'UPDATE table1 t
     LEFT JOIN bank b
     ON b.userid = t.userid
     SET t.ticketamount = t.ticketamount + b.goldbalance
     WHERE t.userid = :id';

    echo "SQL=" . $sql ;

    // prepare statement and bind parameters
    $stmt = $conn->prepare($sql); 
    $stmt->bindParam(':id', $userid);
    $userid = $_POST['userid'];

    $stmt->execute();

    // 2nd statement...
    $stmt = $conn->prepare("UPDATE 'bank' SET 'goldbalance' = 0 WHERE 'userid' = :id");
    $stmt->bindParam(':id', $userid);
    $userid = $_POST['userid'];

    $stmt->execute();

    $conn->commit();

    // echo "1" to verify transaction completed
    echo "1";

} else {
    echo '0';
}
        }
    catch(PDOException $e)
        {
        echo "Error: " . $e->getMessage();
        }
    $conn = null;
    ?>

如果bank.goldbalance=0,那么运行事务就没有意义了,所以我想先检查一下,如果bank.goldbalance=0,那么我只想回显“0”,但如果它=>0,那么我想运行事务,并在事务完成时回显“1”

我试图让交易获取bank.goldbalance中的值,然后将其添加到表1.ticketamount中的值。然后,事务的第二部分应将bank.goldbalance设置为“0”

我现在在控制台中得到的上面代码的响应是:

“错误:SQLSTATE[42000]:语法错误或访问冲突:1064您的SQL语法有错误;请查看与您的MySQL服务器版本对应的手册,以了解在第1行的”“bank”“附近使用的正确语法,其中”“userid”“='11323452347”“。”

我看不出这段代码有什么问题

关于这个问题的任何其他建议都非常好,
提前谢谢

要调试它,请将其分为两个步骤。首先,将SQL语句的文本作为字符串生成到变量中

然后,将变量传递给
prepare

在这两者之间,您可以对字符串变量执行
echo
var\u dump


在您的例子中,这是一个简单的PHP字符串文字/连接问题

第二个双引号以字符串文字结尾,PHP无法识别以下
SELECT…

$stmt = $conn->prepare("UPDATE 'table1' 
        SET 'ticketamount' = 'ticketamount'+("SELECT 'goldbalance'
                                             ^                     
单引号有问题;对于MySQL,这些应该是标识符周围的反标记


由于字符串中没有包含任何变量,因此它是一个静态文本(对于SQL来说,这是一件非常好的事情),因此可以使用单引号而不是双引号:

$sql = 'UPDATE `table1` t
           SET t.`ticketamount` = t.`ticketamount` 
                                + ( SELECT b.`goldbalance`
                                      FROM `bank` b
                                     WHERE b.`userid` = :id1
                                     LIMIT 1
                                  )
          WHERE t.`userid` = :id2';
#echo "SQL=" . $sql ;
$stmt = $conn->prepare($sql);
请注意,在带有PDO的语句中多次使用相同的bind变量名(至少以前是这样)会出现问题,因为PDO实际上是将其从命名符号转换为位置符号的

我还向子查询添加了一个
limit1
子句,因为如果返回多行,MySQL将抛出一个错误。(如果
userid
bank
表中是唯一的,则不会有什么区别。如果它不是唯一的,我们需要哪一行?最新的、goldbalance值最大的一行,等等。我们可以通过添加聚合或订单,使其更具确定性。)

如果一行没有返回,我们会得到一个空值,当我们添加一个空值时,我们会得到一个空值。我们是否要将缺少的行或空值处理为零

如果
userid
bank
表中是唯一的,我将使用join操作进行此查询。为了模拟子查询,我们需要一个外部连接,例如

由于没有一个标识符是保留字,我们不需要在标识符周围加上反标记

  UPDATE table1 t
    LEFT
    JOIN bank b
      ON b.userid = t.userid
     SET t.ticketamount = t.ticketmamount + IFNULL(b.goldbalance,0)
   WHERE t.userid = :id
如果我们想模拟原始查询,我们需要从about
b.goldbalance
中删除
IFNULL
包装,这样它就可以返回NULL,因此ticketamount将设置为NULL

如果我们不想在相关行从银行“丢失”时更新该行,我们可以执行内部联接而不是外部联接(即删除
LEFT
关键字)



您的表/列使用了错误的标识符限定符。在这里,添加
$conn->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_异常)打开连接后,您将看到“更多”语法错误。不要在标识符周围使用单引号,请使用反勾号。(单引号用于字符串文字,而不是表名或列名。)此外,我没有看到
$stmt->execute()
$result
之间的任何链接。。。但是您不需要运行单独的语句来检查
goldbalance
,当goldbalance为零时运行更新会更快,MySQL会发现该行实际上不需要更改。(如果我们希望goldbalance几乎总是为零,那么我会做单独的检查,也就是说,当运行更新时是例外,而不是规则。)如果您知道您将始终从
银行
中获得匹配行,则可以从更新语句中删除
LEFT
关键字。使用LEFT关键字,如果在bank中找不到匹配的行,那么语句将添加NULL,这将导致NULL值,我怀疑您不想用NULL覆盖ticketamount的值。(如果您保留LEFT关键字,您需要在IFNULL函数中包装goldbalance,以获得一个零来代替NULL。)您好@spencer7593非常感谢您的回复!读了你的答案后,我意识到