您好,我是小DAI,专注于数据库管理员相关的技术问答,请问有什么可以帮您?

排序表变量

简介

排序表变量是一种特殊的表变量,旨在通过定义的键值提供对其数据记录的高效访问。它们适用于对批量数据操作的命令算法。排序表变量的数据记录始终按搜索键值排序,搜索键值在变量的数据类型中指定。通过 SQLScript 搜索运算符访问数据时,如果可能,将使用有效的二进制搜索。

搜索键值

搜索键值可以是表变量列的任意子集。搜索键定义中的列顺序很重要:数据记录首先按第一个搜索键列排序,然后按第二个搜索键列排序,依此类推。 备注表 LT 按列 B、A、C:位置ABCD10110100221152003123150412530要查看如何使用搜索键值,请查看以下有关表变量搜索运算符的说明。

数据记录顺序

排序顺序基于搜索键的数据类型。由于排序仅与 SQLScript 表变量搜索运算符相关,因此对于排序与 SQL 语句中的 ORDER BY 规范完全相同的所有数据类型,无法保证其行为完全一致。您也不能影响排序,特别是不能指定升序或降序。

主键

排序表变量还允许指定主键。主键必须完全由搜索键列组成。在表变量的每个操作中检查主键的唯一性(表分配、插入运算符等)。如果违反唯一性,则会抛出相应的错误。

数据类型定义

搜索键值可以指定为用户定义的表类型的一部分:

CREATE TYPE  AS TABLE () SQLSCRIPT SEARCH KEY()

变量声明

搜索键值也可以指定为变量声明的一部分:

DECLARE  TABLE() SEARCH KEY()

DECLARE

SEARCH KEY()

在第二种情况下,表类型不得包含任何搜索键值定义。

过程或函数参数

搜索键值也可以指定为参数定义的一部分。

CREATE PROCEDURE  (IN  TABLE() SEARCH KEY())

CREATE PROCEDURE (IN

SEARCH KEY())

在第二种情况下,表类型不得包含任何搜索键值定义。

除非提供了具有兼容键值的已排序表变量(在这种情况下,无需重新排序),否则将在调用时对输入排序的表变量进行重新排序。

无法在过程或函数内修改输入排序表变量。

对于最外层调用,使用 ORDER BY 子句根据搜索键对输出排序表变量所对应的结果集进行排序。因此,您可以确保输出表参数具有已定义的数据记录顺序。

对于子调用,排序的输出可以分配到任何类型的表变量 - 未排序,或使用其他搜索键排序(这需要复制和/或重新排序)。通常用例确实应该是到具有相同搜索键值的已排序表变量的分配(这既不需要复制,也不需要重新排序)。

表变量搜索运算符和二进制搜索

如果按键值的初始部分或整个键值进行搜索,则可以使用二进制搜索。如果按某些附加字段搜索,则首先应用二进制搜索以缩小搜索间隔,然后按顺序扫描。

基于上述 LT 表的示例:

搜索语句行为:LT.SEARCH(B, 1)按 B 列搜索。可以应用二进制搜索并找到第一个数据记录。:LT.SEARCH((B, A), (1, 2))按 B、A 列搜索。可以应用二进制搜索并找到第二个数据记录。:LT.SEARCH((B, C), (1, 15))按 B、C 列搜索。二进制搜索只能应用于列 B (B = 1),因为未提供列 A(将成为下一个搜索键列)。二进制搜索将搜索间隔缩小为 1..2,并按顺序搜索 C = 200 且找到第二个数据记录。:LT.SEARCH(A, 1) 按 A 列搜索。根本无法应用二进制搜索,因为未提供第一个搜索键列 B。通过顺序搜索找到第三个数据记录。 

表搜索运算符的输出

如果存在匹配的数据记录,则返回第一个匹配数据记录的位置。这与未排序表变量的行为相同。

但是,如果按完整搜索键(指定所有搜索键列)搜索,并且没有匹配记录,则返回负值,而不是 NULL。返回值的绝对值指示将插入具有指定键值的数据记录的位置,以保持排序。

基于上述 LT 表的示例:

搜索语句结果:LT.SEARCH(B, 3)未指定完整搜索键值,并且没有匹配的数据记录。结果为 NULL。:LT.SEARCH((B, A, C), (1, 2, 20))已指定完整搜索键值,并且没有匹配的数据记录。结果是 -3,因为必须在位置 3 插入 B = 1、A = 2、C = 20 的数据记录。 

这允许您在正确的位置直接插入缺少的数据记录。否则,插入运算符必须再次搜索此位置。

示例: 示例代码DECLARE lt TABLE(key int, count int) SEARCH KEY(key);DECLARE search_result int;...search_result = :lt.SEARCH(key, someval);IF search_result > 0 THEN lt.count[search_result] = :lt.count[search_result] + 1;ELSE :lt.INSERT((someval, 0), -search_result);END IF;

迭代具有相同键值的记录

排序不仅允许您访问单个数据记录,还可以高效迭代具有相同键值的数据记录。与表变量搜索运算符一样,您必须使用搜索键的初始部分或整个搜索键。

示例代码表变量有 3 个搜索键列,您可以遍历具有前两个搜索键列的特定键值组合的数据记录。DECLARE pos int;DECLARE mytab TABLE (key1 int, key2 int, key3 int, value int) SEARCH KEY(key1, key2, key3);DECLARE keyval1, keyval2 int;...pos = :mytab.SEARCH((key1, key2), (keyval1, keyval2));IF pos > 0 THEN WHILE :mytab.key1[pos] = keyval1 AND :mytab.key2[pos] = keyval2 DO -- do something with the record at position "pos" ... pos = pos + 1; END WHILE;END IF;

SQLScript 表变量修改运算符

对于排序表变量,可以使用所有可用的表变量修改运算符。但是,每次修改时,系统都必须确保不违反排序。这会产生以下后果:

  • 插入运算符不含显式位置说明的插入运算符在正确的位置插入数据记录,同时考虑排序定义。具有显式位置说明的插入运算符检查是否违反排序。如果是,则会引发错误,并且不会插入任何数据。在将表变量插入到具有显式位置说明的排序表变量时,不会对输入表变量进行重新排序,它必须符合排序定义。用于插入的最高显式指定位置为当前表变量大小增加 1(否则,将创建空数据记录,这可能会违反排序)。

  • 不含显式位置说明的插入运算符在正确的位置插入数据记录,同时考虑排序定义。

  • 具有显式位置说明的插入运算符检查是否违反排序。如果是,则会引发错误,并且不会插入任何数据。

  • 在将表变量插入到具有显式位置说明的排序表变量时,不会对输入表变量进行重新排序,它必须符合排序定义。

  • 用于插入的最高显式指定位置为当前表变量大小增加 1(否则,将创建空数据记录,这可能会违反排序)。

  • 更新运算符/表单元格分配不允许修改搜索键列。不允许修改非现有数据记录(这将导致创建新数据记录并可能违反排序)。

  • 不允许修改搜索键列。

  • 不允许修改非现有数据记录(这将导致创建新数据记录并可能违反排序)。

    如上所述,如果定义了主键,则也会检查其唯一性。

    表变量分配

    您可以将排序的表变量用作分配目标,就像未排序的表变量一样。数据记录将始终根据搜索键值重新排序。如果定义了主键,系统将检查其是否唯一。查询中的任何 ORDER BY 子句(其结果被指派给排序表变量)都无关紧要。

    限制

  • 搜索键不支持以下数据类型:空间数据类型LOB 类型

  • 空间数据类型

  • LOB 类型

  • 无法将表函数的输出定义为排序表类型。