GBase 8s SQL 指南:教程———7修改数据
7.1修改数据库中的数据
下列语句修改数据:
当与更高级的SELECT语句相比时,虽然这些SQL语句相对简单,但由于它们更改数据 库的内容,因此请小心使用它们。
如果在查询期间系统硬件或软件岀现故障,请考虑会发生什么。即使对应用程序的影响是 严重的,也不会破坏数据库自身。然而,如果正在进行修改时系统发生故障,则数据库的 状态就不确定了。显然,处于不确定状态的数据库具有深远的影响。在数据库中删除、插 入或更新行之前,请询问自己下列问题:
•用户对数据库及其表的访问是否安全。即,是否将有限的数据库和表级别权限授予 特定用户?
•修改了的数据是否保持数据库现有的完整性?
•系统的状况是否使其对可能导致系统或硬件故障的外部事件具有相对较强的免疫 力?
如果对这些问题不能都回答“是”,也不用担心。对所有这些问题的解决方案都内建在GBase 8s数据库服务器内。在对修改数据的语句进行描述之后,这部分讨论这些解决方案。
DELETE从表中移除任何行或行的组合。在提交该事务之后,您不可恢复删除了的行。
(在中断了的修改之下讨论事务。现在,请将事务与语句看做是一回事。)
当删除一行时,您还必须小心地删除其值依赖于该删除了的行的其他表的任何行。如果数 据库强制执行引用约束,则您可使用CREATE TABLE或ALTER TABLE语句的ON DELETE CASCADE选项来允许从与另一表的关系中的一个表进行级联删除。要获取关于 引用约束和ON DELETE CASCADE选项的更多信息,请参阅引用完整性。
DELETE语句指定表并通常包含WHERE子句,该子句指定要从表中移除的一行或多行。 如果省略WHERE子句,则删除所有行。
重要:请不要执行下列语句。
DELETE FROM customer;
您可编写带有或不带FROM关键字的DELETE语句。
DELETE customer;
由于这些DELETE语句不包含WHERE子句,因此从customer表删除所有行。如果您尝 试使用DB-Access菜单选项来进行无条件的删除,则程序会警告您并要求确认。然而,从 程序之内执行无条件的DELETE可在不发出警告的情况下发生。
如果想要从名为from的表中删除行,则您必须首先设置DELIMIDENT环境变量,或使用 其所有者的名称来限定该表的名称:
DELETE legree.from;
要获取关于定界的标识符以及DELIMIDENT环境变量的更多信息,请参阅《GBase 8s SQL 指南:语法》中对“带引号的字符串”表达式以及“标识符”段的描述。
您可使用TRUNCATE语句来快速地从表中移除所有行,同时还移除所有对应的索引数 据。在提交该事务之后,您不可恢复删除了的行。您可对包含任何列类型(包括智能大对 象)的表上使用TRUNCATE语句。
使用TRUNCATE语句来移除行的速度比使用DELETE语句来移除它们快。在
TRUNCATE语句之后,不必立即运行UPDATE STATISTICS语句。成功地执行 TRUNCATE之后,GBase 8s自动地更新该表及其系统目录中的索引的统计信息和分布情 况,以展示在该表中或在它的dbspace分区中没有任何行。
要了解日志记录的描述,请参阅事务日志记录。
TRUNCATE是数据定义语言语句,如果在该表上定义任何触发器,则该语句不激活 DELETE触发器。要了解关于使用触发器的说明,请参阅创建和使用触发器。
如果TRUNCATE语句指定的表是typed表,则成功的TRUNCATE操作从那个表中以 及从该表层级结构内的所有子表中移除所有行和B-tree结构。TRUNCATE不等同于 DELETE语句的ONLY关键字,DELETE语句将操作限制在typed表层级结构内的单个 表。
GBase 8s始终对TRUNCATE操作进行日志记录,即使对非日志记录的表也是如此。在支 持事务日志记录的数据库中,在同一事务之内的TRUNCATE之后,仅SQL的COMMIT WORK或ROLLBACK WORK语句是有效的。要获取关于使用TRUNCATE语句对性能 的影响的信息,请参阅《GBase 8s性能指南》。要了解完整的语法,请参阅《GBase 8s SQL 指南:语法》。
DELETE语句中的 WHERE子句与SELECT语句中的 WHERE子句的形式相同。您可 使用它来准确地指定应删除哪一行或哪些行。您可删除带有特定客户编号的客户,如下例 所示:
DELETE FROM customer WHERE customer_num = 175;
在此示例中,由于customer_num列有唯一约束,因此您可确保只删除一行。
您还可选取基于非索引列的行,如下例所示:
DELETE FROM customer WHERE company = 'Druid Cyclery';
由于被测试的列没有唯一约束,因此此语句可能删除多行。(Druid Cyclery可能有两个商 店,两个商店的名称相同但客户编号不一样。)
要了解DELETE语句影响多少行,请从customer表中为Druid Cyclery选择符合条件的行 计数。
SELECT COUNT(*) FROM customer WHERE company = 'Druid Cyclery';
您还可选择这些行并显示它们,以确保它们是您想要删除的那些行。
然而,当数据库对于多个用户同时可用时,使用SELECT语句作为测试只是一种近似的方 法。在您执行SELECT语句与后续的DELETE语句之间的时间内,其他用户可能已修改 了该表并更改了结果。在此示例中,另一用户可能执行下列操作:
- 为名为Druid Cyclery的另一客户插入新行
- 在插入新行之前,删除一个或多个Druid Cyclery行
•更新Druid Cyclery行以具有新的公司名称,或更新某个其他客户以具有名称 Druid Cyclery o
在这短短的时间间隔内,虽然其他用户不太可能执行这些操作,但确实存在这种可能性。 相同的问题也影响UPDATE语句。在并发和锁定之下讨论解决此问题的方法,且在对多 用户环境编程中讨论得更详细。
您可能遇到的另一个问题是,在该语句完成之前出现硬件或软件故障。在此情况下,数据 库可能还没删除行,可能已删除了一些行,或已经删除了所有指定的行。数据库的状态未 知,这是我们不想看到的。要防止此情况,请使用事务日志记录,如中断了的修改讨论的 那样。
当某行包含定义在ROW类型上的列时,您可使用点符号表示法来指定仅删除那些包含特 定字段值的行。例如,下列语句仅从employee表中删除address列中的city字段的值为San Jose 的那些行:
DELETE FROM employee
WHERE address.city = 'San Jose';
在前面的语句中,address列可能是命名的ROW类型或未命名的ROW类型。您用来指 定ROW类型的字段值的语法是相同的。
当某行包含定义在集合类型上的列时,您可在集合中搜索特定的元素,并删除在其中找到 那个元素的一行或多行。例如,下列语句删除其中的direct_reports列包含带有元素Baker的 集合的那些行:
DELETE FROM manager
WHERE 'Baker' IN direct_reports;
当您删除超级表的各行时,删除操作的作用域是超级表及其子表。假设您创建超级 表person,在其下定义两个子表employee和sales_rep。下列对person表执行的DELETE语 句可从person、employee和sales_rep全部三个表中删除行:
DELETE FROM person
WHERE name ='Walker';
要限制为仅删除超级表的行,您必须使用DELETE语句中的ONLY关键字。例如,下列 语句仅删除person表的行:
DELETE FROM ONLY(person)
WHERE name ='Walker';
重要:当您从超级表中删除行时,请小心使用,因为对超级表的删除的作用域包括该超级表及 其所有子表。
DELECT语句中的 WHERE子句可与SELECT语句中的一样复杂。它可包含通过AND 和OR连接的多个条件,且它可能包含子查询。
假设您发现stock表的某些行包含不正确的制造商代码。您不想更新它们,而是想要删除它 们以便重新输入它们。您知道,与正确的那些行不一样,这些行在manufact表中没有相匹 配的行。由于这些不正确的行在manufact表中没有相匹配的行,因此您可以编写下例中所 示的DELETE语句:
DELETE FROM stock
WHERE 0 = (SELECT COUNT(*) FROM manufact
WHERE manufact.manu_code = stock.manu_code);
该子查询对匹配的manufact行数进行计数;对stock的正确的行计数为1,对不正确的行 计数为0。选取不正确的行来删除。
提示: 使用复杂的条件来开发DELETE语句的一种方法是,先开发精确地返回要删除的行的
SELECT语句。将它编写为SELECT *;当它返回所期望的行集时,将SELECT *更改为读 取DELETE,并再执行它一次。
DELETE语句的WHERE子句不可使用测试同一表的子查询。即,当您从stock进行删除 时,您不可在也从stock中选择的WHERE子句中使用子查询。
此规则的关键在于FROM子句。如果在DELETE语句的FROM子句中命名表,则该表 不可还出现在DELECT语句的子查询的FROM子句中。
不在WHERE子句中编写子查询,您可使用MERGE语句将来自源表和目标表的行连接 在一起,然后从目标删除与连接条件相匹配的那些行。(Delete MERGE中的源表还可为 一个集合派生的表,它的行是查询的结果,该查询连接其他的表和视图,但是在下列的示 例中,源是单个表。)
如在前面的示例中那样,假设您发现stock表的某些行包含不正确的制造商代码。您想要删 除它们以便重新输入它们,而不是更新它们。您可使用MERGE语句,指定stock作为目 标表,manufact作为源表,ON子句中的连接条件,并对于带有不正确的制造商代码 的stock行使用Delete子句,如下例所示:
MERGE INTO stock USING manufact
ON stock.manu_code != manufact.manu_code
WHEN MATCHED THEN DELETE;
在此示例中,会从stock表中删除那些满足ON子句中的连接条件的所有行。在此,对于 其中的manu_code列值不等于manufact中的任何manu_code值的stock的那些行,连接条 件中的不等谓词(stock.manu_code != manufact.manu_code)求值为真。
在USING子句中必须罗列正连接到目标表的源表。
MERGE语句还可更新目标表的行,或将数据从源表插入到目标表,根据该行是否满足ON 子句为连接目标表与源表而指定的条件。单个MERGE语句还可同时组合DELETE与
INSERT操作,或者可同时组合UPDATE与INSERT操作而不删除任何行。MERGE语 句不更改源表。要获取关于Delete合并、Insert合并和Update合并的语法与限制的更多 信息,请参阅《GBase 8s SQL指南:语法》中MERGE语句的描述。
INSERT将新的一行或多行添加到表。该语句有两个基本功能。它可使用您提供的列值创 建单个的新行,或可使用从其他表选择的数据创建一组新的行。
在它的最简单形式中,INSERT语句从一列值的列表创建一个新行,并将其放置在表中。 下列语句展示如何将一行添加到stock表:
INSERT INTO stock
VALUES (115, 'PRC', 'tire pump', 108, 'box', '6/box');
stock表有下列列:
stock_num
标识商品的种类的编号。
manu_code
manufact表的外键。
description
该商品的描述。
unit_price
该商品的单价。
unit
计量的单位
unit_descr
说明计量单位的特征。
前一示例中VALUES子句中罗列的值与stock表的列有一一对应关系。要编写VALUES 子句,您必须知道表的列以及它们的前后次序。
VALUES子句仅接受常量值,不接受通用的SQL表达式。您可提供下列值:
- 文字数值
- 文字 DATETIME值
- 文字 INTERVAL 值
•带引号的字符串
- 表示 NULL 的关键字 NULL
•表示当前日期的关键字TODAY
- 表示当前日期和时间的关键字CURRENT (或SYSDATE)
•表示您的授权标识符的关键字USER
- 表示正在运行数据库服务器的计算机名称的关键字DBSERVERNAME (或 SITENAME)
注:MERGE语句可以替代INSERT语句,可使用与INSERT语句一样的VALUES子句语法来 将行插入到表内。MERGE语句执行源表与目标表的外部链接,然后将连接的结果集中的任何行 插入到目标表内,这些行的连接谓词求值为FALSEo MERGE语句不更改源表。除了插入行之外, MERGE语句可可选地同时组合DELETE与INSERT操作,或同时组合UPDATE与INSERT 操作。要获取关于Insert合并、Delete合并和Update合并的语法与限制的更多信息,请参 阅《GBase 8s SQL指南:语法》 中MERGE语句的描述。
表的某些列可能不允许空值。如果您尝试向这样的列插入NULL,则会拒绝该语句。表中 的其他列可能不允许重复的值。如果您指定与这样的列中已经存在的值重复的值,则会拒 绝该语句。有些列甚至可能限制允许的列值。请使用数据完整性约束来限制列。要获取更 多信息,请参阅数据完整性。
限制:请不要为包含货币值的列指定币种符号。请仅指定该金额的数值值。
数据库服务器可在数值与字符数据类型之间进行转换。您可将数值字符的字符串(例如, '-0075.6')作为数值列的值。数据库服务器将数值字符串转换为数值。仅当该字符串不表示 数值时才会发生错误。
您可指定数值或日期作为字符列的值。数据库服务器将那个值转换为字符串。例如,如果 您指定TODAY作为字符列的值,则使用表示当前日期的字符串。(DBDATE环境变量 指定所使用的格式。)
表仅可有一个SERIAL数据类型的列。它还可有SERIAL8列或BIGSERIAL列。
当您插入值时,请为序列列指定值零。数据库服务器按次序生成下一个实际值。序列列不 允许NULL值。
您可为序列列指定非零值(只要它不与那一列中任何现有的值重复),数据库服务器使用 该值。那个非零值可能为数据库服务器生成的值设置新的起始点。(数据库服务器为您生 成的下一个值是比该列中最大值大一的值。)
您不必为每列都指定值。相反,您可在表名称之后罗列列名称,然后仅为您命名了的那些 列提供值。下列示例展示将新行插入到stock表内的语句:
INSERT INTO stock (stock_num, description, unit_price, manu_code)
VALUES (115, 'tyre pump ', 114, 'SHM');
仅提供库存编号、描述、单价和制造商代码的数据。数据库服务器为其余列提供下列值:
•它为未列出的序列列生成一个序列数值。
•它为与它相关联的有特定缺省值的列生成一个缺省值。
•它为任何允许空值的任何列生成NULL值,但它不为指定NULL作为缺省值的任 何列指定缺省值。
您必须为未指定缺省值或不允许NULL值的所有列罗列并提供值。
您可以任何顺序罗列列,只要这些列的值也以相同的顺序罗列。
在执行前一示例中的INSERT语句之后,将下列新行插入到stock表内:
stock_num manu_code description unit_price unit unit_descr
115 SHM tyre pump 114
unit和unit_descr都为空,表示在那两列中存在NULL值。由于unit列允许NULL值, 因此不知道114美元可购买的轮胎充气泵(tire pump)的数目。当然,如果为这一列指定 了 box缺省值,则计量单位将为box。在任何情况下,当您将值插入到表的特定的列内时, 请注意那一行需要什么数据。
您可使用与将行插入到不基于ROW类型的表内的相同方法,将行插入到类型的表内。
当类型的表包含一 row类型列(定义该类型的表的命名了的ROW类型包含嵌套的ROW 类型)时,您插入到row类型列的方法,与为不基于ROW类型的表插入row类型列的 方法相同。下列部分,在列上插入的语法规则,描述如何执行插入到row类型列内。
此部分为示例使用row类型zip_t、address_t和employee_t,以及 类型的表employee。下 图展示创建row类型和表的SQL语法。
图:创建row类型和表的SQL语法。
CREATE ROW TYPE zip_t
(
z_code CHAR(5),
z_suffix CHAR(4)
);
CREATE ROW TYPE address_t |
|
( |
|
street |
VARCHAR(20), |
city |
VARCHAR(20), |
state |
CHAR(2), |
zip ); |
zip_t |
CREATE ROW TYPE employee_t
(
name VARCHAR(30),
address address_t,
salary INTEGER
);
CREATE TABLE employee OF TYPE employee_t;
下列语法规则适用于那些定义在命名了的ROW类型或未命名的ROW类型上的列上的 插入:
在要插入字段值之前,指定ROW构造函数。
将ROW类型的字段值括在圆括号中。
将ROW表达式强制转型为适当的命名了的ROW类型(对于命名了的ROW类型)。
下列语句展示您如何将一行插入到在图1中的employee内:
INSERT INTO employee
VALUES ('Poole, John',
ROW('402 High St', 'Willits', 'CA',
ROW(69055,1450))::address_t, 35000 );
由于employee表的address列是命名了的ROW类型,因此您必须使用强制转型运算符和 ROW类型的名称(address_t)来插入类型address_t的值。
假设您创建下图所示的表。student表定义s_address列为一未命名的row类型。
图:仓腱student表。
CREATE TABLE student
(
s_name VARCHAR(30),
s_address ROW(street VARCHAR (20), city VARCHAR(20),
state CHAR(2), zip VARCHAR(9)), grade_point_avg DECIMAL(3,2)
);
下列语句展示您如何向student表添加一行。要插入到未命名的row类型列s_address内, 请使用ROW构造函数,但不要对该row类型值进行强制转型。
INSERT INTO student
VALUES ('Keene, Terry',
ROW('53 Terra Villa', 'Wheeling', 'IL', '45052'),
3.75);
row类型列的字段可包含NULL值。您可在列级别或在字段级别指定NULL值。
下列语句在列级别指定NULL值,来为s_address列的所有字段插入NULL值。当您在列 级别插入NULL值时,请不要包括ROW构造函数。
INSERT INTO student VALUES ('Brauer, Howie', NULL, 3.75);
当您为ROW类型的特定字段插入NULL值时,必须包括ROW构造函数。下列
INSERT语句展示您可以如何将NULL值插入到employee表的address列的特定字段内。 (address列被定义为命名了的ROW类型。)
INSERT INTO employee
VALUES(
'Singer, John',
ROW(NULL, 'Davis', 'CA',
ROW(97000, 2000))::address_t, 67000
);
当您为ROW类型的字段指定NULL值时,当该ROW类型出现在INSERT语句、 UPDATE语句或程序变量赋值中时,无需显式地强制转型该NULL值。
下列INSERT语句展示您如何为student表的s_address列的street和zip字段插入NULL 值:
INSERT INTO student
VALUES(
'Henry, John',
ROW(NULL, 'Seattle', 'WA', NULL), 3.82
);
当您将行插入到超级表内时,不存在特殊的注意事项。INSERT语句仅适用于在该语句中 指定的表。例如,下列语句将值插入到超级表内,但不将值插入到任何子表内:
INSERT INTO person
VALUES(
'Poole, John',
ROW('4O2 Saphire St.', 'Elmondo', 'CA', '69055'),
345605900
);
此部分描述如何使用DB-Access将集合值插入到列内。它未讨论如何将个别元素插入到集 合列内。要访问或修改集合的个别元素,请使用GBase 8s ESQL/C程序或SPL例程。要获 取关于如何创建GBase 8s ESQL/C程序来插入到集合内的信息,请参阅《GBase 8s ESQL/C 程序员手册》。要获取关于如何创建SPL例程来插入到集合内的信息,请参阅创建和使 用SPL例程。
本部分提供的这些示例是基于下图中的manager表。manager表同时包含简单的和嵌套的集 合类型。
图:创建manager表。
CREATE TABLE manager
( mgr_name department direct_reports projects |
VARCHAR(30), VARCHAR(12), SET(VARCHAR(30) NOT NULL), LIST(ROW(pro_name VARCHAR(15), |
pro_members SET(VARCHAR(20) NOT NULL))
NOT NULL)
);
INSERT INTO manager(mgr_name, department,
direct_reports, projects)
VALUES
(
'Sayles', 'marketing',
"SET{'Simonian', 'Waters', 'Adams', 'Davis', 'Jones'}", LIST{
ROW('voyager_project', SET{'Simonian', 'Waters', 'Adams', 'Davis'}),
ROW ('horizon_project', SET{'Freeman', 'Jacobs', 'Walker', 'Smith', 'Cannan'}),
ROW ('saphire_project', SET{'Villers', 'Reeves',
'Doyle', 'Strongin'})
}
);
要将值插入到ROW类型的集合内,您必须为ROW类型中的每一字段指定值。
通常,在集合中不允许NULL值。然而,如果集合的元素类型为ROW类型,则您可将 NULL值插入到row类型的个别字段内。
您还可指定空集合。空集合是不包含任何元素的集合。要指定空集合,请使用大括号({})。 例如,下列语句将数据插入到manager表中的行内,但指定direct_reports和projects列为空 集合:
INSERT INTO manager
VALUES ('Sayles', 'marketing', "SET{}", "LIST{ROW(NULL, SET{})}"
);
集合列不可包含NULL元素。由于指定NULL值作为集合的元素,因此下列语句返回一 个错误:
INSERT INTO manager
VALUES ('Cole', 'accounting', "SET{NULL}",
"LIST{ROW(NULL, ""SET{NULL}"")}"
下列语法规则适用于对集合类型执行插入和更新:
使用大括号((})来划分每一集合包含的元素。
如果该集合为嵌套的集合,则使用大括号({})来同时划分内部集合和外部集合的元素。
当您使用INSERT语句来将对象插入到BLOB或CLOB列时,数据库服务器在sbspace 中,而不是在表中,存储该对象。数据库服务器提供您可从INSERT语句之内调用的SQL 函数来导入和导出BLOB或CLOB数据,这些数据又称为智能大对象。要了解这些函数 的描述,请参阅智能大对象函数。
下列INSERT语句使用filetoblob()和filetoclob()函数来插入inmate表的行。(图1定 义 inmate 表。)
INSERT INTO inmate
VALUES (437, FILETOBLOB('datafile', 'client'),
FILETOCLOB('tmp/text', 'server'));
在前一示例中,FILETOBLOB()和FILETOCLOB()函数的第一个参数分别指定要复制
到inmate表的BLOB和CLOB列内的源文件的路径。每一函数的第二个参数指定该源文件 是位于客户机计算机('client'),还是位于服务器计算机('server')。要在该函数参数中指 定文件名称的路径,请应用下列规则:
- 如果源文件驻留在服务器计算机上,则您必须指定该文件的完全路径名称(不是相 对于当前工作目录的路径名称)。
- 如果源文件驻留在客户机计算机上,则您可指定该文件的完全路径或相对路径。
INSERT语句的其他主要形式以SELECT语句替代VALUES子句。此特性允许您插入下 列数据:
仅用一条语句处理多个行(每当SELECT语句返回一行,就插入一行)
计算值(VALUES子句仅允许常量),由于projection列表可包含表达式
例如,假设对于已付款但尚未装运的每个订单都需要电话跟进。下列示例中的INSERT语 句找到那些订单并为每一订单在cust_calls中插入一行:
INSERT INTO cust_calls (customer_num, call_descr)
SELECT customer_num, order_num FROM orders
WHERE paid_date IS NOT NULL
AND ship_date IS NULL;
此SELECT语句返回两列。将来自这些列的数据(在每一选择了的行中)插入
到cust_calls表的命名了的列内。然后,将(来自SERIAL列order_num的)订单编号插入
到呼叫描述,这是一个字符列。请记住,数据库服务器允许您将整数值插入到字符列内。 它自动地将序列编号转换为十进制数字的字符串。
下列列表包含对插入行的SELECT语句的限制:
- 它不可包含INTO子句。
- 它不可包含INTO TEMP子句。
- 它不可包含ORDER BY子句。
•它不可引用您正在向其内插入行的表。
INTO、INTO TEMP和ORDER BY子句限制较小。在此上下文中,INTO子句没什么用 处。(要获取更多信息,请参阅SQL编程。)要绕开INTO TEMP子句限制,请先选择 您想要插入到临时表内的数据,然后使用INSERT语句从临时表插入该数据。同样,缺少 ORDER BY子句也无关紧要。如果您需要确保这些新行在表中物理地排序,则您可首先将 它们选择到临时表内并对它排序,然后从该临时表插入。在所有插入完成之后,您还可使 用集群的索引来对该表进行物理排序。
重要: 最后一个限制更为严重,因为它同时阻止在INSERT语句的INTO子句与SELECT语
句的FROM子句中命名同一个表。同时在INSERT语句的INTO子句与SELECT语句的FROM 子句中命名同一个表,导致数据库服务器进入无限循环,每一插入了的行都会在其中被重新选 择和重新插入。
然而,在某些情况下,您可能想要从您必须向其内插入数据的同一个表进行选择。例如, 假设您已了解Nikolus公司与Anza公司供应相同的产品,但仅以一半的价格供应。您想 要向stock表添加一些行来反映两家公司之间的差异。理想情况下,您想要从所有Anza库 存行选择数据,并使用Nikolus制造商代码重新插入它。然而,您不可从您正在向其内插 入的同一个表进行选择。
要避开此限制,请选择您想要插入到临时表内的数据。然后在INSERT语句中从那个临时 表进行选择,如下例所示:
SELECT stock_num, 'NIK' temp_manu, description, unit_price/2
half_price, unit, unit_descr FROM stock
WHERE manu_code = 'ANZ'
AND stock_num < 110
INTO TEMP anzrows;
INSERT INTO stock SELECT * FROM anzrows;
DROP TABLE anzrows;
此SELECT语句从stock得到现有的行,并替换制造商代码的文字值以及单价的计算得到 的值。然后将这些行保存在临时表anzrows中,立即将该表插入到stock表内。
当您插入多个行时,存在一种风险:其中一行包含无效的数据,就可能导致数据库服务器 报告一个错误。当发生这样一个错误时,该语句提早终止。即使未发生错误,也存在一个 小风险:在执行该语句时可能发生硬件或软件故障(例如,磁盘可能写满)。
在任何一种事件中,您都不可轻易地知道插入了多少新行。如果全部重复该语句,则您可 能创建重复的行,也可能不会。由于数据库处于未知状态,因此您无所适从。解决方案在 于使用事务,如中断了的修改讨论的那样。
根据SET子句的规范,使用UPDATE语句来更改表的一个或多个现有行的内容。此语句 采用两种根本不同的形式。一种允许您按名称将特定的值指定给列;另一种允许您将(可 能是通过SELECT语句返回的)值的列表指定给列的列表。在任一情况下,如果您正在更 新行,且某些列有数据完整性约束,则您更改的数据必须符合对那些列的限制。要获取更 多信息,请参考数据完整性。
注:MERGE语句是UPDATE语句的一种替代,可使用与UPDATE语句一样的SET子句语法来 修改表的现有行中的一个或多个值。MERGE语句执行源表与目标表的外部连接,然后以来自于 连接的结果集的值更新目标表中的行,其连接谓词求值为TRUE°MERGE语句不更改源表中的值。 除了更新行之外,MERGE语句可可选地同时组合UPDATE与INSERT操作,或可同时组合 DELETE与INSERT操作而不更新任何行。要获取关于Update合并、Delete合并和Insert合 并的语法和限制的更多信息,请参阅《GBase 8s SQL指南:语法》 中MERGE语句的描述。
UPDATE语句的任一形式都可以确定修改那些行的WHERE子句结尾。如果您省略 WHERE子句,则修改所有行。要选择在WHERE子句中需要更改的精确行集可能非常复 杂。对WHERE子句的唯一限制是,不可在子查询的FROM子句中命名您更新的表。
UPDATE语句的第一种形式是,使用一系列赋值子句来指定新的列值,如下例所示:
UPDATE customer
SET fname = 'Barnaby', Iname = 'Dorfler'
WHERE customer_num = 103;
WHERE子句选择您想要更新的行。在演示数据库中,customer.customer_num列是那个表 的主键,因此,此语句最多可更新一行。
您还可在WHERE子句中使用子查询。假设Anza公司对他们的网球发出安全召回。结果 是,包括来自制造商ANZ的库存编号6的任何未装运的订单都必须设定为延期交货,如 下例所示:
UPDATE orders
SET backlog = 'y'
WHERE ship_date IS NULL
AND order_num IN
(SELECT DISTINCT items.order_num FROM items
WHERE items.stock_num = 6 AND items.manu_code = 'ANZ');
此子查询返回一订单编号(零个或多个)的列。然后,该UPDATE操作针对该列表测 试orders的每一行,如果那一行相匹配,则执行更新。
关键字SET之后的每一赋值都为列指定新的值。那个值统一地应用于您更新的每一行。在 前面部分中的示例中,新的值为常量,但您可指定任意表达式,包括基于列值本身的表达 式。假设制造商HRO已将所有价格提高百分之五,且您必须更新stock表来反映此提价。 请使用下列语句:
UPDATE stock
SET unit_price = unit_price * 1.05 WHERE manu_code = 'HRO';
您还可使用子查询作为指定的值的一部分。当使用子查询作为表达式的元素时,它必须恰 好返回一个值(一列和一行)。对于任何库存编号,或许您决定必须收取比那种产品的任 何制造商都更高的价格。您需要更新所有未装运的订单的价格。下列示例中的SELECT语 句指定该标准:
UPDATE items
SET total_price = quantity *
(SELECT MAX (unit_price) FROM stock WHERE stock.stock_num = items.stock_num) WHERE items.order_num IN
(SELECT order_num FROM orders WHERE ship_date IS NULL);
第一个SELECT语句返回单个值:在stock表中,对于某个特定的产品的最高价格。第一 个SELECT语句是一个相关联的子查询,因为当来自items的值出现在第一个SELECT语 句的WHERE子句中时,您必须为您更新的每一行都执行该查询。
第二个SELECT语句产生未装运的订单的订单编号的一个列表。它是一个执行一次的非相 关的子查询。
当您修改数据时,对子查询的使用存在限制。特别是,您不可查询正在修改的表。您可在 表达式中引用列的当前值,如同在unit_pnce列增大百分之五的示例中那样。您还可引用 在子查询中的WHERE子句中的列的值,如同在更新了 stock表的示例中那样,其中,更 新items 表,且在连接表达式中使用items.stock_num。
在设计良好的数据库中,不会经常发生同时更新与查询一个表的需要。然而,当您首次开 发数据库时,尚未认真全面地考虑它的设计之前,您可能想要同时更新和查询。当无意中 且错误地在表的应为唯一的列中包含了带有重复值的几行时,会发生一个典型的问题。您 可能想要删除重复的行,或仅更新重复的行。不论是哪种方式,不可避免地需要对您想要 修改的同一表上的子查询进行重复的行的测试。这在UPDATE语句或DELETE语句中是 不允许的。通过SQL程序修改数据讨论如何使用更新游标来执行此种修改。
第二种形式的UPDATE语句以单个批量赋值替代赋值列表,其中设置列的列表与值的列 表相同。当这些值是简单的常量时,这种形式与前面的示例的形式没什么不同,只是重新 安排它的某些部分,如下例所示:
UPDATE customer
SET (fname, Iname) = ('Barnaby', 'Dorfler')
WHERE customer_num = 103;
以此方式编写该语句,不存在任何优势。实际上,它更难于阅读,因为将哪些值指定给哪 些列并不明显。
然而,当这些要指定的值来自单个SELECT语句时,这种形式就很合理。假设要将地址的 更改应用于几个客户。不是每次更新customer表都报告更改,而是在名为newaddr的单个 临时表中收集新的地址。现在,一次性应用所有新地址的时候到了。
UPDATE customer
SET (address1, address2, city, state, zipcode)=
((SELECT address1, address2, city, state, zipcode
FROM newaddr
WHERE newaddr.customer_num=customer.customer_num))
WHERE customer_num IN (SELECT customer_num FROM newaddr);
单个SELECT语句产生多个列的值。如果您以其他形式重新编写此示例,为每一更新了的 列进行赋值,您必须编写五个SELECT语句,为每个要更新的列编写一个。这样的语句不 仅更难编写,而且它会花费更长的执行时间。
提示:在SQL API程序中,您可使用记录或主变量来更新值。要获取更多信息,请参考SQL 编程。
依赖于该列是命名了的ROW类型还是未命名的ROW类型,您用于更新row类型值的 语法会不同。本部分描述那些差异,还描述如何为ROW类型的字段指定NULL值。
要更新在命名了的ROW类型上定义的列,您必须指定所有ROW类型的字段。例如,下 列语句仅更新employee表中address列的street和city字段,但每一 ROW类型的字段必须 包含一个值(允许NULL值):
UPDATE employee
SET address = ROW('103 California St',
San Francisco', address.state, address.zip)::address_t WHERE name = 'zawinul, joe';
在此示例中,从该行中读取state和zip字段的值,然后立即重新插入到该行内。仅更 新address列的street和city字段。
当您更新在命名了的ROW类型上定义的列的字段时,您必须使用ROW构造函数,并将 该行值强制转型为适当的命名了的ROW类型。
要更新在未命名的ROW类型上定义的列,您必须指定该ROW类型的所有字段。例如, 下列语句仅更新student表中address列的street和city字段,但ROW 类型的每一字段都必 须包含一个值(允许NULL值):
UPDATE student
SET s_address = ROW('13 Sunset', 'Fresno', s_address.state, s_address.zip)
WHERE s_name = 'henry, john';
要更新在未命名的ROW类型上定义的列的字段,请始终在插入该字段值之前,指定ROW 构造函数。
row类型列的字段可包含NULL值。当您以NULL值插入到row类型字段内或更新 row类型字段时,您必须将该值强制转型为那个字段的数据类型。
下列UPDATE语句展示您可以如何为命名了的row类型列的特定字段指定NULL值:
UPDATE employee
SET address = ROW(NULL::VARCHAR(20), 'Davis', 'CA',
ROW(NULL::CHAR(5), NULL::CHAR(4)))::address_t)
WHERE name = 'henry, john';
下列UPDATE语句展示您如何为student表的address列的street和zip字段指定NULL 值。
UPDATE student
SET address = ROW(NULL::VARCHAR(2O), address.city,
address.state, NULL::VARCHAR(9))
WHERE s_name = 'henry, john';
重要:您不可为row类型列指定NULL值。您仅可为row类型的个别的字段指定NULL值。
当您使用DB-Access来 更新集合类型时,您必须更新整个集合。下列语句展示如何更 新projects列。要定位需要更新的行,请使用IN关键字在direct_reports列上执行搜索。
UPDATE manager
SET projects = "LIST
{
ROW('brazil_project', SET{'Pryor', 'Murphy', 'Kinsley',
'Bryant'}),
ROW ('cuba_project', SET{'Forester', 'Barth', 'Lewis',
'Leonard'})
}"
WHERE 'Williams' IN direct_reports;
在前一语句中第一次出现的SET关键字是UPDATE语句语法的一部分。
重要:请不要将UPDATE语句的SET关键字与表明集合为SET数据类型的SET构造函数 相混淆。
虽然您可使用IN关键字来定位简单集合的特定元素,但您不可从DB-Access更新集合列 的个别元素。然而,您可创建GBase 8s ESQL/C程序和SPL例程来更新集合内的元素。要 获取关于如何创建GBase 8s ESQL/C程序来更新集合的信息,请参阅《GBase 8s ESQL/C程 序员手册》。要获取关于如何创建SPL例程来更新集合的信息,请参阅处理集合部分。
当您更新超级表的行时,更新的作用域是超级表及其子表。
当您对超级表构造UPDATE语句时,您可更新该超级表中的所有列,以及从该超级表继 承的子表的列。例如,下列语句更新来自employee和sales_rep表的行,它们是超级 表person的子表:
UPDATE person
SET salary=65000
WHERE address.state = 'CA';
然而,对超级表的更新不允许您更新不在该超级表内的子表的列。例如,在前面的更新语 句中,您不可更新sales_rep表的region_num列,因为region_num列未出现在employee表 中。
当您对超级表执行更新时,请注意该更新的作用域。例如,对person表的UPDATE语句 未包括 WHERE子句来限定要更新的行,该语句修改person、employee和sales_rep表的所 有行。
要限定为仅对超级表的行更新,您必须在UPDATE语句中使用ONLY关键字。例如,下 列语句仅更新person表的行:
UPDATE ONLY(person)
SET address = R0W('14 Jackson St', 'Berkeley', address.state, address.zip)
WHERE name = 'Sallie, A.';
重要:当您更新超级表的行时,请小心使用,因为对超级表的更新的作用域包括该超级表及其 所有子表。
CASE表达式允许语句返回几个可能的结果之一,这依赖于若干条件测试中哪个求值为
TRUE。
下列示例展示如何在UPDATE语句中使用CASE表达式来增加stock表中某些商品的单 价:
UPDATE stock
SET unit_price = CASE
WHEN stock_num = 1
AND manu_code = "HRO"
THEN unit_price * 1.2 WHEN stock_num = 1
AND manu_code = "SMT"
THEN unit_price * 1.1
ELSE 0
END
您必须在CASE表达式内包括至少一个 WHEN子句;后续的WHEN子句和ELSE子 句是可选的。如果无WHEN条件求值为真,则结果值为空。
您可使用可从UPDATE语句之内调用的SQL函数来导入和导出智能大对象。要了解这 些函数的描述,请参阅智能大对象函数页。
下列UPDATE语句使用LOCOPY()函数来将BLOB数据从fbi_list表的mugshot列复制 到 inmate 表的 picture 列内。(图 1 定义 inmate 和 fbi_list 表。)
UPDATE inmate (picture)
SET picture = (SELECT LOCOPY(mugshot, 'inmate', 'picture')
FROM fbi_list WHERE fbi_list.id = 669)
WHERE inmate.id_num = 437;
LOCOPY()的第一个参数指定从其导出该对象的列(mugshot)。第二个和第三个参数指定 该新创建的对象将使用其存储特性的表(inmate)和列(picture)的名称。该UPDATE语 句执行之后,picture列包含来自mugshot列的数据。
当您在该函数参数中指定文件名称的路径时,请应用下列规则:
•如果源文件驻留在服务器计算机上,则您必须指定该文件的完全路径名称(而不是 相对于当前工作目录的路径名称)。
•如果源文件驻留在客户机计算机上,则您可指定该文件的完全路径名称或相对路径 名称。
MERGE语句允许您对源表与目标表的一个外部连接的结果应用布尔条件。如果MERGE 语句包括Update子句,则对目标在UPDATE操作中使用那些满足您在ON关键字之后 指定的连接条件的行。MERGE语句的SET子句支持与UPDATE语句的SET子句相同 的语法,并指定要更新的目标表的哪些列。
下例示例展示您可如何使用MERGE语句的Update子句来更新目标表:
MERGE INTO t_target AS t USING t_source AS s ON t.col_a = s.col_a
WHEN MATCHED THEN UPDATE
SET t.col_b = t.col_b + s.col_b ;
在前一示例中,目标表的名称为t_target,源表的名称为t_source。对于在源表与目标表中 其col_a都有相同的值的连接结果的行,MERGE语句通过将源表中col_b列的值添加 到t_target表中col_b列的当前值来更新t_target表。
MERGE语句的UPDATE操作不修改源表,且不可更新目标表中的任何行超过一次。
单个 MERGE语句可同时组合UPDATE与INSERT操作,或可同时组合DELETE与 INSERT操作而不需要删除子句。要了解不包括Update子句的MERGE的不同的示例, 请参阅主题MERGE的Delete子句
您可使用下列数据库权限来控制谁可访问数据库:
•数据库级别权限
- 表级别权限
•例程级别权限
•语言级别权限
- 类型级别权限
•序列级别权限
•分片级别权限
本部分简要地描述数据库级别和表级别权限。要了解权限的列表以及GRANT和 REVOKE语句的描述,请参阅《GBase 8s SQL指南:语法》。
当您创建数据库时,您是唯一可访问它的人,直到您作为该数据库的所有者或数据库管理 员(DBA),将数据库级别权限授予其他人。下表展示数据库级别权限。
权限 |
影响 |
Connect |
允许您打开数据库、发出查询以及在临时表上创建和放置索引。 |
Resource |
允许您创建永久表。 |
DBA |
允许您作为DBA执行若干附加的函数。 |
当您在不符合ANSI的数据库中创建表时,所有用户都有访问该表的权限,直到您作为该 表的所有者取消特定用户的表级别权限为止。下表介绍控制用户可如何访问表的四种权限。
权限 用途
权限 |
用途 |
Select |
逐表授予权限,并允许您从表选择行。(此权限可限定于表中的特定列。) |
Delete |
允许您删除行。 |
Insert |
允许您插入行。 |
Update |
允许您更新现有的行(即,更改其内容)。 |
创建数据库和表的人们经常将Connect和Select权限授予public,以便所有用户都拥有它 们。如果您可查询表,则您至少具有对那个数据库和表的Connect和Select权限。
您需要其他的表级别权限来修改数据。表的所有者经常保留这些权限,或仅将它们授予特 定的用户。因此,您可能无法修改您可自由地查询的一些表。
例如,由于这些权限都是逐表授予的,因此您仅可拥有对一个表的Insert权限,以及仅拥 有对另一表的Update权限。甚至可进一步将Update权限限定于表中的特定列。
如果您是表的所有者(即,如果您创建了它),则您拥有对那个表的所有权限。否则,您 可通过查询系统目录来确定您对于某个表拥有的权限。系统目录由描述数据库结构的系统 表构成。对每一表所授予的权限都记录在systabauth系统表中。要显示这些权限,您还必须 知道该表的唯一标识符编号。在systables系统表中指定此编号。要显示对orders表授予的 权限,您可输入下列SELECT语句:
SELECT * FROM systabauth WHERE tabid = (SELECT tabid FROM systables WHERE tabname = 'orders'); |
|
该查询的输出类似于下列示例: |
|
grantorgrantee tabid |
tabauth |
tfecitmutator 101 |
su-i-x-- |
tfecitprocrusteslOI |
s--idx-- |
tfecitpublic 101 |
s--i-x-- |
授权者是授予权限的用户。授权者通常是表的所有者,但所有者可为授权者授权了的另一 用户。被授权者是将权限授予其的用户,被授权者public意味着有Connect权限的任何用 户。如果您的用户名未出现,则您仅拥有授予给了 public的那些权限。
tabauth列指定授予的权限。此列的每一行中的字母是权限名称的首字母,除了 1表示Insert 以及x表示Index之外。在此示例中,public具有Select、Insert和Index权限。仅用 户mutator具有Update权限,仅用户procrustes具有Delete权限。
在数据库服务器为您执行任何操作(例如,执行DELETE语句)之前,它都执行类似于前 一查询的查询。如果您不是该表的所有者,且如果数据库服务器找不到您的用户名 或public对该表的必要权限,则它拒绝执行该操作。
作为DBA,您可创建角色来使得给予一类用户的权限标准化。当您将权限指定给那个角色 时,那个角色的每个用户都拥有那些权限。用于定义和操纵角色的SQL语句包括:C REATE ROLE、DROP ROLE、GRANT、REVOKE和SET ROLE。要获取关于定义和操纵角色的 SQL语句的语法的更多信息,请参阅《GBase 8s SQL指南:语法》。
在连接到数据库时,缺省的角色自动地应用于特定的用户和组,而不要求该用户发出SET ROLE 语句。例如:
GRANT DEFAULT ROLE manager TO larry;
要获取关于角色与缺省角色的更多信息,请参阅控制数据库使用或参阅《GBase 8s管理 员指南》。
要获取关于授予和撤销权限的更多信息,请参阅授予和撤销应用程序中的权限。
INSERT, UPDATE和DELETE语句修改现有的数据库中的数据。每当您修改现有的数据 时,就可影响数据的完整性。例如,可能会将不存在的产品的订单输入到orders表内,可 能从customer表中删除一个有未完成订单的客户,或者可能在orders表中更新订单编号, 但未在items表中更新。在每一这些情况下,都会失去存储的数据的完整性。
数据完整性实际由下列部分组成:
实体完整性
表的每一行都有唯一的标识符。
语义完整性
列中的数据正确地反映设计了该列来保存的信息的类型。
引用完整性
强制执行表之间的关系。
设计良好的数据库体现了这些原则,因此当您修改数据时,数据库本身防止您执行可能损 坏数据完整性的任何操作。
实体是要记录在数据库中的任何人、位置或事物。每一表都表示一个实体,且表的每一行 都表示那个实体的一个实例。例如,如果order是一个实体,则orders表表示订单的概念, 表中的每一行表示一特定的订单。
要标识表中的每一行,该表必须有一主键。主键是标识每一行的一个唯一值。此要求称为 实体完整性约束。
例如,orders表的主键是order_num。order_num列为表中的每一行保存一个唯一的系统生 成的订单编号。要访问orders表中的一行数据,请使用下列SELECT语句:
SELECT * FROM orders WHERE order_num = 1001;
在此语句的WHERE子句中使用该订单编号使得您能够容易地访问行,因为该订单编号唯 一地标识那一行。如果该表允许重复的订单编号,则它几乎不可能访问单个一行,因为此 表的所有其他列都允许重复的值。
语义完整性确保输入到行内的数据反映那一行的允许的值。该值必须在那一行的域或允许 的值集之内。例如,items表的quantity列仅允许数值。如果可将该域之外的值输入到列 内,则违反该数据的语义完整性。
下列约束强制语义完整性:
数据类型
数据类型定义您可存储在列中的值的类型。例如,数据类型SMALLINT允许您将 从-32,767至32,767的值输入到列内。
缺省值
缺省值是当未指定显式的值时插入到该列内的值。例如,如果未输入名称,则 cust_calls表的user_id列的缺省值为该用户的登录名称。
检査约束
检查约束指定对插入到列内的数据的条件。输入到表内的每一行都必须满足这些条 件。例如,items表的quantity列可能检查大于或等于1的数量。
引用完整性指的是表之间的关系。由于数据库中每一表都必须具有主键,因此此主键可出 现在其他的表中,这是因为它与那些表内数据的关系。当来自一个表的主键出现在另一表 中时,将它称之为外键。
外键连接表并在表之间创建依赖。若干表可形成依赖的层级结构,这样,如果您更改或删 除一个表中的行,则您破坏在其他表中行的含义。例如,下图展示customer表 的customer_num列是那个表的主键,以及orders和cust_call表中的外键。
在orders和cust_calls表中都引用客户编号106, George Watson™。如果从customer表删除 客户106,则破坏三个表以及此特定的客户之间的链接。
图:演示数据库中的引用完整性
customer 差
《详细信息)
customer num name |
name |
||||
103 |
Philip |
Currie |
|||
(伽) |
George |
Watson |
|||
〈详细信息) |
|||||
order_num |
order_date |
customer项 um |
|||
1002 |
05/21/1998 |
101 |
|||
1003 |
05/22/1998 |
104 |
|||
1004 |
05/22/1998 |
(使) |
|||
CUSt_MllS^ 〈详细信息) , |
|||||
customer_num |
userjd |
||||
CW6) |
1998-06-128:20 |
maryi |
|||
119 |
1993-07-0710:24 |
riche |
|||
119 |
1998-07-01 15:00 |
riche |
当您删除包含主键的行,或以不同的主键更新它时,您破坏了包含那个值作为外键的任何 行的含义。引用完整性是外键对主键的逻辑依赖。包含外键的行的完整性依赖于它引用的 那行的完整性一包含相匹配的主键的行。
在缺省情况下,数据库服务器不允许您违反引用完整性,且如果在您从子表删除行之前, 您尝试从父表删除行,则向您提示错误消息。然而,您可使用ON DELETE CASCADE选 项来在从父表删除的同时对相应的子表进行删除。请参阅ON DELETE CASCADE选项。
要定义主键和外键以及它们之间的关系,请使用CREATE TABLE和ALTER TABLE语 句。要获取关于这些语句的更多信息,请参阅《GBase 8s SQL指南:语法》。
在级联删除期间锁定
在删除期间,保持父表和子表上的所有符合条件的行上的锁定。当您指定删除时,在执行 任何引用操作之前,执行从父表请求的删除。
多个子表的情况
如果您具有带有两个子约束的父表,一个子表指定了级联删除,另一个子表没有级联删除, 且您尝试从同时应用于两个子表的父表删除一行,则DELETE语句失败,且从父表和子表 都不删除行。
必须打开日志记录
为了使级联删除起作用,您必须在您的当前数据库中打开日志记录。在事务日志记录中讨 论日志记录和级联删除。
假设您有应用了引用完整性规则的两个表,父表accounts,以及子表sub_accounts。下列
CREATE TABLE语句定义引用约束:
CREATE TABLE accounts (
acc_num SERIAL primary key, acc_type INT,
acc_descr CHAR(20));
CREATE TABLE sub_accounts ( sub_acc INTEGER primary key, ref_num INTEGER REFERENCES accounts (acc_num) ON DELETE CASCADE,
sub_descr CHAR(20));
accounts表的主键,acc_num列,使用SERIAL数据类型,sub_accounts表的外键, ref_num列,使用INTEGER数据类型。允许组合主键上的SERIAL与外键上的INTEGER 数据类型。仅在此条件下,您可混合并匹配数据类型。SERIAL数据类型是INTEGER,且 数据库自动地为该列生成值。所有其他主键与外键组合都必须显式地相匹配。例如,定义 为CHAR的主键必须与定义为CHAR的外键相匹配。
sub_accounts表的外键的定义,ref_num列,包括ON DELETE CASCADE选项。此选项指 定在父表accounts中任何行的删除都将自动地导致删除子表sub_accounts的对应行。 要从将级联删除sub_accounts表的accounts表删除一行,您必须打开日志记录。打开日志 记录之后,您可从两个表都删除账户编号2,如下例所示:
DELETE FROM accounts WHERE acc_num = 2;
对于大多数删除,包括自引用的删除和循环查询的删除,您可使用级联删除。唯一的例外 是相关的子查询,相关的子查询是嵌套的SELECT语句,子查询(或内部SELECT)在 其中产生的值依赖于包含它的外部SELECT语句所产生的值。如果您已实施了级联删除, 则您不可在相关的子查询中编写使用子表的删除。当您尝试从相关的子查询删除时,您会 收到错误。
限制:如果表使用ON DELETE CASCADE定义引用约束,则您不可在该表上定义DELETE 触发器事件。
数据库的对象模式和违反检测可帮助您监视数据完整性。在模式更改期间,或当对于短期 内大批量数据执行插入、删除和更新操作时组合这些特性,这些特性特别有效。
在对象模式特性的讨论的上下文之内,数据库对象是约束、索引和触发器,且它们中的每 一个都有不同的模式。请不要将与对象模式特性相关的数据库对象与一般的数据库对象相 混淆。一般的数据库对象是诸如表和同义词之类的对象。
您可为约束或唯一索引设置禁用、启用或过滤模式。您可为触发器或重复索引设置启用或 禁用模式。您可使用数据库对象模式来控制INSERT、DELETE和UPDATE语句的效果。
在缺省情况下,约束、索引和触发器是启用的。
当数据库对象是启用的时,数据库服务器识别该数据库对象的存在,并在它执行INSERT、 DELETE或UPDATE语句时考虑该数据库对象。因此,当触发器事件发生时,强制执行 启用的约束,更新启用的索引,并执行启用的触发器。
当您启用约束和唯一索引时,如果存在违反的行,则该数据处理语句失败(即,不更改行) 且数据库服务器返回错误消息。
当您分析违反表和诊断表中的信息时,您可标识该失败的原因。然后,您可采取更正活动 或回滚该操作。
当数据库对象是禁用的时,在执行INSERT、DELETE或UPDATE语句时,数据库服务 器不考虑它。当触发器事件发生时,不强制执行禁用的约束,不更新禁用的索引,也不执 行禁用的触发器。当您禁用约束和唯一索引时,违反该约束或唯一索引的限制的任何数据 操纵语句都成功,(即,更改目标行),且数据库服务器不返回错误消息。
当约束或唯一索引处于过滤模式时,该语句成功,且在INSERT, DELETE或UPDATE语 句期间,通过将失败了的行写到与该目标表相关联的违反表,数据库服务器强制满足约束 或唯一索引需求。将关于该约束违反的诊断信息写到与目标表相关联的诊断表。
一个使用INSERT语句的示例可说明启用模式、禁用模式与过滤模式之间的差异。请考虑 这样一条INSERT语句,其中一个用户试图在表上添加不满足完整性约束的一行。例如, 假设用户joe创建了名为cust_subset的表,且此表由下列列构成:ssn (客户的社会保险编 号)、fname (客户的名)、lname (客户的姓)以及city (客户生活的城市)。ssn列具有INT 数据类型。其他三列有CHAR数据类型。
假设用户joe定义了 lname列为非空,但尚未将名称指定给非空约束,于是,数据库服务器 己隐式地将名称nl04_7指定给此约束。最后,假设用户joe在ssn列上创建了名 为unq_ssn的唯一索引。
现在,对cust_subset有Insert权限的用户linda在此表上输入下列INSERT语句:
INSERT INTO cust_subset (ssn, fname, city)
VALUES (973824499, "jane", "los altos");
要更好地理解启用模式、禁用模式与过滤模式之间的区别,您可在下面三个部分中查看前 面的INSERT语句的结果。
当约束为启用的时,插入操作的结果
如果在cust_subset表上的NOT NULL约束是启用的,则INSERT语句不能在此表中插入 新行。而当用户linda输入该INSERT语句时,她收到下列错误消息:
-292 An implied insert column lname does not accept NULLs.
当约束为禁用时,插入操作的结果 如果在cust_subset表上NOT NULL约束是禁用的,则用户linda发出的INSERT操作成 功地在此表中插入新行。cust_subset表的新行有下列列值。
ssn |
fname |
lname |
city |
973824499 |
jane |
NULL |
los altos |
如果将cust_subset表上的NOT NULL约束设置为过滤模式,则用户linda发出的INSERT 命令不能在此表中插入新行。而将该新行插入到违反表内,并将描述完整性违反的诊断行 添加到诊断表。
假设用户joe已为cust_subset表启动了违反表和诊断表。违反表名为cust_subset_vio,诊断 表名为cust_subset_dia。当用户linda在cust_subset目标表上发出INSERT语句时,添加 到c ust_subset_vio违反表的新行有下列列值。
ssn |
fnam e |
Inam e |
city |
gbasedbt_tupl eid |
gbasedbt_opt ype |
gbasedbt_recow ner |
9738244 |
jane |
NULL |
los |
1 |
I |
linda |
99 |
alto |
|||||
s |
cust_subset_vio违反表中的此新行有下列特征:
违反表的前四列恰好与目标表的列相匹配。这四列与目标表的对应列有相同的名称和相同 的数据类型,它们具有用户linda输入的INSERT语句提供了的列值。
gbasedbt_tupleid列中的值1是分配给不符合的行的唯一序列标识符。
gbasedbt_optype列中的值I表示操作类型的代码,该操作已导致了创建此不符合的行。特 别地,I代表INSERT操作。
gbasedbt_recowner列中的值linda标识发出了导致创建此不符合行的用户。
用户linda在cust_subset目标表上发出的INSERT语句还导致将诊断行添加
到cust_subset_dia诊断表。添加到诊断表的诊断行有下列列值。
gbasedbt_tuplei d |
objtype |
objowner |
objname |
1 |
C |
joe |
n104_7 |
cust_subset_dia 诊断表中的此新诊断行有下列特征:
通过同时出现在两表中的gbasedbt_tupleid列,将此诊断表的行连接到违反表的对应行。 值1同时出现在两表中的此列。
objtype列中的值C标识违反表中对应行导致的完整性违反的类型。特别地,值C代表约束 违反。
objowner列中的值joe表示检测到违反完整性的约束的所有者。
objname列中的值n104_7给出对其检测到了完整性违反的约束的名称。
通过连接违反表与诊断表,用户joe (其拥有cust_subset目标表及其相关联的特殊表)或
DBA可在违反表中发现在INSERT语句之后创建了的其gbasedbt_tupleid值为1的行,且 此行违反约束。表的所有者或DBA可查询sysconstraints系统目录表来确定此约束为NOT NULL约束。既然知道该INSERT语句失败的原因,用户joe或DBA便可采取更正行动。
gbasedbt_tuplei d |
objtype |
objowner |
objname |
1 |
C |
joe |
n104_7 |
1 |
I |
joe |
unq_ssn |
诊断表中的两行同时对应于违反表的同一行,因为这两行在gbasedbt_tupleid列中都有值1。 然而,第一个诊断行标识用户linda发出了的INSERT语句导致约束违反,而第二个诊断 行标识同一 INSERT语句导致唯一索引违反。在此第二个诊断行中,objtype中的值I代表 唯一索引违反,且0bjname列中的值unq_ssn给出检测出了完整性违反的索引的名称。
要获取关于如何设置数据库对象模式的更多信息,请参阅《GBase 8s SQL指南:语法》中 的 SET Database Object Mode 语句。
当您为目标表启动违反表时,在对目标表的INSERT、UPDATE和DELETE操作期间, 违反约束和唯一索引的任何行都不会导致整个操作失败,但会被过滤到违反表。诊断表包 含关于由违反表中每一行导致的完整性违反的信息。通过检查这些表,您可标识失败的原 因,并通过修正违反或回滚操作来采取更正行动。
在您为目标表创建违反表之后,您不可改变基础表或违反表的列或分片。在您已启动了违 反表之后,如果您改变目标表上的约束,则将不符合的行过滤到违反表。
要获取关于如何启动和停止违反表的信息,请参阅《GBase 8s SQL指南:语法》中的START VIOLATIONS TABLE 和 STOP VIOLATIONS TABLE 语句。
违反表与数据库对象模式的关系
如果您将定义在表上的约束和唯一索引设置为过滤模式,但您未为此目标表创建违反表和 诊断表,则在插入、更新或删除操作期间,违反约束或唯一索引要求的任何行都不过滤到 违反表。相反,您会收到错误消息,指示您必须为目标表启动违反表。
类似地,如果您将禁用的约束或禁用的唯一索引设置为启用模式或过滤模式,且您想要能 够标识不满足约束或唯一索引要求的现有的行,则在您发出SET Database Object Mode语 句之前必须创建违反表。
下列示例展示执行START VIOLATIONS TABLE语句的不同方式。
启动违反表和诊断表而不指定它们的名称
要为演示数据库中名为customer的目标表启动违反表和诊断表,请输入下列语句:
START VIOLATIONS TABLE FOR customer;
由于您的START VIOLATIONS TABLE语句不包括USING子句,因此违反表的缺省名 称为customer_vio,诊断表的缺省名称为customer_dia。customer_vio表包括下列列:
customejnum
fname
lname
company
addressl
address2
city
state
zipcode
phone
gbasedbt_tupleid gbasedbt_optype gbasedbt_recowner
customer_vio表与customer表有相同的表定义,除了 customer_vio表有包含关于导致了坏 行的操作的信息的三个附加列之外。
customer_dia 表包括下列列:
gbasedbt_tupleid
objtype
objowner objname
对于目标表,此列的列表展示诊断表与违反表之间的重要差异。尽管对于目标表中的每列, 违约表都有相匹配的列,但诊断表的列不依赖于目标表的模式。由任何START
VIOLATIONS TABLE语句创建的诊断表始终有以上列表中的四列,带有相同的列名称和 数据类型。
启动违反表和诊断表并指定它们的名称
下列语句为名为items的目标表启动违反表和诊断表。USING子句为违反表和诊断表声明 显式的名称。违反表将命名为exceptions,诊断表将命名为reasonso
START VIOLATIONS TABLE FOR items
USING exceptions, reasons;
指定诊断表中的最大行数
下列语句为名为orders的目标表启动违反表和诊断表。当在目标表上执行诸如INSERT、 MERGE或SET Database Object Mode之类的单个语句时,MAX ROWS子句指定可插入 到orders_dia诊断表内的最大行数。
START VIOLATIONS TABLE FOR orders MAX ROWS 50000;
如果您未为START VIOLATIONS TABLE语句中的MAX ROWS指定值,则对诊断表中 的行数没有缺省的限制,除了可用的磁盘空间之外。
MAX ROWS子句仅对于表函数在其中作为诊断表的操作限定行的数目。
下列示例说明如何从对目标表的权限的当前集派生对违反表的权限的初始集。
例如,假设我们创建了名为cust_subset的表,且此表由下列列组成:ssn (客户的社会保险 号码)、fname (客户的名)、lname (客户的姓)以及city (客户生活的城市)。
在cust_subset表上存在下列权限集:
•用户alvin是该表的所有者。
- 用户barbara具有对该表的Insert和Index权限。她还具有对ssn和lname列的 Select 权限。
- 用户carrie具有对city列的Update权限。她还具有对ssn列的Select权限。
- 用户danny具有对该表的Alter权限。
现在,用户alvin为cust_subset表启动名为cust_subset_viols的违反表和名 为 cust_subset_diags 的诊断表,如下:
START VIOLATIONS TABLE FOR cust_subset
USING cust_subset_viols, cust_subset_diags;
数据库服务器授予对cust_subset_viols违反表的下列初始权限集:
•用户alvin是该违反表的所有者,因此他具有对该表的所有表级别权限。
- 用户barbara具有对违反表的Insert、Delete和Index权限。她还具有对违反表的 下列列的 Select 权限:ssn 列、lname列、gbasedbt_tupleid 列、gbasedbt_optype 列 和 gbasedbt_recowner 列。
- 用户carrie具有对违反表的Insert和Delete权限。她还具有对违反表的下列列的 Update 权限:city 列、gbasedbt_tupleid列、gbasedbt_optype 列
和gbasedbt_recowner列。她具有对违反表的下列列的Select权限:ssn列、 gbasedbt_tupleid列、gbasedbt_optype 列和 gbasedbt_recowner 列。
•用户danny不具有对违反表的任何权限。
下列示例说明如何从对目标表的当前权限集派生对诊断表的初始权限集。
例如,假设名为cust_subset的表由下列列组成:ssn (客户的社会保险编号)、fname (客 户的名)、lname (客户的姓)以及city (客户生活的城市)。
对cust_subset表存在下列权限集:
•用户alvin为该表的所有者。
- 用户barbara具有对该表的Insert和Index权限。她还具有对ssn和lname列的 Select 权限。
- 用户carrie具有对city列的Update权限。她还具有对ssn列的Select权限。
- 用户danny具有对该表的Alter权限。
现在,用户alvin为cust_subset表启动名为cust_subset_viols的违反表和名 为cust_subset_diags的诊断表,如下:
START VIOLATIONS TABLE FOR cust_subset
USING cust_subset_viols, cust_subset_diags;
数据库服务器对于cust_subset_diags诊断表授予下列初始的权限集:
•用户alvin为诊断表的所有者,因此他具有对该表的所有表级别权限。
- 用户barbara具有对诊断表的Insert、Delete、Select和Index权限。
- 用户carrie具有对诊断表的Insert、Delete、Select和Update权限。
•用户danny对诊断表没有权限。
即使所有软件都没有错误且所有硬件都完全可靠,计算机外部的世界也可干扰它。闪电可 能击中建筑物,中断供电并在您的UPDATE语句运行期间停止计算机。当磁盘已满或用 户提供不正确的数据时,更可能发生的情景是,导致您的多行插入过早停止并产生错误。 在任何情况下,每当您修改数据,您必须假设某种不可预测的事件可中断该修改。
当外部原因导致修改中断时,您不可确定该操作完成了多少。即使在单行操作中,您也不 可知道是否正确地更新了到达了磁盘的数据或索引。
如果多行修改是一个问题,则多语句修改就更糟。通常在程序中嵌入它们,因此您看不到 正在执行的个别SQL语句。例如,要在演示数据库中输入新的订单,请执行下列步骤:
- 在orders表中插入一行。(此插入生成一个订单编号。)
- 对于订购的每一商品,在items表中插入一行。
存在两种编制订单输入应用程序的方法。一种方法是使它完全是交互的,以便程序立即插 入第一行,然后在用户输入时插入每一商品。但这种方法使得操作可能遭遇许多更不可预 测的事件:客户的电话电线,用户按错键,用户的终端或计算机断电,等等。
下列列表描述构建订单输入应用程序的正确方法:
•以交互方式接受所有数据。
- 验证数据并展开它(例如,在stock和manufact中查找代码)。
- 在屏幕上显示信息以进行检查。
•等待操作人员进行最终的提交。
•快速地执行插入。
即使使用这些步骤,不可预测的情况还可在它插入该订单之后,但在它完成插入商品之前 停止该程序。如果发生那种情况,则数据库处于不可预测的状态:它的数据完整性受到损 害。
对所有这些潜在问题的解决方案称为事务。事务是必须或者全部完成,或者根本就不执行 的修改的序列。数据库服务器保证在事务的范围内执行的操作或者完整并正确地提交到磁 盘,或者将数据库恢复到事务开始之前的同一状态。
事务不仅是对不可预测的故障的保护;当程序检测到逻辑错误时,它还为程序提供一种规 避的方法。
数据库服务器可保持对在事务期间数据库服务器对数据库进行的每一更改的记录。如果发 生了取消该事务的情况,则数据库服务器自动地使用这些记录来撤销更改。许多原因可导 致事务失败。例如,发出SQL语句的程序可失败或被终止。数据库服务器一发现事务失
败,失败可能就在重新启动计算机和数据库服务器之后发生,它就使用来自该事务的记录 来将数据库返回到之前的同一状态。
保存事务的记录的过程称为事务日志记录,或简称为日志记录。事务的记录,称为日志记 录,保存在与数据库分开的磁盘空间部分中。此空间称为逻辑日志,因为该日志记录表示 事务的逻辑单元。
GBase 8s提供下列支持:
- 在日志记录数据库中创建无日志记录(raw)或日志记录(standard)的表。
- 使用ALTER TABLE语句将表从无日志记录改变为日志记录,或相反。
为了快速加载非常大的表,GBase 8s支持无日志记录的表。建议您在事务内不使用无日志 记录的表。要避免并发问题,在您在事务中使用表之前,请使用ALTER TABLE语句来使 该表成为standard (即,日志记录)。
要获取关于GBase 8s的无日志记录的表的更多信息,请参阅《GBase 8s管理员指南》。 要了解无日志记录的表的性能优势,请参阅《GBase 8s性能指南》。要获取关于ALTER TABLE语句的信息,请参阅GBase 8s SQL指南:语法。
大多数GBase 8s数据库不会自动地生成事务记录。DBA决定数据库是否使用事务日志记 录。没有事务日志记录,您就不可回滚事务。
为了使级联删除起作用,必须在您的数据库中打开日志记录,因为当您指定级联删除时, 首先在父表的主键上执行删除。如果在执行父表的主键的行删除之后,但在删除子表的外 键的行之前,系统出现故障,则违反引用完整性。如果关闭日志记录,即使是临时地关闭, 也不会级联删除。然而,在重新打开日志记录之后,又可级联删除。
GBase 8s允许您使用CREATE DATABASE语句中的 WITH LOG子句来打开日志记录。
您可使用两种方法来用SQL语句指定事务的边界。在最常用的方法中,通过执行BEGIN WORK语句指定多语句事务的开始。在以MODE ANSI选项创建的数据库中,不存在标 记事务的开始的需要。总会有一个起作用;您只要指明每一事务的结束。
在两种方法中,要指定成功的事务的结束,请执行COMMIT WORK语句。此语句告诉数 据库服务器您达到了必须一起成功完成的一系列语句的结束。数据库服务器执行任何必要 的操作来确保正确地完成了所有修改并提交到了磁盘。
程序还可通过执行ROLLBACK WORK语句来有意地取消事务。此语句请求数据库服务器 取消当前事务并撤销任何更改。
当订单输入应用程序创建新订单时,它可以下列方式使用事务:
•交互地接受所有数据。
- 验证并展开它。
•等候操作人员进行最终的提交
•执行 BEGIN WORK
- 在orders和items表中插入行,检查数据库服务器返回的错误代码
- 如果未发生错误,则执行COMMIT WORK;否则,执行ROLLBACK WORK
如果任何外部故障阻止事务的完成,在当系统重启时,部分事务回滚。在所有情况下,该 数据库处于不可预测的状态。要么完全地输入新订单,要么根本未输入它。
志
通过使用事务,您可确保数据库始终处于一致的状态,且将您的修改正确地记录在磁盘上。 但磁盘本身不十分安全。对于机械故障以及洪水、火灾和地震,它都是脆弱的。唯一的保 护措施是保存数据的多个副本。这些冗余的副本称为备份副本。
事务日志(也称为逻辑日志)补充数据库的备份副本。它的内容是自从上一次备份数据库 以来发生了的所有修改的历史。如果您曾经需要从备份副本恢复数据库,则您可使用事务 日志来将数据库向前滚到它最近的状态。
数据库服务器包含完善的特性来支持备份和日志记录。您的数据库服务器归档和备份指南 描述这些特性。
数据库服务器对性能和可靠性有严格的要求(例如,它支持在正在使用数据库时制作备份 副本。)
数据库服务器管理它自己的磁盘空间,这些空间专用于日志记录。
数据库服务器使用有限的日志文件集来并发地执行所有数据库的日志记录。在事务为活动 的时,可将日志文件复制到另一介质(备份)。
数据库服务器从不需要考虑这些设置,因为DBA总是从中央位置管理它们。
GBase 8s支持onload和onunload实用程序。使用onunload实用程序来制作单个数据库 或表的个人备份副本。此程序将表或数据库复制到磁带。它的输岀由磁盘页的二进制映像 组成,如同在数据库服务器中存储了它们。因此,可快速地制作副本,且相应的onload程 序可快速地恢复该文件。然而,对于任何其他程序,该数据格式没有意义。要获取关于如 何使用onload和onunload实用程序的信息,请参阅《GBase 8s迁移指南》。
如果您的DBA使用ON-Bar来创建备份并备份逻辑日志,则您还可能能够使用ON-Bar 来创建您自己的备份副本。要获取更多信息,请参阅您的《GBase 8s备份与恢复指南》。
如果在单个用户工作站中包含您的数据库,而没有网络将它连接到其他计算机,则并发并 不重要。在所有其他情况下,您必须允许这样的可能性:当您的程序正在修改数据时,另 一程序也正在读取或修改同一数据。并发涉及在同一时间对同一数据的两个或多个独立使 用。
在多用户数据库系统中,高级别的并发对良好的性能至关重要。然而,除非在数据的使用 上存在控制,否则并发可导致各种负面的影响。程序可能读取过时的数据;即使表面上似 乎成功地输入了修改,但修改可能丢失。
要防止此类错误,数据库服务器强加一个锁定系统。锁定是程序可在一块数据上放置的声 明或保留。只要数据被锁定,数据库服务器就保证其他程序不可修改它。当另一程序请求 该数据时,数据库服务器或者让该程序等待,或者向它返回错误。
要控制锁定对您的数据访问的影响,请使用SQL语句的组合:SET LOCK MODE与或者 SET ISOLATION或者SET TRANSACTION。在从程序内阅读关于游标的使用的讨论之 后,您可了解这些语句的详细信息。在SQL编程和通过SQL程序修改数据中讨论游 标。要获取关于锁定和并发的更多信息,请参阅对多用户环境编程。
从更广义上讲,术语数据复制意味着在多个不同的站点,数据库对象多次出现。例如,有 一种复制数据的方式是将数据库复制到不同的计算机上的数据库服务器,这样,报告可针 对该数据运行,而不干扰正在使用原始数据库的客户机应用程序。
下列列表描述数据复制的优势:
•与未复制的远程数据相对,在本地访问复制了的数据的客户机的性能提高,因为它 们无需使用网络服务。
•使用复制了的数据,提高所有站点的客户机的可用性,因为如果本地的复制了的数 据不可用时,尽管是远程地,该数据的一个副本仍可用。
获得这些优势不是没有代价的。与非复制的数据相比,对于复制了的数据,数据复制显然 需要更多的存储,且更新复制了的数据可比更新单个对象要花费更多处理时间。
通过显式地指定应发现和更新数据的位置,可在客户机应用程序的逻辑中实际地实现数据 复制。然而,归档数据复制的这种方式成本高、容易出错且难以维护。相反,数据复制的 概念常常伴随着复制透明。复制透明是在数据库服务器内自动地处理定位和维护数据副本 的详细信息的内建功能。
在数据复制的大框架内,GBase 8s数据库服务器几乎实现整个数据库服务器的透明的数据 复制。复制一个数据库服务器管理的所有数据,并动态地在另一数据库服务器上更新,通 常位于一远程站点。GBase 8s数据库服务器的数据复制有时称为热站点备份,因为它提供 一种维护整个数据库服务器的备份副本的方法,在发生灾难性故障时,可快速地使用它。
由于数据库服务器提供复制透明,因此您通常不需要关注或注意到数据复制;DBA会处理 它。然而,如果您的机构决定使用数据复制,则您应注意到,在数据复制环境中,存在对 于客户机应用程序的特殊连接性事项。在GBase 8s管理员指南中描述这些事项。
通过数据库所有者授予您的权限来控制数据库访问。通常自动地授予您查询数据的权限, 但通过特定的Insert、Delete和Update权限来控制修改数据的能力,以逐个表的方式授予 这些权限。
如果对数据库施加数据完整性约束,则您的修改数据的能力受到那些约束的限制。您的数 据库级别权限和表级别权限以及任何数据约束控制您可如何以及何时修改数据。此外,数 据库的对象模式和违反检测特性也影响您可修改数据的方式,并有助于保持您的数据的完 整性。
您可使用DELETE语句从表删除一行或多行。它的WHERE子句选择这些行;使用带有 相同子句的SELECT语句来预览这些删除。
TRUNCATE语句删除表的所有行。
使用INSERT语句将行添加到表。您可插入包含特定的列值的单个行,或可插入SELECT 语句生成的一批行。
使用UPDATE语句来修改现有的行的内容。您使用可包括子查询的表达式来指定新的内 容,以便您可使用基于其他表或更新了的表自身的数据。该语句有两种形式。在第一种形 式中,您逐列地指定新值。在第二种形式中,SELECT语句或记录变量生成一组新值。
使用CREATE TABLE和 ALTER TABLE语句的REFERENCES子句来创建表之间的 关系。REFERENCES子句的ON DELETE CASCADE选项允许您使用一个 DELETE语 句来从父表和相关联的子表删除行。
使用事务来防止在修改过程中不可预测的中断,防止数据库处于不确定的状态。当在一事 务内执行修改时,会在发生错误之后回滚它们。事务日志还扩展数据库的定期制作的备份 副本。如果必须恢复数据库,则它可将数据库返回到最近的状态。
对用户为透明的数据复制提供另一种针对灾难性故障的保护。
GBase 8s SQL 指南:教程———7修改数据相关推荐
- GBase 8s SQL 指南:教程———6编写高级SELECT语句
6编写高级SELECT语句 本章中增大了使用SELECT语句可执行的操作的范围.并使您能够执行更复杂的数据库查 询和数据处理.编写SELECT语句着重于SELECT语句语法中的五个子句.本章添加了 G ...
- GBase 8s SQL 指南:教程———3编写SELECT语句
3编写SELECT语句 SELECT语句是最重要且最复杂的SQL语句.可使用它和SQL语句INSERT. UPDATE和DELETE操纵数据.可以使用SELECT语句从数据库检索数据.将它用作 INS ...
- GBase 8s SQL 指南:教程———12 创建和使用SPL例程
本部分描述如何创建和使用SPL例程.SPL例程是以GBase 8s "存储过程语言"(SPL) 编写的用户定义的例程.GBase 8s SPL是提供流控制的SQL的扩展,诸如循环和 ...
- GBase 8s SQL 指南:语法————2.2 SQL 语句
ALTER ROUTINE 语句 使用 ALTER ROUTINE 语句更改先前定义的用户定义的例程(UDR)的例程修饰符或路径名.该 语句是 SQL ANSI/ISO 标准的扩展. 语法 元素 ...
- sql server跨服务器修改数据,SQL Server跨数据库服务器查询和跨表更新的详细操作...
SQL Server数据库跨数据库服务器查询和跨表更新的相关知识是本文我们主要要介绍的内容,接下来我们就通过一个实例来介绍这一过程.实例是这样的:想实现的功能很简单, 在我的本地一个表用来保存省的信息 ...
- SQL Server插入或修改数据是中文乱码的问题
SQL Server中乱码解决方案: 在Sql Server2005英文版中,如果未对Varchar类型的字段进行设置,那么很多朋友会发现向数据库中插入记录时,如果对应的varchar类型字段 的值为 ...
- GBase 8s V8.8 SQL 指南:教程-5.1.5(1)
5.1.5 智能大对象函数 数据库服务器提供了四个 SQL 函数,您可以从 SQL 语句中调用这些函数来导入和导出智 能大对象.下表显示智能大对象函数. 表 1. 智能大对象的 SQL 函数 有关智能 ...
- GBase 8s ALTER SECURITY LABEL COMPONENT 语句
使用 ALTER SECURITY LABEL COMPONENT 语句向当前数据库中的一个现有的安全标签构件中 添加一个或多个元件.该语句是 SQL ANSI/ISO 标准的扩展. 语法 用法 只有 ...
- php 访问 gbase,GBase 8s PHP连接指南V1.0
1 PHP 与GBase 8s 连接指南 欢迎使用PHP与GBase 8s(以下简称GBase)连接指南.此指南旨在为协助GBase管理人员和开发人员提供PHP与GBase成功连接的相关方法,并根据w ...
最新文章
- Dart语言--基础内容
- Redhat 5 无法安装elfutils-libelf-devel-0.137问题
- 【Groovy】闭包 Closure ( 闭包的 delegate 代理策略 | OWNER_FIRST | DELEGATE_FIRST | OWNER_ONLY | DELEGATE_ONLY )
- vi编辑器的学习使用(十五)
- Python3.x 基础练习题100例(91-100)
- 关系数据库的基本概念和MySQL说明
- java bytebuffer 读写_java nio bytebuffer文件读写问题
- python控制台进度条_python在控制台输出进度条的方法
- centos7安装python2.6_centos7.2下yum和python重装问题及解决方法
- 办公神器,专治低效——特色功能软件工具
- manchi翻译中文 mi_求这一段意大利文歌词中文翻译(MiManchi)?
- LaTeX调整页眉宽度适应文本
- SQL Server 索引碎片和填充因子
- 双十一,美团为何静悄悄?
- 单核CPU与多核CPU的区别
- [爆笑]吃了伟哥的公鸡
- 关于C++ variant 类型问题
- word如何给数学公式编号
- html的css怎么设置深度,vue css 深度选择器
- 定位及overflow
热门文章
- ES6 数组对象去重
- java值传递和引用传递 面试题
- 对抗式主动学习三部曲(GAAL 、VAAL、TA-VAAL)---入内不亏
- 网站通用后台框架代码,自适应显示器高度和宽度
- 3亿新市民金融崛起前夕,谁能率先打通服务链?
- Adobe 数字出版解决方案 Digital Publishing Suite (Indesign 制作iPad电子书) 系列之二: 制作流程的介绍
- Python进行ffmpeg推流和拉流rtsp、rtmp
- java匿名类监听器
- 【OpenCV】(三)opencv入门之图像的基本操作——图像阈值分割(ostu算法)
- php require 输出乱码,php输出excel乱码怎么办