将数据库列从 UNSIGNED 更改为 BINARY 而无需转换为字符串
Change a Database Column from UNSIGNED to BINARY without converting to string
我有一个 table 在 UNSIGNED INTEGER
列中包含 IPv4 地址。我现在将其更改为支持 IPv6 地址,由 INET6_ATON()
返回,需要 VARBINARY(16)
列类型。
https://mariadb.com/kb/en/mariadb/inet6_aton/
如何更改现有列以保留其内容?
ALTER TABLE hitcounts CHANGE ip ip BINARY(16);
上面的命令似乎将无符号整数值转换为等效的字符串,这不是我想要的。
示范[=27=]
CREATE TEMPORARY TABLE hitcounts (ip INTEGER UNSIGNED);
INSERT INTO hitcounts VALUES (INET_ATON('78.156.181.3')),(INET_ATON('64.255.180.66')),(INET_ATON('31.126.241.81'));
SELECT * FROM hitcounts;
+------------+
| ip |
+------------+
| 1318892803 |
| 1090499650 |
| 528413009 |
+------------+
3 rows in set (0.00 sec)
ALTER TABLE hitcounts MODIFY COLUMN ip VARBINARY(16);
SELECT * FROM hitcounts;
+------------+
| ip |
+------------+
| 1318892803 |
| 1090499650 |
| 528413009 |
+------------+
3 rows in set (0.00 sec)
虽然转换后的ip值看起来已经被保留了,但实际上它们已经被转换成ASCII字符串(注意第三行的左对齐与它是真实数字时使用的右对齐相比) .尝试获取 IP 地址将失败:
SELECT INET6_NTOA(ip) FROM hitcounts;
+----------------+
| INET6_NTOA(ip) |
+----------------+
| NULL |
| NULL |
| NULL |
+----------------+
3 rows in set (0.01 sec)
简单的解决方案是按照所述更改列,然后更新列以转换为由 INET6_ATON() 生成的二进制字符串:
UPDATE hitcounts SET ip = INET6_ATON(INET_NTOA(ip));
由于 INET6 函数处理 IPv4 的 4 字节二进制和 IPv6 的 16 字节二进制,我认为这更接近 'correct':
ALTER TABLE hitcounts MODIFY COLUMN ip VARBINARY(16) NOT NULL;
VAR
是因为INET6_ATON('1.2.3.4')
生成了一个BINARY(4)
字符串。
我尚未验证仅将 UNSIGNED
转换为 VARBINARY(16)
是否会正确保留 IPv4 值。
MySQL 需要 5.6.3 或 MariaDB 10.0.12。 (在早些时候,我认为 MariaDB 使用了不同的拼写:INET6_NTOP()
和 INET6_PTON()
)。
我有一个 table 在 UNSIGNED INTEGER
列中包含 IPv4 地址。我现在将其更改为支持 IPv6 地址,由 INET6_ATON()
返回,需要 VARBINARY(16)
列类型。
https://mariadb.com/kb/en/mariadb/inet6_aton/
如何更改现有列以保留其内容?
ALTER TABLE hitcounts CHANGE ip ip BINARY(16);
上面的命令似乎将无符号整数值转换为等效的字符串,这不是我想要的。
示范[=27=]
CREATE TEMPORARY TABLE hitcounts (ip INTEGER UNSIGNED);
INSERT INTO hitcounts VALUES (INET_ATON('78.156.181.3')),(INET_ATON('64.255.180.66')),(INET_ATON('31.126.241.81'));
SELECT * FROM hitcounts;
+------------+
| ip |
+------------+
| 1318892803 |
| 1090499650 |
| 528413009 |
+------------+
3 rows in set (0.00 sec)
ALTER TABLE hitcounts MODIFY COLUMN ip VARBINARY(16);
SELECT * FROM hitcounts;
+------------+
| ip |
+------------+
| 1318892803 |
| 1090499650 |
| 528413009 |
+------------+
3 rows in set (0.00 sec)
CREATE TEMPORARY TABLE hitcounts (ip INTEGER UNSIGNED);
INSERT INTO hitcounts VALUES (INET_ATON('78.156.181.3')),(INET_ATON('64.255.180.66')),(INET_ATON('31.126.241.81'));
SELECT * FROM hitcounts;
+------------+
| ip |
+------------+
| 1318892803 |
| 1090499650 |
| 528413009 |
+------------+
3 rows in set (0.00 sec)
ALTER TABLE hitcounts MODIFY COLUMN ip VARBINARY(16);
SELECT * FROM hitcounts;
+------------+
| ip |
+------------+
| 1318892803 |
| 1090499650 |
| 528413009 |
+------------+
3 rows in set (0.00 sec)
虽然转换后的ip值看起来已经被保留了,但实际上它们已经被转换成ASCII字符串(注意第三行的左对齐与它是真实数字时使用的右对齐相比) .尝试获取 IP 地址将失败:
SELECT INET6_NTOA(ip) FROM hitcounts;
+----------------+
| INET6_NTOA(ip) |
+----------------+
| NULL |
| NULL |
| NULL |
+----------------+
3 rows in set (0.01 sec)
简单的解决方案是按照所述更改列,然后更新列以转换为由 INET6_ATON() 生成的二进制字符串:
UPDATE hitcounts SET ip = INET6_ATON(INET_NTOA(ip));
由于 INET6 函数处理 IPv4 的 4 字节二进制和 IPv6 的 16 字节二进制,我认为这更接近 'correct':
ALTER TABLE hitcounts MODIFY COLUMN ip VARBINARY(16) NOT NULL;
VAR
是因为INET6_ATON('1.2.3.4')
生成了一个BINARY(4)
字符串。
我尚未验证仅将 UNSIGNED
转换为 VARBINARY(16)
是否会正确保留 IPv4 值。
MySQL 需要 5.6.3 或 MariaDB 10.0.12。 (在早些时候,我认为 MariaDB 使用了不同的拼写:INET6_NTOP()
和 INET6_PTON()
)。