我的代码/语法错了吗?我不确定出了什么问题,对此我不熟悉。我在PHPMyAdmin中创建了一个表。它有两列。一个是" id"并且是主键/自动增量。另一列是" steamname"。
此代码应该采用某人的在线名称并将其输入数据库。如果已有记录,则应使用相同/最新名称进行更新。
phpmyAdmin中表格的名称是名称
<?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);
?>
我通过手动更改&#34; steamname&#34;中行的值来测试了这一点。在PHPMyAdmin到&#34; woogy&#34;然后运行此脚本以查看它是否会更新该数据库值...没有发生任何事情。它应该更新&#34; woogy&#34;正确的名称。
----------- ---------------更新
大家好。谢谢你的反馈。我现在的代码如下。对不起,如果还是错的话。我正在学习。
<?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页面时,这就是我的数据库。
How database looks after running script
不确定为什么它没有更新 - 以及为什么会有这么大的空间?
答案 0 :(得分:2)
INSERT ... ON DUPLICATE KEY
的正确语法如下所示,您需要在VALUES
中提及VALUES(column_name)
而非VALUES('$profile')
的列名称。此外,如果ID
,您错过了PK列UPDATE
。因为您要更新特定steamname
值的ID
。
INSERT INTO names (steamname)
VALUES ('$profile')
ON DUPLICATE KEY UPDATE ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname)
(OR)
INSERT INTO names (steamname)
VALUES ('$profile')
ON DUPLICATE KEY UPDATE steamname = VALUES(steamname)
如果表格包含
AUTO_INCREMENT
列且INSERT ... UPDATE
插入一行,LAST_INSERT_ID()
函数返回AUTO_INCREMENT
值。LAST_INSERT_ID()
如果语句更新了一行,LAST_INSERT_ID(expr)
没有意义。但是,你可以解决这个问题 使用{{1}}。
答案 1 :(得分:1)
除非您尝试插入与现有主键或唯一键列冲突的值,否则不能使用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)
部分,这没有任何效果。这是一个无操作。 @Rahul建议,但不幸的是,他或她错了。我将在后续测试中取出该术语。
那么这个INSERT会发生什么?您为steamname
指定了值,但ID
没有值。所以MySQL为ID
生成一个新值。这将成为新行的主键值,并使用steamname&#39; Woogy&#39;插入该行。
mysql> select * from names;
+----+-----------+
| id | steamname |
+----+-----------+
| 1 | Woogy |
+----+-----------+
接下来,我们尝试将名称更改为&#39; Chatyak&#39;:
mysql> insert into names (steamname) values ('Chatyak')
on duplicate key update steamname = VALUES(steamname);
这会将更改应用于哪一行? INSERT未指定ID值,因此MySQL会自动增加另一个新ID值。该值是新行的主键,而且是获取steamname&#39; Chatyak&#39;的行。
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));
然后,如果您尝试将相同的 steamname插入已存在的那个,它将不会插入新行。它会更新现有的行。
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)
注意它说&#34; 0行&#34;被该声明插入。
但是这仍然不允许您更改现有的steamname。如果指定新名称,则只需插入新行。如果您指定的名称已经在使用中,则它会重复,因此无法插入新行,但也不会更改名称。
如果允许INSERT语句自动递增新的ID值,您如何期望INSERT语句应用于现有行?您认为哪个现有行应与之冲突?
重新发表您的第二条评论:
您不需要辅助唯一密钥,我只想告诉您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。有变量吗?它是否与用户的会话数据相对应?
答案 2 :(得分:1)
<强> **************************编辑:**************** *********
回应@Rahul提供的答案。这句话:
INSERT INTO names (steamname) VALUES ('$profile') ON DUPLICATE KEY UPDATE ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname)
在技术上是有效的,但无论如何都会完全影响0行。实际上它有很多错误,很难枚举它们(这就是编辑的原因)。
在this page底部的MySQL文档中提供的ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id)
的使用是如何捕获已更新的行的id
值的示例即未插入,因为否则LAST_INSERT_ID()
(没有参数)会返回最后一个插入 ID,如果是更新< / strong>对于有问题的行而言没有意义。
所以上述陈述,如果它曾经有效 - 虽然它不能 - 与这句话实际上没有什么不同:
INSERT INTO names (steamname)
VALUES ('$profile')
ON DUPLICATE KEY UPDATE steamname = VALUES(steamname)
除了您还要将该行的id
值更新为已经存在的值。
除此之外,语句永远不会起作用的原因是因为除非存在重复键,否则永远不会评估ON DUPLICATE KEY UPDATE
子句。如果我们尝试将ON DUPLICATE KEY UPDATE
更新为等于steamname
的值,即与steamname
相同的值,则会发生没有ON DUPLICATE KEY UPDATE
子句时发生的相同错误首先是条款。
*****************************编辑结束************ *********************** 强>
首先:当您尝试在查询中使用$profile
时,SimpleXMLElement
仍然是SimpleXMLElement::__toString
对象的实例。因此调用了SimpleXMLElement::__toString
方法,但<steamname>
方法仅从第一个元素中直接返回文本内容,而不返回任何后代的文本。因此,如果您在<steamID>
调用返回的父元素中嵌套了一些元素simplexml_load_file
和一些元素VALUES
,则不会返回它们的值。请参阅manual。
第二:当UPDATE
函数与DUPLICATE KEY UPDATE colname = VALUES(some_col_name)
子句一起使用时,正确的语法是引用列名,如DUPLICATE KEY UPDATE colname = 'value'
。如果要使用显式值,则语法为id
。请参阅manual。
第三:由于您已将AUTO_INCREMENT
设置为names
,因此在id
表中插入任何行而未明确插入WHERE
值或使用id
指定id
值的子句将创建一个新行,其中包含新的自动递增DUPLICATE KEY UPDATE
值,无论您是否使用AUTO_INCREMENT
,因为 REPLACE
将确保您永远不会生成重复的密钥。
我认为您可以使用mysql的REPLACE INTO `names` (`id`,`steamname`)
VALUES ($id, $steamname)
语句代替。这是最简单的查询,适用于您描述的需求。
$id
其中$profile->steamID
为$steamname
,而steamname
是该行REPLACE
列的新(或非新)值。
DELETE
语句只会INSERT
,然后id
已存在id
值。但是,由于您要插入相同的steamname
,因此效果是更新包含匹配id
值的行中id
的值。 请注意,如果您在同一个表格中除steamname
和REPLACE
之外还有其他列,并且您未在VALUES
语句中包含其值 <?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();
?>
然后这些价值将会丢失。
最后:让自己轻松自如;因为你已经使用SimpleXMLElement的对象表示法来访问元素值,为什么不将它与mysqli一起使用呢?试试这个。它是 UNTESTED ,但它认为它对您有用。
{{1}}