Php 基于其他一些行创建具有非唯一键的mysql行

Php 基于其他一些行创建具有非唯一键的mysql行,php,mysql,sql,Php,Mysql,Sql,数据库示例: | country | animal | size | x_id* | |---------+--------+--------+-------| | 777 | 1001 | small | 1 | | 777 | 2002 | medium | 2 | | 777 | 7007 | medium | 3 | | 777 | 7007 | large | 4 | | 42 | 100

数据库示例:

| country | animal | size   | x_id* |
|---------+--------+--------+-------|
|  777    | 1001   | small  |   1   |
|  777    | 2002   | medium |   2   |
|  777    | 7007   | medium |   3   |
|  777    | 7007   | large  |   4   |
|  42     | 1001   | small  |   1   |
|  42     | 2002   | medium |   2   |
|  42     | 7007   | large  |   4   |
我需要根据(动物、大小)中的条目连续生成
x_id
,如果组合
x_id
存在,请再次使用它

目前,我使用以下PHP脚本来执行此操作,但在大型db表上,速度非常慢

query("UPDATE myTable SET x_id = -1");

$i = $j;
$c = array();
$q = query("
    SELECT animal, size
      FROM myTable
     WHERE x_id = -1
  GROUP BY animal, size");

while($r = fetch_array($q)) {

  $hk = $r['animal'] . '-' . $r['size'];

  if( !isset( $c[$hk] ) ) $c[$hk] = $i++;

  query("
      UPDATE myTable
       SET x_id = {$c[$hk]}
     WHERE animal = '".$r['animal']."'
       AND size = '".$r['size']."'
       AND x_id = -1");

}
有没有办法将PHP脚本转换为一个或两个mysql命令

编辑:


您可以使用
x\u id
,如下所示:

CONCAT(`animal`, '_', `size`) AS `x_id`
然后将其与
x_id
进行比较,这样您将得到如下结果:

+---------+-----------+--------+------------------+
| country | animal    | size   | x_id*            |
+---------+-----------+--------+------------------+
| africa  | crocodile | small  | crocodile_small  |
| africa  | elephant  | medium | elephant_medium  |
| africa  | giraffe   | medium | giraffe_medium   |
| africa  | giraffe   | large  | giraffe_large    |
| europe  | crocodile | small  | crocodile_small  |
| europe  | elephant  | medium | elephant_medium  |
| europe  | giraffe   | large  | giraffe_large    |
+---------+-----------+--------+------------------+

这是一个概念性的问题。如果有用的话,就把它植入你的世界

模式 一些疑问 注意:
insert ignore
说做它,忽略它可能死亡的事实。在我们的例子中,它将由于唯一密钥(这很好)而失败。通常,除非您知道自己在做什么,否则不要使用
insert ignore

通常认为它与重复密钥更新时的插入(IODKU)调用有关。或者我应该说,我在想,我如何才能解决目前的困境。但是,在这种情况下(IODKU)将是一个延伸。然而,将这两种方法都放在你的工具箱中以寻求解决方案

insert ignore触发后,您知道,不管怎样,行就在那里

忘记INNODB间隙方面,上面的建议是,如果行在insert ignore之前已经存在,那么

对于
id

因此,在触发insert ignore之后,去获取您知道必须存在的id。在针对CountryAnimalSize的后续调用中使用该选项

对于您的CountryAnimalSize表插入,如果行可能已经存在,也可能尚未存在,请继续进行这一推理

这里没有理由将解决方案形式化,因为正如您所说的,这些表根本不是问题中的表

另外,回到
INNODB GAP
。谷歌。弄清楚你是否可以在创建的间隙中生活

大多数人都有更大的事情要做,那就是保持身份证的紧密和无间隙

其他人(读作:强迫症)被感知到的差距问题消耗殆尽,以至于为此浪费了好几天的时间


因此,这些是一般性的评论,旨在帮助更广泛的受众,而不是回答您的问题,正如您所说,这甚至不是您的模式。

用户变量很难理解,但应该可以在我的机器上测试

CREATE TABLE t
( animal VARCHAR(20),
 size VARCHAR(20),
x_id INT);

 INSERT INTO T(animal,size) VALUES('crocodile','small'),
   ('elephant','medium'),
 ('giraffe','medium'),
 ('giraffe','large'),
 ('crocodile','small'),
 ('elephant','medium'),
 ('giraffe','large');




 UPDATE t  RIGHT JOIN
 (SELECT animal,size,
MIN(CASE WHEN @var:=CONCAT(animal,size) THEN @id ELSE @id:=@id+1  END)id
FROM t,
(SELECT  @var:=CONCAT(animal,size) FROM t)x ,
                      (SELECT @id:=0)y
                     GROUP BY animal,size)q
                     ON t.animal=q.animal AND t.size=q.size
                     SET x_id=q.id
结果

"animal"    "size"     "x_id"
"crocodile" "small"     "1"
"elephant"  "medium"    "2"
"giraffe"   "medium"    "3"
"giraffe"   "large"     "4"
"crocodile" "small"     "1"
"elephant"  "medium"    "2"
"giraffe"   "large"     "4"
您希望添加这些索引以加快访问速度

ALTER TABLE `yourtable` ADD INDEX `as_idx` (`animal`,`size`);
ALTER TABLE `yourtable` ADD INDEX `id_idx` (`x_id`);


子查询中不需要group by。它会产生无用的开销。如果速度足够快,请保持这样,否则我们可以使用distinct+另一个子查询。

如我所见,您已经在使用
MyISAM
引擎类型,您可以将
国家
x\u id
字段定义为
主键
(联合使用)您可以为
x\u id
字段设置
AUTO\u INCREMENT
。现在
MySQL
将为您完成剩下的工作!宾果

这是给你的礼物

结果如下:

| country | animal | size   |lang_id | x_id  | 
|---------+--------+--------+--------+-------|
|  777    | 1001   | small  |   1    |   1   |
|  777    | 2002   | medium |   1    |   2   |
|  777    | 7007   | medium |   1    |   3   |
|  777    | 7007   | large  |   1    |   4   |
|  42     | 1001   | small  |   1    |   1   |
|  42     | 2002   | medium |   1    |   2   |
|  42     | 7007   | large  |   1    |   4   |
注意:这仅适用于
MyISAM
BDB
表,对于其他引擎类型,您将收到错误提示:“表定义不正确;只能有一个自动列,必须将其定义为键!”有关此项的详细信息,请参阅此答案:



您可以只使用视图,也可以只使用查询,不需要存储它。@user5717193它需要一个关系表。你准备好了吗?我知道建立关系表是正确的方法,但现在为时已晚/我想有人会喜欢更新。。内部连接。。SET..IFNULL(b.x_id,MAX(c.x_id))可以是解决方案创建包含动物和大小的单个表。用它来支持所示的表格。那是一个hint@Drew我知道这是正确的方法,但是我不能改变这个db表,复杂性比这个小例子要复杂得多,我可以帮助你,但是它会令人难以置信地困惑,你说你不能改变模式。所以idk。为什么要吹20分钟呢。这对任何人都没有用:Pi不能更改行或拆分表,但我可以向Drew、Sebas和Mihai添加索引或其他内容-干得好!今天是圣诞节。我想我会留给你一些东西。圣诞快乐,你的工作得到了+1,但这不是我问题的解决方案。在我结束这个过程之前,它运行了超过40分钟,这并不比我的php脚本在超过18k条目的输入上好,谢谢你的支持time@HQ5在问题中显示表格定义,对于18K行,此查询肯定不会花费超过一秒的时间
SHOW CREATE TABLE yourtable
您对表定义的意思是什么?@HQ5运行我在评论中发布的查询,用该查询的结果编辑您的问题会变得复杂,而不是这里的确切示例此命令运行良好,这正是我想要的,但它运行了30-40分钟,一个MyPHP脚本运行了一个小时:18k(查询耗时5.9308秒),索引为@Mihai-谢谢!!根据您的评论,我没有建议任何与ddl相关的内容,用粗体
表示我无法更改此db表
。但我很高兴你不管怎么说都解决了。CheersALTER表
myTable
添加主键(
country
animal
);返回键'PRIMARY'@HQ5的#1062-重复条目'####',您的错误已经告诉您这个问题,您有一个相同国家的重复条目,无论如何都应该删除。如果可能的话,清理一下表格,重新开始。@HQ5,好吧,你真的尝试过用
添加主键(国家,动物)而不是
添加主键(国家/地区,x_id)?为什么
动物
x_id的位置
"animal"    "size"     "x_id"
"crocodile" "small"     "1"
"elephant"  "medium"    "2"
"giraffe"   "medium"    "3"
"giraffe"   "large"     "4"
"crocodile" "small"     "1"
"elephant"  "medium"    "2"
"giraffe"   "large"     "4"
ALTER TABLE `yourtable` ADD INDEX `as_idx` (`animal`,`size`);
ALTER TABLE `yourtable` ADD INDEX `id_idx` (`x_id`);
UPDATE myTable m
    JOIN (
        SELECT animal, size, @newid := @newid + 1 AS x_id
        FROM myTable a
            CROSS JOIN (SELECT @newid := 0) b
        WHERE x_id = -1
        GROUP BY animal, size
    ) t ON m.animal = t.animal AND m.size = t.size
SET m.x_id = t.x_id
;
CREATE TABLE `myTable` (
    `country` int(10) unsigned NOT NULL DEFAULT '1', -- country
    `animal` int(4) NOT NULL,
    `size` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
    `lang_id` tinyint(4) NOT NULL DEFAULT '1',
    `x_id` int(10) NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (country,x_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


INSERT INTO `myTable` (`country`, `animal`, `size`) VALUES 
    (777, 1001, 'small'),
    (777, 2002, 'medium'),
    (777, 7007, 'medium'),
    (777, 7007, 'large'),
    (42, 1001, 'small'),
    (42, 2002, 'medium'),
    (42, 7007, 'large')
| country | animal | size   |lang_id | x_id  | 
|---------+--------+--------+--------+-------|
|  777    | 1001   | small  |   1    |   1   |
|  777    | 2002   | medium |   1    |   2   |
|  777    | 7007   | medium |   1    |   3   |
|  777    | 7007   | large  |   1    |   4   |
|  42     | 1001   | small  |   1    |   1   |
|  42     | 2002   | medium |   1    |   2   |
|  42     | 7007   | large  |   1    |   4   |