isn 模块为以下国际产品编号标准提供数据类型:EAN13、UPC、ISBN(图书)、ISMN(音乐)与 ISSN(连续出版物)。输入时会根据一个硬编码的前缀列表进行校验;该前缀列表也用于在输出时为编号添加连字符。由于新前缀会不时被分配,该前缀列表可能过时。本模块的未来版本有望从一个或多个表中获取前缀列表,以便用户可以按需轻松更新;但目前,该列表只能通过修改源码并重新编译来更新。另一种可能的做法是,本模块的未来版本直接移除前缀校验与连字符支持。
该模块被视为“可信”模块,也就是说,拥有当前数据库 CREATE 权限的非超级用户也可以安装它。
Table F.10 展示了 isn 模块提供的数据类型。
Table F.10. isn 数据类型
| 数据类型 | 描述 |
|---|---|
EAN13 | 欧洲商品编号,始终以 EAN13 显示格式显示 |
ISBN13 | 以新的 EAN13 显示格式显示的国际标准书号 |
ISMN13 | 以新的 EAN13 显示格式显示的国际标准音乐编号 |
ISSN13 | 以新的 EAN13 显示格式显示的国际标准连续出版物编号 |
ISBN | 以旧的短显示格式显示的国际标准书号 |
ISMN | 以旧的短显示格式显示的国际标准音乐编号 |
ISSN | 以旧的短显示格式显示的国际标准连续出版物编号 |
UPC | 通用产品代码 |
一些说明:
ISBN13、ISMN13、ISSN13 编号都是 EAN13 编号。
EAN13 编号并非总是 ISBN13、ISMN13 或 ISSN13(有些是)。
某些 ISBN13 编号可以显示为 ISBN。
某些 ISMN13 编号可以显示为 ISMN。
某些 ISSN13 编号可以显示为 ISSN。
UPC 编号是 EAN13 编号的子集(它们基本上是去掉第一个 0 数字的 EAN13)。
所有 UPC、ISBN、ISMN 与 ISSN 编号都可以表示为 EAN13 编号。
在内部,所有这些类型使用相同的表示(一个 64 位整数),并且都可以互换。提供多种类型是为了控制显示格式,并对应当表示某一特定类型编号的输入执行更严格的校验。
ISBN、ISMN 与 ISSN 类型在可能时显示编号的短版本(ISxN 10),对于不适合短版本的编号则显示 ISxN 13 格式。EAN13、ISBN13、ISMN13 与 ISSN13 类型始终显示 ISxN 的长版本(EAN13)。
isn 模块提供以下成对的类型转换:
ISBN13 <=> EAN13
ISMN13 <=> EAN13
ISSN13 <=> EAN13
ISBN <=> EAN13
ISMN <=> EAN13
ISSN <=> EAN13
UPC <=> EAN13
ISBN <=> ISBN13
ISMN <=> ISMN13
ISSN <=> ISSN13
从 EAN13 转换为其他类型时,运行时会检查值是否在目标类型的域内,否则抛出错误。其他转换只是简单的重新标记,总是可以成功。
isn 模块为所有这些数据类型提供标准比较操作符,以及 B 树与哈希索引支持。此外还有几个专用函数,见 Table F.11。在该表中,isn 表示模块的任意一种数据类型。
Table F.11. isn 函数
isn.weak (boolean)
#
isn.weak 启用弱输入模式,允许接受校验位错误的 ISN 输入值。默认为 false,即拒绝无效的校验位。
什么情况下你会想使用弱模式?比如,你拥有海量的 ISBN 编号,由于某些奇怪的原因,其中一些的校验位是错的(也许编号是从打印列表扫描的,OCR 识别错了;也许是手工录入的……谁知道呢)。总之,关键是:你可能想清理这些乱象,但仍希望所有编号都能进入数据库,也许还要用外部工具定位数据库中的无效编号,以便更容易地核实与校验信息;例如,你可能想选出表中所有无效的编号。
使用弱模式向表中插入无效编号时,该编号会以更正后的校验位插入,但显示时会在末尾带一个感叹号(!),例如 0-11-000322-5!。可以用 is_valid 函数检查这个无效标记,并用 make_valid 函数清除它。
即使不在弱模式下,你也可以通过在编号末尾附加 ! 字符来强制插入被标记为无效的编号。
另一个特殊功能是:输入时你可以在校验位的位置写 ?,正确的校验位会被自动插入。
--Using the types directly:
SELECT isbn('978-0-393-04002-9');
SELECT isbn13('0901690546');
SELECT issn('1436-4522');
--Casting types:
-- note that you can only cast from ean13 to another type when the
-- number would be valid in the realm of the target type;
-- thus, the following will NOT work: select isbn(ean13('0220356483481'));
-- but these will:
SELECT upc(ean13('0220356483481'));
SELECT ean13(upc('220356483481'));
--Create a table with a single column to hold ISBN numbers:
CREATE TABLE test (id isbn);
INSERT INTO test VALUES('9780393040029');
--Automatically calculate check digits (observe the '?'):
INSERT INTO test VALUES('220500896?');
INSERT INTO test VALUES('978055215372?');
SELECT issn('3251231?');
SELECT ismn('979047213542?');
--Using the weak mode:
SET isn.weak TO true;
INSERT INTO test VALUES('978-0-11-000533-4');
INSERT INTO test VALUES('9780141219307');
INSERT INTO test VALUES('2-205-00876-X');
SET isn.weak TO false;
SELECT id FROM test WHERE NOT is_valid(id);
UPDATE test SET id = make_valid(id) WHERE id = '2-205-00876-X!';
SELECT * FROM test;
SELECT isbn13(id) FROM test;