第五十六章 SQL命令 INSERT OR UPDATE

第五十六章 SQL命令 INSERT OR UPDATE

在表中添加新行或更新表中的现有行。

大纲

INSERT OR UPDATE [%keyword] [INTO] table
          SET column = scalar-expression {,column2 = scalar-expression2} ...  |
          [ (column{,column2} ...) ] VALUES (scalar-expression {,scalar-expression2} ...)  |
          VALUES :array()  |
          [  (column{,column2} ...) ] query  |
          DEFAULT VALUES

参数

  • %keyword - 可选-以下一个或多个关键字选项,以空格分隔:%NOCHECK%NOFPLAN%NOINDEX%NOJOURN%NOLOCK%NOTRIGGER%PROFILE%PROFILE_ALL
  • table - 要对其执行插入操作的表或视图的名称。此参数可以是子查询。INTO关键字是可选的。
  • column - 可选-与提供的值列表顺序对应的列名或以逗号分隔的列名列表。如果省略,值列表将按列号顺序应用于所有列。
  • scalar-expression - 为相应列字段提供数据值的标量表达式或以逗号分隔的标量表达式列表。
  • :array() - 仅嵌入式SQL-指定为主机变量的值的动态本地数组。必须未指定数组的最低下标级别。因此:myupdates(), :myupdates(5,):myupdates(1,1,)都是有效的规范。
  • query - 一种选择查询,其结果集为一行或多行的相应列字段提供数据值。

描述

INSERTUPDATE语句是INSERT语句的扩展(它与INSERT语句非常相似):

  • 如果指定的记录不存在,则INSERTUPDATE执行INSERT
  • 如果指定的记录已存在,则INSERTUPDATE执行更新。它使用指定的字段值更新记录。即使指定的数据与现有数据相同,也会进行更新。

INSERTUPDATE通过将唯一关键字字段值与现有数据值匹配来确定记录是否存在。如果发生违反唯一键约束的情况,则INSERTUPDATE将执行UPDATE操作。请注意,唯一键字段值可能不是在INSERTUPDATE中显式指定的值;它可能是列默认值或计算值的结果。当对切片表运行INSERTUPDATE时,如果切片键与UNIQUE KEY约束相同(或是其子集),则INSERTUPDATE将执行UPDATE操作。如果INSERTUPDATE因为找到任何其他唯一键值(不是切片键)而尝试执行更新,则该命令会失败,并由于UNIQUE约束失败而出现SQLCODE-119错误。

注意:由于%NOCHECK关键字禁用唯一值检查,因此INSERTUPDATE %NOCHECK总是导致INSERT操作。因此,请不要指定%NOCHECK

单个记录的INSERTUPDATE始终将%ROWCOUNT变量设置为1,并将已插入或更新的行的%ROWID变量设置为1。

INSERTUPDATE语句与SELECT语句组合可以插入和/或更新多个表行。

INSERTUPDATE使用相同的语法,并且通常具有与INSERT语句相同的功能和限制。这里描述了插入或更新的特殊注意事项。除非此处另有说明,否则请参阅插入以了解详细信息。

权限

INSERTUPDATE同时需要插入和更新权限。必须将这些权限作为表级权限或列级权限拥有。对于表级权限:

  • 无论实际执行的是什么操作,用户都必须拥有对指定表的INSERTUPDATE权限。
  • 如果使用SELECT查询插入或更新另一个表中的数据,则用户必须对该表具有SELECT权限。

如果用户是表的所有者(创建者),则会自动授予该用户对该表的所有权限。否则,必须授予用户对该表的权限。否则将导致SQLCODE-99错误,因为%msg用户‘name’没有该操作的特权。可以通过调用%CHECKPRIV命令来确定当前用户是否具有适当的权限。可以使用GRANT命令为用户分配表权限。

IDKEY字段

可以插入IDKEY字段值,但不能更新IDKEY字段值。如果表具有IDKEY索引和另一个唯一键约束,则INSERTUPDATE将匹配这些字段以确定是执行INSERT还是UPDATE。如果另一个键约束失败,则强制INSERTUPDATE执行更新而不是INSERT。但是,如果指定的IDKEY字段值与现有IDKEY字段值不匹配,则此更新将失败并生成SQLCODE-107错误,因为更新正在尝试修改IDKEY字段。

例如,表MyTest定义了四个字段:A、B、C、D,具有IDKEY(A,B)Unique(C,D)约束。该表包含以下记录:

Row 1: A=1, B=1, C=2, D=2

Row 2: A=1, B=2, C=3, D=4

调用INSERTUPDATE ABC(A,B,C,D)(2,2,3,4),因为UNIQUE(C,D)约束失败,所以该语句不能执行INSERT。相反,它会尝试更新第2行。第2行的IDKEY为(1,2),因此INSERTUPDATE语句将尝试将字段A的值从1更改为2。但无法更改IDKEY值,因此更新失败,并显示SQLCODE-107错误。

计数器字段

当执行INSERTUPDATE时, IRIS最初假定操作将是INSERT。因此,它将用于向串行(%Library.Counter)字段提供整数的内部计数器加1。INSERT使用这些递增的计数器值将整数值分配给这些字段。但是,如果 IRIS确定该操作需要更新,则INSERTUPDATE已经递增了内部计数器,但它不会将这些递增的整数值分配给计数器字段。如果下一个操作是INSERT,则会导致这些字段的整数序列出现间隙。下面的示例显示了这一点:

  1. 内部计数器值为4INSERTUPDATE递增内部计数器,然后插入行5:内部计数器=5,串行字段值=5
  2. INSERTUPDATE递增内部计数器,然后确定它必须对现有行执行更新:INTERNAL COUNTER=6,不更改字段计数器。
  3. INSERTUPDATE递增内部计数器,然后插入一行:内部计数器=7序列字段值=7

Identity和RowID字段

INSERTUPDATERowId值分配的影响取决于是否存在标识字段:

  • 如果没有为表定义标识字段,则INSERT操作会导致 IRIS自动将下一个连续整数值分配给ID(RowID)字段。更新操作对后续插入没有影响。因此,INSERTUPDATE执行与INSERT相同的INSERT操作。
  • 如果为表定义了标识字段,则INSERTUPDATE会导致 IRIS在确定操作是INSERT还是UPDATE之前,将用于向标识字段提供整数的内部计数器加1。插入操作将该递增的计数器值分配给标识字段。但是,如果 IRIS确定INSERTUPDATE操作需要更新,则它已经递增了内部计数器,但不会分配这些递增的整数值。如果下一个INSERTUPDATE操作是INSERT,则会导致标识字段的整数序列出现间隙。RowID字段值取自Identity字段值,导致ID(RowID)整数值的分配存在差距。

示例

以下五个示例:创建一个新表(SQLUser.CaveDwell);使用INSERTUPDATE用数据填充该表;使用INSERTUPDATE添加新行并更新现有行;使用SELECT*显示数据;以及删除该表。

以下示例使用CREATE TABLE创建具有唯一字段(NUM)的表:

ClassMethod InsertOrUpdate()
{
    &sql(
        CREATE TABLE SQLUser.CaveDwellers (
            Num          INT UNIQUE,
            CaveCluster  CHAR(80) NOT NULL,
            Troglodyte   CHAR(50) NOT NULL,
            CONSTRAINT CaveDwellerPK PRIMARY KEY (Num)
        )
    )
    if SQLCODE = 0 { 
        w !,"表创建" 
    } elseif SQLCODE = -201 { 
        w !,"表已经存在" 
    } else { 
        w !,"SQL表创建错误代码: ",SQLCODE
        q 
    }
}

下面的示例使用类定义定义同一个表,为num定义唯一键:

Class User.CaveDwellers Extends %Persistent [ ClassType = persistent, DdlAllowed, Final, Owner = {yx}, ProcedureBlock, SqlRowIdPrivate, SqlTableName = CaveDwellers ]
{

Property Num As %Library.Integer(MAXVAL = 2147483647, MINVAL = -2147483648) [ SqlColumnNumber = 2 ];

Property CaveCluster As %Library.String(MAXLEN = 80) [ Required, SqlColumnNumber = 3 ];

Property Troglodyte As %Library.String(MAXLEN = 50) [ Required, SqlColumnNumber = 4 ];

/// DDL Unique Key Specification
Index CAVEDWELLERSUNIQUE1 On Num [ SqlName = CAVEDWELLERS_UNIQUE1, Unique ];

/// DDL Primary Key Specification
Index CaveDwellerPK On Num [ PrimaryKey, Type = index, Unique ];

/// Bitmap Extent Index auto-generated by DDL CREATE TABLE statement.  Do not edit the SqlName of this index.
Index DDLBEIndex [ Extent, SqlName = "%%DDLBEIndex", Type = bitmap ];

}

SELECT * FROM SQLUser.CaveDwellers ORDER BY Num

以任何顺序运行以下两个示例一次或多次。他们将插入记录15。如果记录4已经存在,插入或更新将更新它。使用SELECT *示例显示表格数据:

ClassMethod InsertOrUpdate1()
{

    &sql(
        INSERT OR UPDATE INTO SQLUser.CaveDwellers 
        (
            Num, CaveCluster, Troglodyte
        ) 
        VALUES 
        (
            3, 'Bedrock', 'Flintstone,Fred'
        )
    )
    if SQLCODE = 0 { 
        SET rcount=%ROWCOUNT 
    }
    &sql(
        INSERT OR UPDATE INTO SQLUser.CaveDwellers 
        (
            Num, CaveCluster, Troglodyte
        ) 
        VALUES 
        (
            4, 'Bedrock1', 'Flintstone,Wilma'
        )
    )
    if SQLCODE = 0 { 
        s rcount = rcount + %ROWCOUNT 
        w !,rcount," records inserted/updated" 
    } else { 
        w !,"Insert/Update failed, SQLCODE=",SQLCODE 
    }
}
ClassMethod InsertOrUpdate2()
{

    n SQLCODE,%ROWCOUNT,%ROWID
    &sql(
        INSERT OR UPDATE SQLUser.CaveDwellers
        (
            Num,CaveCluster,Troglodyte
        )
        SELECT %ID,Home_City,Name
        FROM Sample.Person
        WHERE %ID BETWEEN 2 AND 5)
    if SQLCODE=0 {
        w !,"Insert/Update succeeded"
        w !,%ROWCOUNT," records inserted/updated"
        w !,"Row ID=",%ROWID 
    } else {
        w !,"Insert/Update failed, SQLCODE=",SQLCODE 
    }
}

以下示例删除该表:

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

推荐阅读更多精彩内容