【问题标题】:Converting CHAR Primary Key to INT in MySQL/MariaDB在 MySQL/MariaDB 中将 CHAR 主键转换为 INT
【发布时间】:2019-02-11 20:09:05
【问题描述】:

我有一个使用CHAR 作为客户主键的表。我正在尝试将此表加载到架构中,以便主键应该是INT

DROP TABLE IF EXISTS `customers`;
CREATE TABLE `customers` (
  `customer_id` char(5) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `customers` VALUES ('99944'),('99946'),('99976'),('A0014'),('A0049'),('A0124'),('C01AH'),('C01AQ'),('C01AW'),('C01AX'),('C01AY'),('C01AZ');

Fiddle

我尝试了对select cast(customer_id AS UNSIGNED) FROM customers; 的变体,但只为非整数行返回 0。如何将非 int 行转换为一致的 INT 结果?

理想的结果应该是这样的: 对于完全是整数的客户 ID,请不要理会它们。 对于包含任何字母的客户 ID,请将 ID 中的所有内容替换为唯一的数字标识符。

预期结果:

SELECT * FROM Customers;

`customer_id`
-------
99944
99946
99976
13871911
13871912
13871913
13872128
13872229
13872293
13872505
13872512
13872561

【问题讨论】:

  • 你想要什么结果?
  • 总是第一个字符不是数字吗?这些 ID 当前是否映射到另一个表,因此需要一致的转换?
  • 没有。第一个字符可以是数字或非数字。这些 ID 将映射到另一个表,因此需要保持一致性。对于数字 ID,请保持原样。对于非数字 ID,返回一致的结果 - 例如,用十进制 ASCII 代码替换非数字字符。
  • 我建议您将预期结果作为格式化数据。如何做到这一点你可以在这里阅读Why should I provide an MCVE for what seems to me to be a very simple SQL query?
  • 嘿@RaymondNijland...我开始喜欢你的解决方案了!

标签: mysql sql char type-conversion mariadb


【解决方案1】:

GMB 确实给了我另一个想法。
使用HEX()CONV(.., 16, 10) 将十六进制转换为十进制

查询

SELECT
   customers.customer_id
 , CASE 
    WHEN (customers.customer_id >> 0) > 0
    THEN customers.customer_id >> 0
    ELSE
     CONV(HEX(customers.customer_id), 16, 10)
    END
   AS customer_id_int
FROM 
 customers;

结果

| customer_id | customer_id_int |
| ----------- | --------------- |
| 99944       | 99944           |
| 99946       | 99946           |
| 99976       | 99976           |
| A0014       | 279981338932    |
| A0049       | 279981339705    |
| A0124       | 279981404724    |
| C01AH       | 288571343176    |
| C01AQ       | 288571343185    |
| C01AW       | 288571343191    |
| C01AX       | 288571343192    |
| C01AY       | 288571343193    |
| C01AZ       | 288571343194    |

附言 它可能会生成一个很大的 int,您需要使用 BIGINT 数据类型。
demo

更新

另一种生成较小整数 (UNSIGNED INT) 的方法使用“SQL 数字生成器”SUBSTRING()ORD()GROUP_CONCAT()

查询

    SELECT 
       customers.customer_id
     CASE 
       WHEN customers.customer_id >> 1 > 0
       THEN customers.customer_id 
       ELSE
         GROUP_CONCAT(
           CASE
             WHEN SUBSTRING(customers.customer_id, number_generator.number, 1) NOT BETWEEN 'A' AND 'Z'
             THEN SUBSTRING(customers.customer_id, number_generator.number, 1) >> 1
             ELSE ORD(SUBSTRING(customers.customer_id, number_generator.number, 1))
           END
           ORDER BY 
             number_generator.number ASC
           SEPARATOR ''
         )                            
     END                            
   ) AS customer_id_int                  
    FROM (
      SELECT 
       record_1.number
      FROM (
        SELECT 1 AS number UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5
      ) AS record_1   
    ) AS number_generator
    CROSS JOIN
     customers
    GROUP BY 
     customers.customer_id
    ORDER BY 
     customers.customer_id ASC

结果

| customer_id | customer_id_int |
| ----------- | --------------- |
| 99944       | 99944           |
| 99946       | 99946           |
| 99976       | 99976           |
| A0014       | 650002          |
| A0049       | 650024          |
| A0124       | 650012          |
| C01AH       | 67006572        |
| C01AQ       | 67006581        |
| C01AW       | 67006587        |
| C01AX       | 67006588        |
| C01AY       | 67006589        |
| C01AZ       | 67006590        |

demo

【讨论】:

  • 我知道你在做某事! +1,因为此解决方案满足要求,并且确实为不支持 REGEXP_REPLACE 的 MySQL / MariaDB 版本提供了替代方案。
  • @GMB 和 @3C41DC 看看我的其他 REGEXP_REPLACE 替换方法,我更新为我的答案适用于 MySQL / MariaDB .. 它与 GMB 的 REGEXP_REPLACE 查询相同方法。除此之外它生成一个更小的 int 适合 UNSIGNED INT 数据类型
【解决方案2】:

在 Maria DB >= 10.0.5 的情况下,这是一种以可预测的方式将字符串主键转换为整数主键的解决方案:

SELECT 
    customer_id old_id,
    CAST(
        REGEXP_REPLACE(customer_id, '([^0-9])', ORD('$1')) 
        AS UNSIGNED
    ) new_id
FROM customers;

REGEXP_REPLACE() 捕获非数字字符(字符串中的任何位置),ORD() 将它们中的每一个转换为其序数(数字)表示。

Demo on DB Fiddle

old_id | new_id :----- | --------: 99944 | 99944 9Z946 | 936946 A9CZ6 | 36936366 A0C14 | 3603614 0ABC0 | 3636360

【讨论】:

  • 没有。这可能会导致重复。客户“41410”和“AA0”都是“41410”。
  • @RickJames:是的,你是对的。我修改了答案,不再提及唯一性。
【解决方案3】:

使用 MySQL 8.0 REGEXP_REPLACE

select cast(REGEXP_REPLACE(customer_id,'[^0-9]','') AS UNSIGNED) FROM customers;

db<>fiddle demo

【讨论】:

  • 抱歉,我更新了要求。在 ID 上运行此命令 C01AH C01AQ C01AW C01AX C01AY C01AZ 都返回转换后的 ID 1。
猜你喜欢
  • 2012-08-07
  • 1970-01-01
  • 1970-01-01
  • 2014-02-07
  • 2013-08-10
  • 2018-02-10
  • 2010-09-19
相关资源
最近更新 更多