第七十七章 SQL命令 TRUNCATE TABLE

第七十七章 SQL命令 TRUNCATE TABLE

从表中删除所有数据并重置计数器。

大纲

TRUNCATE TABLE [restriction] tablename

参数

  • restriction - 可选—以下限制关键字中的一个或多个,用空格隔开:%NOCHECK%NOLOCK
  • tablename - 要从中删除所有行的表。
    还可以指定一个可更新视图,通过该视图可以删除表中的所有行。
    表名(或视图名)可以是限定的(schema.table)或非限定的(table)。
    使用模式搜索路径(如果提供的话)或默认模式名将非限定名称匹配到其模式。

描述

TRUNCATE TABLE命令从表中删除所有行,并重置所有表计数器。
可以直接截断表,也可以通过视图截断表。
通过视图截断表会受到删除要求和限制,如CREATE view中所述。

TRUNCATE TABLE重置用于生成RowID字段、IDENTITY字段和SERIAL(%Library.Counter)字段连续整数值的内部计数器。
IRIS为插入到TRUNCATE表后的表中的第一行中的这些字段赋值为1。
对表的所有行执行DELETE操作不会重置这些内部计数器。

TRUNCATE TABLE重置用于在数据插入到流字段时生成流字段OID值的内部计数器。
对表的所有行执行DELETE操作不会重置此内部计数器。

TRUNCATE TABLE总是将%ROWCOUNT本地变量设置为-1;
它没有将%ROWCOUNT设置为删除的行数。

TRUNCATE TABLE不会重置ROWVERSION计数器。

TRUNCATE TABLE禁止提取基表触发器,否则在DELETE处理期间提取基表触发器。
因为TRUNCATE TABLE执行的是带有%NOTRIGGER行为的删除,用户必须被授予%NOTRIGGER权限(使用GRANT语句)才能运行TRUNCATE TABLE
TRUNCATE TABLE的这方面在功能上是相同的:

DELETE %NOTRIGGER FROM tablename

注意:DELETE命令也可以用来删除表中的所有行。
DELETE提供了比TRUNCATE TABLE更多的功能,包括返回%ROWCOUNT中已删除的行数。
DELETE不会重置内部计数器。

TRUNCATE TABLE为从其他数据库软件迁移代码提供了兼容性。

截断一个表:

  • 表必须存在于当前(或指定)命名空间中。
    如果无法找到指定的表,IRIS将发出SQLCODE -30错误。

  • 即使没有定义触发器,用户也必须具有%NOTRIGGER管理权限。
    如果没有此权限,则会出现%msg User does not have %NOTRIGGER权限的SQLCODE -99错误。

  • 用户必须对表具有DELETE权限。
    如果没有此权限,将导致带有%msgSQLCODE -99
    可以通过调用%CHECKPRIV命令来确定当前用户是否具有DELETE权限。
    可以通过调用$SYSTEM.SQL.Security.CheckPrivilege()方法来确定指定的用户是否具有DELETE权限。

  • 该表不能定义为READONLY
    试图编译引用只读表的TRUNCATE TABLE会导致SQLCODE -115错误。
    注意,这个错误现在是在编译时发出的,而不是只在执行时发生。

  • 如果通过视图删除,视图必须是可更新的;
    不能定义为WITH READ ONLY
    尝试这样做会导致SQLCODE -35错误。

  • 所有的行必须是可删除的。
    默认情况下,如果不能删除一行或多行,则TRUNCATE TABLE操作失败,不会删除任何行。

如果表被其他进程以EXCLUSIVE模式或SHARE模式锁定,则TRUNCATE TABLE失败。
试图在一个锁定的表上执行TRUNCATE TABLE操作将导致SQLCODE -110错误,并带有%msg,如下所示:
MyStuff' on row with RowID = '3'(其中指定的RowID是表中的第一行)。

如果删除一行会违反外键引用完整性,那么TRUNCATE TABLE将失败。
未删除任何行,因此TRUNCATE TABLE发出SQLCODE -124错误。
这个默认行为是可以修改的,如下所述。

Fast Truncate

如果可能,SQL优化器将执行高效的Fast Truncate表操作。
Fast Truncate操作删除表的范围,而不是单独删除每条记录。
在可能的情况下,快速截断将自动应用。
当无法实现快速截断时,将执行标准的Truncate TABLE操作。

注意:如果没有删除行,或者使用Fast TRUNCATE删除行,则TRUNCATE TABLE不会初始化或设置%ROWID
因此,应该避免在TRUNCATE表之后使用%ROWID值。

Fast Truncate 限制

快速截断可以应用于标准表或分片表。

不能应用快速截断:

  • 如果用户无法获得表级锁(除非指定了%NOLOCK)。
  • 如果表是外键约束的目标。
  • 如果表包含带有指定LOCATION参数的流字段。
    当所有流字段没有指定可选的LOCATION参数时,可以应用快速截断。

Atomicity

TRUNCATE TABLE不会在自动启动的事务中发生,因此不提供日志记录或回滚选项。

如果需要日志记录和回滚TRUNCATE TABLE选项,则必须显式指定START TRANSACTION,并以显式COMMITrollback结束。

这与SET TRANSACTION %COMMITMODE= NONE或0(没有自动事务)相同——调用TRUNCATE TABLE时不会启动任何事务。
失败的TRUNCATE TABLE操作可能会使数据库处于不一致的状态,一些行被删除,一些行没有被删除。
要在此模式中提供事务支持,必须使用START transaction来启动事务,并使用COMMITROLLBACK来结束事务。

分片表的TRUNCATE TABLE总是使用SET TRANSACTION %COMMITMODE NONE执行,即使用户显式地设置了SET TRANSACTION %COMMITMODE EXPLICIT

限制参数

要使用constraint参数,必须拥有当前名称空间对应的admin-privilege

指定约束参数限制处理如下:

  • %NOCHECK - 禁止对引用被删除行的外键进行引用完整性检查。
  • %NOLOCK - 抑制被删除行的行锁定。
    这应该只在单个用户/进程更新数据库时使用。
    如果不指定%NOLOCK,则快速截断将尝试获取表级锁。
    如果TRUNCATE TABLE不能获得表级锁,它将执行一个标准的截断表,在表的每一行上获取行级锁。

可以以任何顺序指定多个限制参数。
多个参数由空格分隔。

如果在删除父记录时指定了约束参数,则在删除相应的子记录时将应用相同的约束参数。

TRUNCATE TABLE总是使用隐式的%NOTRIGGER行为执行删除操作,并且需要相应的admin-privilege

参照完整性

IRIS使用系统范围的配置设置来确定是否执行外键引用完整性检查;
默认值是执行外键引用完整性检查。
可以在系统范围内设置此默认值,如外键引用完整性检查中所述。
要确定当前系统范围的设置,调用$SYSTEM.SQL.CurrentSettings()

TRUNCATE TABLE操作期间,对于每个外键引用,都会在引用表中相应的行上获得一个共享锁。
这一行将被锁定,直到事务结束。
这确保了在可能的TRUNCATE表回滚之前不会更改引用的行。

事务锁

IRIS对TRUNCATE TABLE操作执行标准锁定。
唯一的字段值在当前事务期间被锁定。

默认的锁阈值是每个表1000个锁。
这意味着,如果在事务期间从表中删除超过1000个惟一字段值,就会达到锁阈值,IRIS会自动将锁级别从惟一字段值锁提升到表锁。
这允许在事务期间进行大规模删除,而不会溢出锁表。

可以使用$SYSTEM.SQL.Util.GetOption(“LockThreshold”)方法确定当前系统范围的锁阈值。
这个系统范围的锁阈值是可配置的:

  • 使用$SYSTEM.SQL.Util.SetOption("LockThreshold")方法。
  • 通过管理门户。
    进入系统管理,配置,SQL和对象设置,SQL。
    查看和编辑“锁定升级阈值”的当前设置。

需要在“%Admin Manage Resource”中具有“USE”权限才能修改锁定阈值。
IRIS会立即将对锁阈值的任何更改应用到所有当前进程。

Imported SQL代码

ImportDDL("IRIS")Run()方法不支持TRUNCATE TABLE命令。
在这些方法导入的SQL代码文件中发现的TRUNCATE TABLE命令将被忽略。
这些导入方法确实支持DELETE命令。

示例

下面两个动态SQL示例比较了DELETETRUNCATE表。
每个示例都创建一个表,向表中插入行,删除表中的所有行,然后向现在为空的表中插入一行。

第一个示例使用DELETE删除表中的所有记录。
注意,DELETE不会重置RowID计数器:

ClassMethod TruncateTable()
{
    s tcreate = "CREATE TABLE SQLUser.MyStudents1 (StudentName VARCHAR(32),StudentDOB DATE)"
    s tinsert = "INSERT INTO SQLUser.MyStudents1 (StudentName,StudentDOB) "_
                "SELECT Name,DOB FROM Sample.Person WHERE Age <= '21'"
    s tinsert1 = "INSERT INTO SQLUser.MyStudents1 (StudentName,StudentDOB) VALUES ('Bob Jones',60123)"
    s tdelete = "DELETE SQLUser.MyStudents1"
    s tStatement = ##class(%SQL.Statement).%New()
    s qStatus = tStatement.%Prepare(tcreate)
    if qStatus '= 1 {
        w "%Prepare failed:" 
        d $System.Status.DisplayError(qStatus) 
        q
    }
    s rset = tStatement.%Execute()
    w rset.%StatementTypeName,!

    n %ROWCOUNT,%ROWID
    s qStatus = tStatement.%Prepare(tinsert)
    if qStatus '= 1 {
        w "%Prepare failed:" 
        d $System.Status.DisplayError(qStatus) 
        q
    }
    s rset = tStatement.%Execute()
    w rset.%StatementTypeName," rowcount ",rset.%ROWCOUNT,!

    s qStatus = tStatement.%Prepare(tdelete)
    if qStatus '= 1 {
        w "%Prepare failed:" 
        d $System.Status.DisplayError(qStatus) 
        q
    }
    s rset = tStatement.%Execute()
    w rset.%StatementTypeName," rowcount ",rset.%ROWCOUNT,!

    s qStatus = tStatement.%Prepare(tinsert1)
    if qStatus '= 1 {
        w "%Prepare failed:" 
        d $System.Status.DisplayError(qStatus) 
        q
    }
    s rset = tStatement.%Execute()
    w rset.%StatementTypeName," rowcount ",rset.%ROWCOUNT," RowID ",rset.%ROWID,!
    &sql(DROP TABLE SQLUser.MyStudents1)
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).TruncateTable()
CREATE TABLE
INSERT rowcount 41
DELETE rowcount 41
INSERT rowcount 1 RowID 42

第二个示例使用TRUNCATE TABLE删除表中的所有记录。
注意,%StatementTypeNameTRUNCATE表返回“DELETE”
注意,TRUNCATE TABLE会重置RowID计数器:

ClassMethod TruncateTable1()
{
    s tcreate = "CREATE TABLE SQLUser.MyStudents2 (StudentName VARCHAR(32),StudentDOB DATE)"
    s tinsert = "INSERT INTO SQLUser.MyStudents2 (StudentName,StudentDOB) "_
    "SELECT Name,DOB FROM Sample.Person WHERE Age <= '21'"
    s tinsert1 = "INSERT INTO SQLUser.MyStudents2 (StudentName,StudentDOB) VALUES ('Bob Jones',60123)"
    s ttrunc = "TRUNCATE TABLE SQLUser.MyStudents2"
    s tStatement = ##class(%SQL.Statement).%New()
    s qStatus = tStatement.%Prepare(tcreate)
    if qStatus '= 1 {
        w "%Prepare failed:" 
        d $System.Status.DisplayError(qStatus) 
        q
    }
    s rset = tStatement.%Execute()
    w rset.%StatementTypeName,!

    n %ROWCOUNT,%ROWID
    s qStatus = tStatement.%Prepare(tinsert)
    if qStatus '= 1 {
        w "%Prepare failed:" 
        d $System.Status.DisplayError(qStatus) 
        q
    }
    s rset = tStatement.%Execute()
    w rset.%StatementTypeName," rowcount ",rset.%ROWCOUNT,!

    s qStatus = tStatement.%Prepare(ttrunc)
    if qStatus '= 1 {
        w "%Prepare failed:" 
        d $System.Status.DisplayError(qStatus) 
        q
    }
    s rset = tStatement.%Execute()
    w rset.%StatementTypeName," (TRUNCATE TABLE) rowcount ",rset.%ROWCOUNT,!

    s qStatus = tStatement.%Prepare(tinsert1)
    if qStatus '= 1 {
        w "%Prepare failed:" 
        d $System.Status.DisplayError(qStatus) 
        q
    }
    s rset = tStatement.%Execute()
    w rset.%StatementTypeName," rowcount ",rset.%ROWCOUNT," RowID ",rset.%ROWID,!
    //&sql(DROP TABLE SQLUser.MyStudents2)
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容