| 免费下载:IBM® Informix® 11.7 试用版(包括 Ultimate Edition、Developer Edition 和 Innovator-C Edition) |
|---|
| 下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。 |
IBM Informix 数据库历来是区分大小写的。这意味着,如果您在 CHAR 列的不同行输入大写 “IBM” 和小写 “ibm”,然后查询小写的 “ibm”,那么只会返回小写的值。如果您希望以不区分大小写的方式搜索 CHAR 数据,那么有以下几种方法:您可以创建一个功能索引、使用一个基本的文本搜索索引,或者使用内置的 UPPER 或 LOWER 函数;但是这些方法都需要更改应用程序,或者可能导致性能下降。
有了 Informix 11.70.xc2 之后,Informix 首次可以支持不区分大小写 (CI) 的数据库功能了。您为何想要执行 CI 搜索?假如说您有一个列记录了您客户所在公司的名称。如果您有代表同一公司的多个值,一个大写和一个小写,比如 “IBM” 和 “ibm”,两者都表示您希望在任何这样的查询中返回的准确数据。Informix 11.70.xc2 中提供了对 CI 搜索的支持,现在您就可以进行不区分大小写的查询了。
Informix 通过两个数据类型提供不区分大小写功能:NCHAR 和 NVARCHAR,它们可以与 Informix CI 数据库一同使用。该数据库内的所有其他类型仍然是区分大小写的,因此如果您希望使用 CI 功能,就必须使用这些数据类型。
如果您想支持 CI 功能,则需要在创建数据库时建立它。以下命令展示了如何创建 CI 数据库:
CREATE DATABASE mydb WITH LOG NLSCASE INSENSITIVE; |
通过该语句,您创建了一个名为 ‘mydb’ 的数据库,允许该数据库内创建的所有 NCHAR 和 NVARCHAR 列具有 CI 功能。
有时在您的服务器上会有已经创建好的数据库。在输入或查询数据之前,弄清该数据库是否支持 CI 会很有用。sysmaster:sysdatabases 表中有一列是用来提供答案的。在将 is_case_insens 设置为 1 时,表明数据库支持 CI。清单 1 显示了如何查询该系统表来确定数据库是否支持 CI:
清单 1. 如何弄清您的数据库是否支持 CI
SELECT is_case_insens FROM sysmaster:sysdatabases WHERE name LIKE 'mydb';
is_case_insens
1
1 row(s) retrieved.
|
我们在 CI 数据库 ‘mydb’ 中创建一个基本模式以及商店数据库的一个变体,以展示如何使用 CI 功能。我们将同时使用 NCHAR 和 NVARCHAR 数据类型,因为这些是 CI 唯一支持的类型。
清单 2. 使用 NCHAR 和 NVARCHAR 数据类型创建一个基本的商店模式
CREATE TABLE customer
(
customer_num NCHAR(4),
fname NCHAR(15),
lname NCHAR(15),
company NCHAR(20),
address1 NVARCHAR(20),
address2 NVARCHAR(20),
city NCHAR(15),
state NCHAR(2),
zipcode NCHAR(5),
phone NCHAR(18),
PRIMARY KEY (customer_num)
);
INSERT INTO customer VALUES('101a','LUDWIG','pauli','All SportS Supplies','213 erstWild
Court',null,
'SunnyVale','CA','94086','408-789-8075');
INSERT INTO customer VALUES('102b','Carole','Sadler','Sports Spot','785 GearY St',null,
'San Francisco'
,'CA','94117','415-822-1289');
INSERT INTO customer VALUES('103c','Philip','Currie','Phil Sports','654 Poplar,P. o. boX
3498',null,'Palo AlTo'
,'Ca','94303','415-328-4543');
INSERT INTO customer VALUES('104d','AnthonY','Higgins','PlaY ball!','east Shopping Cntr.
','422 baY Road',
'Redwood CitY','CA','94026','415-368-1100');
INSERT INTO customer VALUES('105e','RaYmond','Vector','Los Altos Sports','1899 La Loma
Drive',null,
'Los Altos','ca','94022','415-776-3249');
CREATE TABLE cust_calls
(
customer_num NCHAR(4),
call_dtime datetime year to minute,
user_id NCHAR(32) default user,
call_code NCHAR(1),
call_descr CHAR(240),
res_dtime datetime year to minute,
res_descr NVARCHAR(240),
PRIMARY KEY(customer_num, call_dtime),
FOREIGN KEY (customer_num) REFERENCES customer (customer_num)
);
INSERT INTO cust_calls VALUES('101A','2008-06-12 8:20','maryj','D','order was received
' ,'2008-06-12 8:25','
Authorized credit for two cans to customer');
INSERT INTO cust_calls VALUES('102B','2008-07-07 10:24','richc','L','order placed
one month ago (6/7) not
received.','2008-07-07 10:30','Checked with shipping (ed Smith)');
INSERT INTO cust_calls VALUES('103C','2008-07-01 15:00','richc','B','Richc' ,
'2008-07-02 8:21','Is sending
new bill to customer');
INSERT INTO cust_calls VALUES('104D','2008-07-10 14:05','maryj','o','Customer
likes our merchandise.',
null,'Sent note to marketing');
INSERT INTO cust_calls VALUES('105E','2008-07-31 14:30','maryj','I','Received
Hero watches',null,'Sent
memo to shipping');
CREATE TABLE orders
(
order_num serial(1001),
order_date date,
customer_num NCHAR(4),
ship_instruct NVARCHAR(40),
backlog NCHAR(1),
po_num NCHAR(10),
ship_date date,
ship_weight decimal(8,2),
ship_CHARge money(6),
paid_date date,
PRIMARY KEY (order_num),
FOREIGN KEY (customer_num) REFERENCES customer (customer_num)
)
FRAGMENT BY EXPRESSION
partition part0 (backlog = 'y') in dbspace1,
partition part1 (backlog = 'n') in dbspace2;
INSERT INTO orders VALUES(1001,'05/20/2008','104D','express','y','B77836','06/01/2008',
'20.4','10.0',
'07/22/2008');
INSERT INTO orders VALUES(1002,'05/21/2008','101A','Po on box; deliver to bAck door
onlY','n','9270',
'05/26/2008','50.6','15.3','06/03/2008');
INSERT INTO orders VALUES(1003,'05/22/2008','104D','express','n','B77890','05/23/2008',
'35.6','10.8',
'06/14/2008');
INSERT INTO orders VALUES(1004,'05/22/2008','104d','ring bell twice','Y','8006',
'05/30/2008','95.8','19.2',
'04/14/2008');
INSERT INTO orders VALUES(1005,'05/24/2008','101a','cAll before deliverY','n','2865',
'06/09/2008','80.8',
'16.2','06/21/2008');
|
清单 3 显示了用于查找居住在 California 的所有客户的一个基本查询。
清单 3. 查询居住在 California 的客户
SELECT fname, lname, state FROM customer WHERE state LIKE 'CA' fname lname state LUDWIG pauli CA Carole Sadler CA Philip Currie Ca AnthonY Higgins CA RaYmond Vector ca |
您可以看到,尽管我们搜索 state 中的 ‘CA’,但查询返回了 state 的所有形式,包括大写、大小写混合和小写(‘CA’、‘Ca’ 和 ‘ca’)。区分大小写的数据库只会返回与本例的查询中使用的大小写匹配的三行。
数据库的不区分大小写功能会在 NCHAR/NVARCHAR 类型的列上定义的主键和外键上生效。也就是说,如果任何字符数据的变种形式存在于主键列中,那么大小写的任何其他变体形式将不受支持。我们来看一个示例,如果我们尝试将一个新行插入到 customer_num 为 ‘101A’ 而非 ‘101a’ 的 customer 表中。在以前区分大小写的数据库中,这样做会很有效,但在 CI 数据库中则不然。
清单 4. 违反主键约束
INSERT into customer VALUES('101A','Jones','P','Some Shop','123 Lost Lane',null,
'NullyDale','CA',
'94086','408-789-8075');
268: Unique constraint (informix.u112_25) violated.
100: ISAM error: duplicate value for a record with unique key.
|
类似地,如果您希望在 orders 表中插入 customer_num 为 ‘101A’ 的行,尽管对应的外键值是 ‘101a’,这样做仍然是可行的:
清单 5. 外键约束
INSERT into orders VALUES(1006,'03/14/2007','101A','Call first','n','2765','05/06/2008', '70.8','15.2', '05/20/2008'); 268: Unique constraint (informix.u112_25) violated. 100: ISAM error: duplicate value for a record with unique key. |
检查约束也对 CI 数据库有影响。这里我们的 customer 表中包含有检查约束的 state 列,其中仅允许插入或更新 state 为 ‘ca’ 或 ‘nv’ 的记录。区分大小写的数据库会检查完全匹配 state 字段的记录,但是 CI 数据库会忽略字母的大小写不同。CI 数据库将拥有相同字母序列的字符串中的大小写差异看作是重复,且支持使用以下这些值:‘CA’、‘Ca’、‘cA’ 和 ‘ca’。
清单 6. 检查约束
CREATE TABLE customer_check (customer_num NCHAR(4), fname NCHAR(15), lname NCHAR(15),
company NCHAR(20), address1 NVARCHAR(20), address2 NVARCHAR(20), city NCHAR(15),
state
NCHAR(2), check (state in ('ca', 'nv')), zipcode NCHAR(5), phone NCHAR(18),
primary key (customer_num));
Table created.
INSERT INTO customer_check VALUES('101A','Jones','P','Some Shop','123 Lost Lane',null,
'NullyDale','CA',
'94086','408-789-8075');
1 Row Inserted
|
本例展示了如何使用 ‘state’ 列上的检查约束创建 customer 表,而且尽管我们在插入内容时输入了 ‘CA’,但该值仍然有效,因为 ‘ca’ 和 ‘nv’ 值对于该检查是有效的。
还有一点值得注意的是,在 CI 数据库中选择 NCHAR/NVARCHAR 类型的 distinct 值时,返回的行现在会有所不同,因为大小写被忽略。假设您希望找到从您公司下单的所有客户。
清单 7. Distinct 选择
SELECT DISTINCT(customer_num) FROM orders; customer_num 101A 104D |
从结果中您可以看到,使用 CI 功能之后,‘101a’ 和 ‘101A’ 不是不同的值。
如果您在 CI 数据库中对 NCHAR 或 NVARCHAR 列进行聚合或分组,字母大小写会被忽略,因为如果您在计算与 customer_num ‘104d’ 相关的所有订单,那么返回的行会不同。
清单 8. 聚合选择
SELECT COUNT(customer_num) FROM orders WHERE customer_num = '104d';
(count)
3
|
在 CI 数据库中使用 GROUP BY 子句时,‘104d’ 和 ‘104D’ 会放在同一个组中,且根据处理行的顺序,输出要么为 ‘104d’,要么为 ‘104D’。
清单 9. GROUP BY 选择
SELECT customer_num FROM orders GROUP BY customer_num; customer_num 101A 104D |
返回的这些值也可以是 ‘101a’ 或 ‘104d’。对值进行排序时不考虑字母大小写。字母 ‘a’ 和 ‘A’ 被视为等同,且在排序过程中不会优先考虑任何一个。
在 CI 数据库中,NCHAR 和 NVARCHAR 数据上的排序操作忽略字母大小写差异,因此数据库服务器将具有相同字母序列的字符串中的大小写差异看作是重复的。排序列表根据检索顺序为这些不区分大小写的重复值进行排序。
清单 10. Order By 选择
SELECT order_num , customer_num FROM orders ORDER BY customer_num;
order_num customer_num
1002 101A
1005 101a
1006 101A
1004 104d
1001 104D
1003 104D
6 row(s) retrieved.
|
在本例中,很明显 ‘101A’ 和 ‘101a’ 值被看作是重复值。类似地,‘101D’ 和 ‘101d’ 值以及这些重复值的顺序根据检索顺序进行管理。
如果您想碎片化数据,可以使用 NCHAR 和 NVARCHAR 类型。以下是一个创建 orders 表并基于 backlog 列进行碎片化的示例。在 CI 数据库中的 Fragment by 表达式中使用 NCHAR 和 NVARCHAR 列时,数据库服务器将所有不区分大小写的值存储在相同的碎片中,不过每个原始数据值仍然相同。服务器对 NCHAR 和 NVARCHAR 列的碎片消除以及 CI 数据库中的表达式应用类似的方法。CI 列上的索引所用的碎片键类似于表上的碎片键。“Fragment by expression” 和 “fragment by list” 都会为 NCHAR 和 NVARCHAR 列使用不区分大小写的方法。
清单 11. 在碎片化表达式中使用 NCHAR
SELECT order_num, backlog FROM orders;
order_num backlog
1004 Y
1001 n
1002 n
1003 n
1005 n
1006 n
6 row(s) retrieved.
|
在本例中 order_num 1001 和 1004 记录存储在 dbspace1 中的 part0 分区中,因为在不区分大小写的数据库中 backlog 值 ‘Y’ 和 ‘y’ 的碎片化表达式是相匹配的。
清单 12. Set Explain 示例
SET EXPLAIN ON;
Explain set.
SELECT order_num, backlog FROM orders WHERE backlog = 'y';
order_num backlog
1001 y
1004 Y
2 row(s) retrieved.
SELECT order_num, backlog FROM orders WHERE backlog = 'y'
Estimated Cost: 2
Estimated # of Rows Returned: 1
1) informix.orders: SEQUENTIAL SCAN (Serial, fragments: 0)
Fragments Scanned: (0) part0 in dbspace1
Filters: informix.orders.backlog = 'y'
|
在 清单 12 中的 explain 输出中,服务器在 NCHAR 列 backlog 上使用了碎片清除。
您可以在 NCHAR 和 NVARCHAR 列上创建索引,并充分利用 CI 功能的优势。在本例中,我们在 NCHAR 列 ‘phone’ 上创建了一个索引。
清单 13. CI 数据库中的索引创建
CREATE INDEX i ON customer(phone); index Created |
如果我们创建一个唯一的索引,重复值会返回一个错误,如清单 14 所示。
清单 14. 在 CI 数据库中创建唯一索引
CREATE UNIQUE INDEX z ON customer(lname);
Index created.
INSERT INTO customer VALUES('105f','Boris','VECTOR','John Sports','18 Bull
Drive',null,'Santa fe','nm','94011','315-776-3249');
239: Could not insert new row - duplicate value in a UNIQUE INDEX column
100: ISAM error: duplicate value for a record with unique key.
|
当我们尝试将 ‘VECTOR’ 插入 lname(已经有一个包含 ‘Vector’ 值的行)时, 唯一索引给出一个错误。
我们看一下如何使用 CI 数据联接两个表。我们会以 customer_num 作为联接列联接 customer 和 cust_calls 表。
清单 15. customer 和 cust_calls 的联接
SELECT c.customer_num, c.lname, c.company,
c.phone, u.call_dtime, u.call_descr
FROM customer c, cust_calls u
WHERE c.customer_num = u.customer_num
ORDER BY customer_num;
customer_num 101a
lname pauli
company All SportS Supplies
phone 408-789-8075
call_dtime 2008-06-12 08:20
call_descr order was received
customer_num 102b
lname Sadler
company Sports Spot
phone 415-822-1289
call_dtime 2008-07-07 10:24
call_descr order placed one month ago (6/7) not received.
customer_num 103c
lname Currie
company Phil Sports
phone 415-328-4543
call_dtime 2008-07-01 15:00
call_descr Bill does not rflect credit
customer_num 104d
lname Higgins
company PlaY ball!
phone 415-368-1100
call_dtime 2008-07-10 14:05
call_descr Customer likes our merchandise.
customer_num 105e
lname Vector
company Los Altos Sports
phone 415-776-3249
call_dtime 2008-07-31 14:30
call_descr Received Hero watches
|
尽管 customer 和 in cust_calls 中的 custom_num 列数据大小写不同,但我们的联接仍然成功完成了。
现在我们尝试对 customer、orders 和 cust_calls 表执行外联接。
清单 16. customer、cust_calls 和 orders 的外联接
SELECT c.customer_num, lname, o.order_num,
order_date, call_dtime
FROM customer c, outer orders o, outer cust_calls x
WHERE c.customer_num = o.customer_num
and c.customer_num = x.customer_num
ORDER BY c.customer_num;
customer_num lname order_num order_date call_dtime
101a pauli 1002 05/21/2008 2008-06-12 08:20
101a pauli 1005 05/24/2008 2008-06-12 08:20
101a pauli 1006 03/14/2007 2008-06-12 08:20
102b Sadler 2008-07-07 10:24
103c Currie 2008-07-01 15:00
104d Higgins 1001 05/20/2008 2008-07-10 14:05
104d Higgins 1003 05/22/2008 2008-07-10 14:05
104d Higgins 1004 05/22/2008 2008-07-10 14:05
105e Vector 2008-07-31 14:30
|
当一个查询比较一个字符值与另一个数据类型时,服务器至少会隐式转换两个值中的一个。结果的数据类型如下表所示:
| TYPE | NCHAR | NVARCHAR | CHAR | VARCHAR | LVARCHAR | 其他 |
|---|---|---|---|---|---|---|
| NCHAR | NCHAR | NVARCHAR 或 NCHAR | NCHAR | NVARCHAR 或 NCHAR | NVARCHAR 或 NCHAR | NVARCHAR 或 NCHAR |
| NVARCHAR | NVARCHAR 或 NCHAR | NVARCHAR 或 NCHAR | NVARCHAR 或 NCHAR | NVARCHAR 或 NCHAR | NVARCHAR 或 NCHAR | NVARCHAR 或 NCHAR |
| CHAR | NCHAR | NVARCHAR 或 NCHAR | CHAR | VARCHAR 或 LVARCHAR | LVARCHAR | VARCHAR 或 LVARCHAR |
| VARCHAR | NVARCHAR 或 NCHAR | NVARCHAR 或 NCHAR | VARCHAR 或 LVARCHAR | VARCHAR 或 LVARCHAR | LVARCHAR | VARCHAR 或 LVARCHAR |
| LVARCHAR | NVARCHAR 或 NCHAR | NVARCHAR 或 NCHAR | LVARCHAR | LVARCHAR | LVARCHAR | LVARCHAR |
| 其他 | NVARCHAR 或 NCHAR | NVARCHAR 或 NCHAR | VARCHAR 或 LVARCHAR | VARCHAR 或 LVARCHAR | LVARCHAR | VARCHAR 或 LVARCHAR |
清单 17. 比较 CHAR 与 NCHAR 值
SELECT user_id, call_descr FROM cust_calls WHERE user_id = call_descr; user_id richc call_descr Richc 1 row(s) retrieved. |
在本例中,您可以看到尽管 call_descr 列是非 CI 的 CHAR 数据类型,比较仍然是可行的。服务器将 CHAR 转换为 NCHAR,同时处理查询谓词。
在收集一个表的分布统计数据时,数据库的不区分大小写功能会影响 NCHAR 和 NVARCHAR 列,其中服务器会将所有大小写不同的值判断为一个 distinct 值。Informix 服务器会使用这些统计数据生成尽可能最好的用于处理查询的计划。以下示例显示了统计数据的外观。在本例中,在运行 ‘UPDATE STATISTICS HIGH’ 之后,有关 ‘orders’ 表的 ‘cust_num’ 列的分布信息如下所示。
清单 18. 导入一个非 CI 数据库
Distribution for informix.orders.customer_num
Constructed on 2011-04-29 16:29:15.00000
High Mode, 0.500000 Resolution
--- DISTRIBUTION ---
( 101A )
--- OVERFLOW ---
1: ( 2, 101A )
2: ( 3, 104d )
|
这里最重要的因素在于,‘101A’ 和 ‘101a’ 值都存储在一个 bin 中,而在区分大小写的数据库中,它们会存储在不同的 bin 中。
对于不同数据库间的任何查询,不管是在同一服务器内还是在服务器实例之间,如果这些数据库没有相同的大小写敏感性,就会引发错误。如果同一服务器实例或不同服务器的参与数据库从大小写敏感性来讲不是同一类型的,那么服务器会报告一个错误。这里唯一的例外是系统数据库。
要从现有的非 CI 数据库上迁移数据,用户需要使用 Informix 工具 dbimport 和 dbexport。在使用这些工具之前,用户可以将非 CI 数据库中的 CHAR 和 VARCHAR 类型(分别)改为 NCHAR 和 NVARCHAR,以便使用 CI 功能。迁移数据的用户需要确保迁移到 CI 数据库上的数据与 CI 约定一致。例如,CI 数据库中 NCHAR 上的唯一索引会对 ‘IBM’ 和 ‘ibm’ 这样的数据抛出异常。在将数据从非 CI 数据库迁移到 CI 数据库时可能会违反引用约束。比如说包含 ‘IBM’ 和 ‘ibm’ 行的非 CI 数据库中的 CHAR 列上有一个外键。在导出该数据并将其导入含有 NCHAR 列的 CI 数据库时,您会收到一个约束违反错误消息。
清单 19. 导出一个非 CI 数据库
Dbexport -c mydb dbexport completed |
要导入数据并将其重新创建为一个 CI 数据库,有一个新参数可供 dbimport 使用。命令行选项 ‘-ci’ 会告诉 dbimport 将数据库创建为 CI。
清单 20. 清单 21. 将数据导入 CI 数据库
# First drop existing mydb database DROP DATABASE mydb; Database dropped. # Import old mydb database Dbimport -ci mydb -i ./ dbimport completed |
现在您将有一个新创建的 CI 数据库。
Informix CI 数据库提供了更多的选项来使用和搜索您的数据。在存储和检索数据时,CI 会是一个很重要的问题。很多时候当您从外部源将数据导入数据库时,不会总是保留大小写,且用户错误常常也会导致大小写混合。在检索和搜索数据时,新的 CI 功能使 Informix DBA 的生活更加轻松,而且在正确实现 CI 时,大小写不再是一个要考虑的因素。
学习
- “使用 XML-RPC 为 C++ 应用程序启用 Web 服务”(developerWorks,2006 年 6 月)是将 C++ 公开为服务的一个分步指南。
- 在 developerWorks 中国网站 XML 技术专区,获取提高您的 XML 技能所需的资源,包括 DTD、模式和 XSLT。
- 随时关注 developerWorks 技术活动 和 网络广播,了解各种 IBM 产品和 IT 行业话题。
- 观看 developerWorks 演示中心,包括面向初学者的产品安装和设置演示,以及为经验丰富的开发人员提供的高级功能。
- 在 developerWorks 中国网站 Information Management 专区 了解关于信息管理的更多信息,获取技术文档、how-to 文章、培训、下载、产品信息以及其他资源。
-
在 Twitter 上关注 developerWorks。
获得产品和技术
- 使用可以直接从 developerWorks 下载的 IBM 产品评估试用版软件 构建您的下一个开发项目。
讨论
- 参与论坛讨论。
- 参与 developerWorks 博客 并加入 developerWorks 中文社区,developerWorks 社区是一个面向全球 IT 专业人员,可以提供博客、书签、wiki、群组、联系、共享和协作等社区功能的专业社交网络社区。