我的代码/语法有错吗?我不知道出了什么问题,而且我是新手。我在PHPMyAdmin中创建了一个表。它有两列。一个是"id",是主键/自动增量。另一列是"蒸汽名称"。
这个代码应该取一个人的网名并将其输入数据库。如果已经有一个记录,它应该以相同/最新的名称对其进行更新。
phpmyAdmin中表的名称是names
<?php
// Capture person's name from XML file
$profile = simplexml_load_file('UrlGoesHere.Com/?xml=1', 'SimpleXMLElement', LIBXML_NOCDATA);
echo (string)$profile->steamID;
//Enter name into databse and overwrite it if same/duplicate
$con=mysqli_connect("localhost","username","password","databaseName");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
// Perform queries
mysqli_query($con,"INSERT INTO names (steamname) VALUES ('$profile') ON DUPLICATE KEY UPDATE steamname = VALUES('$profile')");
mysqli_close($con);
?>
我通过手动将PHPMyAdmin中"steamname"中的一行的值更改为"woogy"来测试这一点,然后运行此脚本来查看它是否会更新该数据库值。。。什么也没发生。它应该将"woogy"更新为正确的名称。
---------------更新---------------
大家好。感谢您的意见。现在我的代码如下。如果还是错了,我很抱歉。我在学习。
<?php
$profile = simplexml_load_file('http://steamcommunity.com/profiles/76561198006938281/?xml=1', 'SimpleXMLElement', LIBXML_NOCDATA);
echo (string)$profile->steamID;
$con=mysqli_connect("localhost","userHere","passwordHERE","DBName");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
// Perform queries
mysqli_query($con,"INSERT INTO names (steamname) VALUES ('$profile') ON DUPLICATE KEY UPDATE ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname)");
mysqli_close($con);
?>
在运行脚本之前,数据库是这样的:(woogy应该改为Chatyak(
点击此处图片
现在,当我运行PHP页面时,我的数据库会发生这种情况。
运行脚本后数据库的外观
不知道为什么它没有更新,也不知道为什么有这么大的空间?
INSERT ... ON DUPLICATE KEY
的正确语法如下所示,您需要在VALUES
中提到类似VALUES(column_name)
而不是VALUES('$profile')
的列名。此外,如果是UPDATE
,则缺少PK列ID
。因为您要为特定的ID
值更新steamname
。
INSERT INTO names (steamname)
VALUES ('$profile')
ON DUPLICATE KEY UPDATE ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname)
(或(
INSERT INTO names (steamname)
VALUES ('$profile')
ON DUPLICATE KEY UPDATE steamname = VALUES(steamname)
引用自MySQL文档
如果表包含
AUTO_INCREMENT
列和INSERT ... UPDATE
插入一行,LAST_INSERT_ID()
函数返回AUTO_INCREMENT
值。如果该语句改为更新一行,LAST_INSERT_ID()
没有意义。但是,你可以解决这个问题使用CCD_ 14。
除非尝试插入与现有主键列或唯一键列冲突的值,否则不能使用INSERT ON DUPLICATE KEY UPDATE(IODKU(进行更新而不是插入新行。
由于在这个INSERT中没有为ID指定任何值,所以它总是递增自动递增主键并插入新行。
如果希望INSERT替换现有行的steamname,则必须在INSERT中指定ID值。
关于你的第一条评论:
我看了你的样品。这并不奇怪,它创造了一个新的行。它生成了一个新的自动递增ID值,因为您在INSERT中没有指定ID。因此,它自然而然地产生了新的争吵。它无法判断您要替换哪一行。
这里有一个演示:
mysql> create table names (id serial primary key, steamname text);
mysql> insert into names (steamname) values ('Woogy')
on duplicate key update ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname);
忽略ID = LAST_INSERT_ID(ID)
部分,这没有任何效果。这是一个禁忌@拉胡尔提出了这个建议,但不幸的是他或她错了。我将在以后的测试中去掉这个词。
那么,在这个INSERT中会发生什么呢?为steamname
指定一个值,但不为ID
指定值。因此MySQL为ID
生成了一个新值。这将成为新行的主键值,并且该行将插入蒸汽名称"Woogy"。
mysql> select * from names;
+----+-----------+
| id | steamname |
+----+-----------+
| 1 | Woogy |
+----+-----------+
接下来,我们尝试将名称更改为"Chatyak":
mysql> insert into names (steamname) values ('Chatyak')
on duplicate key update steamname = VALUES(steamname);
这将更改应用于哪一行?INSERT没有指定ID值,因此MySQL会自动增加另一个新的ID值。该值是新行的主键,这一行的蒸汽名称为"Chatyak"。
mysql> select * from names;
+----+-----------+
| id | steamname |
+----+-----------+
| 1 | Woogy |
| 2 | Chatyak |
+----+-----------+
这意味着如果每次INSERT时都让自动增量生成一个新的ID值,则永远无法触发ON DUPLICATE KEY部分每次INSERT都会产生一个新行。
正如我上面所说,除非您尝试插入一个与表中已存在的行的主键或唯一键冲突的值,否则ON DUPLICATE KEY不会执行任何操作。但在这种情况下,您并不冲突,您总是生成一个新的ID值。所以它插入了一个新行。
如果您对steamname有一个UNIQUE KEY约束,那么这将是触发on DUPLICATE KEY的另一个机会但它仍然不能满足你的要求
mysql> alter table names add unique key (steamname(20));
然后,如果您尝试插入与已存在的蒸汽名称相同的蒸汽名称,它将不会插入新行。它将更新现有行。
mysql> insert into names (steamname) values ('Chatyak')
on duplicate key update ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname);
Query OK, 0 rows affected (0.02 sec)
请注意,上面写着该语句插入了"0行"。
但这仍然不允许您更改现有的蒸汽名称。如果指定一个新名称,它只会插入一个新行。如果指定了已在使用的名称,则该名称是重复的,因此不会插入新行,但也不会更改名称。
如果您让INSERT语句自动递增一个新的ID值,您希望它如何应用于现有行?您认为它应该与现有的哪一行冲突?
关于你的第二条评论:
您不需要第二个唯一密钥,我只是想向您展示IODKU是如何工作的。
在考虑SQL语法之前,您必须考虑问题的逻辑。换句话说,如果您指定了一个新名称,您希望它替换现有的哪一行?
例如:
mysql> insert into names (id, steamname) values (123, 'Chatyak')
on duplicate key update steamname = VALUES(steamname);
这将起作用,因为如果存在ID为123的行,则此INSERT将导致重复密钥冲突,因此将触发ON duplicate key子句。但是在这个例子中,我们从哪里得到值123呢?大概在你的应用程序中,你知道你认为你在更新什么id。这有变量吗?它是否对应于用户的会话数据?
******************编辑:*************************
回应@Rahul提供的答案。此声明:
INSERT INTO names (steamname) VALUES ('$profile') ON DUPLICATE KEY UPDATE ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname)
在技术上是有效的,但无论发生什么,都将始终影响0行。事实上,它有很多错误,很难一一列举(这就是这次编辑的原因(。
本页底部MySQL文档中给出的ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id)
的用法是如何捕获已更新的行的id
值的示例,即未插入,因为否则LAST_INSERT_ID()
(无参数(将返回最后一个插入的id,在更新的情况下,这对于所讨论的行来说是没有意义的。
因此,如果上面的声明有效——尽管它不能——实际上与以下声明没有什么不同:
INSERT INTO names (steamname)
VALUES ('$profile')
ON DUPLICATE KEY UPDATE steamname = VALUES(steamname)
除了将该行的id
值更新为原来的值之外。
除此之外,该语句永远无法工作的原因是,除非存在重复键,否则ON DUPLICATE KEY UPDATE
子句永远不会被求值。当我们尝试将steamname
更新为等于steamname
的值时,也就是说,如果没有ON DUPLICATE KEY UPDATE
子句,也会发生同样的错误,即最初触发ON DUPLICATE KEY UPDATE
子句的值。
*********************编辑结束***************************
首先:当您尝试在查询中使用$profile
对象时,它仍然是SimpleXMLElement
对象的实例。因此调用了SimpleXMLElement::__toString
方法,但SimpleXMLElement::__toString
方法仅返回直接位于第一个元素内部的文本内容,而不返回任何子元素的文本。因此,如果在调用simplexml_load_file
返回的父元素中嵌套了一些元素<steamname>
和<steamID>
,则不会返回它们的值。请参阅手册。
第二:将VALUES
函数与UPDATE
子句一起使用时,正确的语法是引用类似于DUPLICATE KEY UPDATE colname = VALUES(some_col_name)
的列名。如果要使用显式值,则语法为DUPLICATE KEY UPDATE colname = 'value'
。请参阅手册。
第三:由于将id
设置为AUTO_INCREMENT
,所以在未显式插入id
值或使用WHERE
子句指定id
值的情况下插入到names
表中的任何行都将创建一个具有新的自动递增id
值的新行,无论您是否使用DUPLICATE KEY UPDATE
,因为AUTO_INCREMENT
将确保您永远不会生成重复密钥。
我认为您可以使用mysql的REPLACE
语句。这是最简单的查询,可以满足您所描述的需求。
REPLACE INTO `names` (`id`,`steamname`)
VALUES ($id, $steamname)
其中$id
是$profile->steamID
,而$steamname
是该行的steamname
列的新值(或不是新值(。
REPLACE
语句将简单地DELETE
,然后是INSERT
,其中id
值已经存在。但是,由于插入的是相同的id
,因此效果是在包含匹配id
值的行中更新steamname
的值请注意,如果在同一个表中除了id
和steamname
之外还有其他列,并且您没有在REPLACE
语句的VALUES
中包含它们的值,那么这些值将丢失
第四:对于调试这类事情,了解实际传递到查询字符串中的值非常重要b(知道您正在使用的基本查询语法是正确的,除了您正在(或没有(使用的任何特定值。
最后:让事情变得简单;既然您已经在SimpleXMLElement中使用对象表示法来访问元素值,为什么不在mysqli中也使用它呢?试试这个。它是未测试,但它认为它会为您工作。
<?php
// Capture person's name and id from XML file
$profile = simplexml_load_file('UrlGoesHere.Com/?xml=1', 'SimpleXMLElement', LIBXML_NOCDATA);
$profile_id = (string)$profile->steamID;
$profile_name = (string)$profile->steamName;
//connect to database
$mysqli = new mysqli("localhost","username","password","databaseName");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
//build query
//IMPROTANT: this will delete other fields(if any)
//> in the row, unless they are also refilled by this statement
$q = ("
REPLACE INTO `names` (`id`,`steamname`)
VALUES (?, ?)
");
//uncomment to debug query
//echo "<pre>$q</pre>";
//uncomment to debug values
//echo "<pre>profile_name: 'n $profile_name</pre>";
//echo "<pre>profile_id: 'n $profile_id</pre>";
//prepare statement using above query
$stmt = $mysqli->prepare($q);
//fill in '?'s with actual values
//first argument is the data types
//'i' [integer] 's' [string]
//follownig aruments fill in '?'s in order
$stmt->bind_param('is', $profle_id, $profile_name);
// execute statement
$stmt->execute();
//close statement
$stmt->close();
//close connection
$mysqli->close();
?>