php - 使用 SELECT rows by ID 生成不同的唯一 ID
问题描述
这是一个 php mysqli 查询,其中有一个名为 result(uid,matchid,playerid,score) 的表我想根据带有 matchid 的 select 语句返回的行数生成一个唯一的 id 如果 matchid 为 0,它看起来像这样然后首先返回的行将为零,然后 uid 必须是 matchid+rows 返回,然后使用该 uid 保存数据并将 id 与其他详细信息匹配
我希望它必须返回这样的东西......即如果id1(ID)为0,那么唯一的id(UID)将是ID + UID,即00,01,02......等等,UID将基于以特定 id1(ID) 返回的行数。
另一个示例,采用不同的 ID,即如果 id1(ID) 为 1,则根据上述解释,它将是 ID+UID,即 10,11,12...等等,基于该 id1( ID)
我试图获取匹配 id 返回的行数,发现给出的结果是 0(必须表示 null),并且 scound time 它也返回 0,并且在第三次之后它开始递增值。即 00,00,01,02 等等
<?php
$ri=0;
$res=mysqli_query($c,"select rsid from result where mid='$m' ");
$rows=mysqli_num_rows($res);
$ri=$rows++;
echo ("<script> alert( '$ri' ); </script>");
//Unique Match Id for Player Result
$rsid = $m.$ri;
//Saving the data in the table
mysqli_query($c,"insert into result values('$rsid','$m','$u','$k','$w')");
?>
我预计输出为 00,01,02... 但输出为 00,00,01,02...
解决方案
为了产生你想要的结果,你可以在表上使用INSERT ... SELECT
带有COUNT
子查询的语法result
,以检索你的行数或 0,以及CONCAT()
产生mid
想要的rsid
值。
为了帮助防止 SQL 注入攻击,强烈建议使用准备好的语句,
假设rsid
是您的主键,您可以使用以下内容。
示例db-fiddle
//enable mysqli exception handling
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$c = mysqli_connect($host, $user, $pass, $dbname);
$query = <<<'EOL'
INSERT INTO `result`
SELECT
CONCAT(?, COALESCE((SELECT COUNT(r.rsid)
FROM `result` AS r
WHERE r.mid = ?
GROUP BY r.mid), 0)),
?, ?, ?, ?
EOL;
try {
/* example data
* $m = 0;
* $u = 1;
* $w = 1;
* $k = 1;
*/
$stmt = mysqli_prepare($c, $query)
mysqli_stmt_bind_param($stmt, 'ssssss', $m, $m, $m, $u, $k, $w);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
/*
* retrieve the theoretical last record inserted
*/
$stmt = mysqli_prepare($c, 'SELECT MAX(rsid) FROM result WHERE mid = ?');
mysqli_stmt_bind_param($stmt, 's', $m);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $rsid);
if (mysqli_stmt_fetch($stmt)) {
echo $rsid;
}
mysqli_stmt_close($stmt);
} catch(mysqli_sql_exception $e) {
//handle the exception
//echo $e->getMessage();
}
每次执行的结果
| execution | $rsid |
| 1 | 00 |
| 2 | 01 |
| 3 | 02 |
...
免责声明,您当前使用总行数生成的
rsid
方法会导致严重的数据完整性问题。当从表中删除一条记录时result
,检索到的COUNT
或mysqli_num_rows
将导致冲突rsid
。此外,如果mid
值被更改(更正错字),该rsid
值将变为无效。比赛条件/危险还需要考虑其他复杂情况。有关预防措施的详细信息,
请参阅sql - Do database transactions prevent race conditions
例如,如果您00
在数据库中已有记录,SELECT CONCAT(mid, COUNT(rsid)) WHERE mid = 0;
将返回01
. 插入01
然后删除后00
,您的下一个插入将是rsid
;01
的副本
INSERT INTO results(rsid)
VALUES(01);
DELETE FROM results WHERE rsid = '00';
INSERT INTO results(rsid)
VALUES(01); /* error duplicate key */
我建议使用SELECT MAX(rsid) + 1
而不是COUNT()
. 这将确保您rsid
在删除后不会重复,但不能解决UPDATE mid
问题。但是,您至少需要mid
1MAX() + 1
才能工作。
示例db-fiddle
INSERT INTO `result`
SELECT
COALESCE((SELECT MAX(r.rsid) + 1
FROM `result` AS r
WHERE r.mid = ?
GROUP BY r.mid), CONCAT(?, 0)),
?, ?, ?, ?
如果您绝对需要使用行数,为了避免复杂性,您需要确保只使用分组DELETE
中的最高rsid
记录,而不是列值。否则,您将需要在对表进行任何更改时重建所有值。如果您决定重建这些值,我建议使用更新前和删除后处理这两个实例并使用列来确定记录的顺序。mid
UPDATE
mid
rsid
rsid
triggers
DATETIME NULL DEFAULT CURRENT_TIMESTAMP
或者,您可以rsid
通过使用AUTO_INCREMENT
主键和增量用户变量生成仅在查看时。那么你就不再需要担心应用程序受控了rsid
,只需要插入即可mid
。
示例db-fiddle
SET @rsid: = NULL;
SET @mid = NULL;
SELECT
result.*,
CONCAT(mid, CASE WHEN @mid != result.mid OR @rsid IS NULL THEN @rsid := 0 ELSE @rsid := @rsid + 1 END) AS rsid,
@mid:=result.mid
FROM result
ORDER BY mid ASC, id ASC;
结果
| id | mid | ... | rsid |
| 1 | 0 | ... | 00 |
| 29 | 0 | ... | 01 |
| 311 | 0 | ... | 02 |
| 20 | 1 | ... | 10 |
| 40 | 1 | ... | 11 |
...
作为最后一种选择,您可以通过MyISAM 引擎AUTO_INCREMENT
指定复合主键来使用分段,该引擎不支持事务或外键引用。但是,这种方法还有其他复杂性。[原文如此]mid, id
AUTO_INCREMENT
如果删除AUTO_INCREMENT
任何组中值最大的行,值将被重用。
示例db-fiddle
CREATE TABLE `result` (
`mid` INT(11) UNSIGNED NOT NULL,
`id` INT(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`mid`, `id`)
)
ENGINE=MyISAM
;
INSERT INTO result(mid)
VALUES(0),(1),(0),(2),(0),(1);
SELECT
result.*,
CONCAT(mid, id) AS rsid
FROM result;
结果:
| mid | id | rsid |
| --- | --- | ---- |
| 0 | 1 | 01 |
| 0 | 2 | 02 |
| 0 | 3 | 03 |
| 1 | 1 | 11 |
| 1 | 2 | 12 |
| 2 | 1 | 21 |
要更新当前result
表,您可以使用
/* remove default value */
ALTER TABLE `result` ALTER `mid` DROP DEFAULT;
/* change engine, add id column, add composite primary key */
ALTER TABLE `result`
ENGINE=MyISAM,
CHANGE COLUMN `mid` `mid` INT(11) NOT NULL FIRST,
ADD COLUMN `id` INT(11) NOT NULL AUTO_INCREMENT AFTER `mid`,
ADD PRIMARY KEY (`mid`, `id`);
推荐阅读
- python - 在旧版 Windows 上运行现代 Python
- json - 是否可以使用 Eclipse 实现 JSON 模式自动完成和文档?
- reactjs - Reactjs onBlur-navbar
- java - 带有布局管理器的状态策略
- apache-spark - 从 spark sql 的 s3 下载的字节数是 hive sql 的数倍
- php - Laravel:hasMany 也从父表中获取值
- android - 为什么不 popBackStack,popBackStackImmediate 不工作并改变行为?
- android - 我可以将谷歌地图自动完成添加到我的 EditText 吗?
- pentaho-report-designer - 从另一个 pentaho 报告调用 pentaho 报告
- java - 无法读取硒中的属性文件(对象存储库)