【问题标题】:Generate different Unique IDs using SELECT rows by ID使用 SELECT rows by ID 生成不同的唯一 ID
【发布时间】:2019-08-20 04:17:03
【问题描述】:

这是一个 php mysqli 查询,其中有一个名为 result(uid,matchid,playerid,score) 的表 我想根据带有 matchid 的 select 语句返回的行数生成一个唯一的 id 看起来像这样 如果 matchid 为 0,则首先返回的行为零,然后 uid 必须为 matchid+返回的行数 然后使用该 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),并且scund 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...

【问题讨论】:

  • 这个问题是一个典型的 xy 问题

标签: php mysqli


【解决方案1】:

要产生您想要的结果,您可以在result 表上使用INSERT ... SELECT 语法和COUNT 子查询,以检索您的行数或0,以及@987654334 的CONCAT() @ 生成所需的rsid 值。

为帮助防止 SQL 注入攻击,强烈建议使用prepared statements,

假设 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 值将变为无效。

race conditions/hazards 还需要考虑其他复杂情况。
有关预防措施的详细信息,请参阅sql - Do database transactions prevent race conditions

例如,如果您在数据库中已有00 的记录,则SELECT CONCAT(mid, COUNT(rsid)) WHERE mid = 0; 将返回01。在插入01 然后删除00 之后,你的下一个插入将是01 的重复rsid;

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 至少需要 1 个,MAX() + 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)), 
?, ?, ?, ?

如果您绝对需要使用行数,为了避免复杂性,您需要确保在mid 分组中只记录DELETE 最高的rsid,而不是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 引擎指定复合主键 mid, id 来使用分段的AUTO_INCREMENT,该引擎不能够进行事务或外键引用。但是,这种方法还有其他复杂性。 [sic]

如果您删除任何组中具有最大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`);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-20
    • 1970-01-01
    • 2012-02-22
    • 1970-01-01
    • 2015-09-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多