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 |