特殊 ABAP SQL 表达式 NULL
null
值是数据库返回的特殊值,用于指示未定义的值或结果。ABAP 中没有特殊的 null
值,如今在语言中添加这样的功能并不容易。数据类型的值范围占用其数据对象的整个内存空间。例如,想象一下 ABAP 字典中的简单单字节整数类型 INT1
,对应于 ABAP 中的 b
:值范围是 0 到 255,这正是您可以用 1 个字节的位(十六进制 00 到 FF)表示的范围。没有为 null
值留出空间,也没有剩余值来表示 null
值。
当使用 ABAP SQL 从数据库中读取 null
值时,它只会转换为 ABAP 目标字段的特定于类型的初始值,对于数字类型为 0,对于字符类型为空。因此,无法通过简单的比较来判断是否读取了 null
值。长期以来,处理 null
值的唯一方法是关系表达式 IS NULL
以及最近的 null
指示符。
事实上,在 ABAP 的早期,这从未被视为问题,因为在 ABAP 世界中,null
值仅在特殊情况下才会出现在数据库中:
- 在 ABAP SQL 中,对数据库表的写入访问通常不会产生
null
值。 - 将新列追加到填充的表中时,可以在 DDIC 数据库表中生成
null
值。但是,这可以用初始值的标志覆盖。
在读取访问方面,只有在 ABAP 4.0 版中引入外部连接后,空值才开始出现在结果集中。从那时起,随着越来越多的 SQL 表达式和函数被添加,空值作为这些表达式和函数的结果出现。一个突出的例子是大小写区分:如果省略 ELSE
语句,表达式将自动生成 null
值。其他示例是在发生异常时返回 null
值的函数。由于这些原因,空值在 ABAP SQL 中变得越来越常见,因此需要改进对空值的处理。
除了上述关系表达式 IS NULL
和 null
指示符之外,还有一种在 ABAP SQL 中显式表示 null
值的新方法,即表达式 NULL。
虽然 ABAP CDS 在 ABAP 版本 7.89、SAP BTP ABAP Environment 2208(请参阅所有 CDS DDL 功能的功能矩阵)中引入了 ELSE NULL
,允许您在 CASE
表达式的 ELSE
之后指定空值,但 ABAP SQL 更进一步,引入了一个新的 SQL 表达式 NULL
,该表达式可用于 ABAP SQL 的更多操作数位置。特殊 SQL 表达式 NULL
从 ABAP 版本 7.83 SAP BTP ABAP Environment 2102 开始可用。
本博客简要介绍了 null 表达式,由于 NULL
几乎可以在 ABAP SQL 环境中的任何地方使用,因此我们测试了每个位置并总结了我们的发现和可能的陷阱。
介绍
操作数 NULL
表示 null 值,可以在 SQL 表达式的许多操作数位置使用。一个著名的例子是上面介绍的case distinction。
记住,ABAP 没有 null 值。相反,在 ABAP SQL、Native SQL 或 AMDP 中分配给 ABAP 数据对象的 null 值将转换为与类型相关的初始值。在此处内容。
因此,表达式 NULL
是处理 ABAP SQL 中 null 值的选项。其他选项包括关系表达式 IS NULL
和 null 指示符。NULL
和 IS NULL
之间的区别解释如下。使用 NULL
的一个重要方面是必须能够派生类型(请参见 Pitfalls)。
引入 NULL
,目标是允许 NULL
作为字段列表中的常量列值。最后,ABAP SQL 中通常允许 NULL
。这样就可以根据条件将整个表达式显式用于其操作数之一,从而将整个表达式设置为 null。可能的用例如下所述。
使用案例
null 表达式的两个可能用例是 ELSE NULL
和 THEN NULL
,这两者都是大小写区别的一部分。Scope 部分给出了大小写区分的另一个示例,以演示可以使用 NULL
的操作数位置。以下示例代码显示了 2023 年 3 月航空公司代码为 LH
的所有航班的示例。包括大小写区分,以识别有可用头等舱座位的航班。
METHOD main.
SELECT FROM sflight
FIELDS carrid,
connid,
fldate,
price,
currency,
planetype,
CASE
WHEN seatsocc_f < seatsmax_f THEN 'yes'
WHEN seatsocc_f = seatsmax_f THEN CAST( NULL AS CHAR( 1 ) )
END AS book_a_seat
WHERE fldate BETWEEN datn`20230301` AND datn`20230331`
AND carrid = 'LH'
INTO TABLE @FINAL(result) INDICATORS NULL STRUCTURE null_ind.
cl_demo_output=>display( result ).
ENDMETHOD.
(顺便说一句,您认识示例中的类型化文本吗?查看此博客文章。
查询返回以下内容(不包括 NULL_IND
CARRID | CONNID | FLDATE | PRICE | CURRENCY | PLANETYPE | BOOK_A_SEAT |
---|---|---|---|---|---|---|
LH | 0401 | 2023-03-14 | 668.2 | EUR | 767-200 | |
LH | 0402 | 2023-03-10 | 668.2 | EUR | A380-800 | yes |
LH | 2402 | 2023-03-15 | 244.2 | EUR | A380-800 | yes |
LH | 2407 | 2023-03-15 | 244.2 | EUR | A320-200 | |
LH | 0400 | 2023-03-15 | 808.52 | EUR | A340-600 |
此处 NULL 的用例是,您主要对可用座位感兴趣,但仍想了解其他航班,也许是为了规划未来几个月的航班。下面解释了 NULL
和 null 指示符的所有内容。
范围
下面的示例演示 NULL
可以在简单的大小写区分中使用的位置。您可以在 ABAP 关键字文档中找到此类示例。
METHOD main.
SELECT FROM scarr
LEFT OUTER JOIN spfli
ON scarr~carrid = spfli~carrid
FIELDS scarr~carrid,
distid,
CASE distid
WHEN 'MI' THEN 'Miles'
WHEN 'KM' THEN 'Kilometers'
ELSE NULL
END AS distance,
CASE distid
WHEN 'MI' THEN NULL
WHEN NULL THEN 'Kilometers'
ELSE NULL
END AS null
INTO TABLE @FINAL(result)
UP TO 5 ROWS.
cl_demo_output=>display( result ).
ENDMETHOD.
在此示例中,指定了两个简单 case 区分,这两个区分都包含 NULL
。NULL
可以在 ELSE
之后的操作数位置显式使用,也可以在 WHEN
和 THEN
之后使用。结果表如下所示:
查看 result
表时,您无法查看是否存在 null 值。这是因为 null 值会转换为初始值,例如,由空格表示。Null 指示符可用于识别 Null 值:
INTO TABLE @FINAL(result) INDICATORS NULL STRUCTURE null_ind
使用 null 指示符,可以确定包含 null 值的结果集的列。在此示例中,使用了一个结构化指标,并且结构的每个组件都是 x
类型,长度为 1。十六进制 1 的组件值表示结果集的相应列中的 null 值。result
表现在如下所示:
result
表强调列 DISTID
、DISTANCE
和 NULL
对所有不为 true 的比较返回 null 值。此外,列 NULL
返回未知结果,以便与 null 值进行比较。当 NULL
传递到结果表时,null 值将转换为初始值。
发现
基本上,NULL
可以在 SQL 表达式的任何操作数位置使用。下表标记了例外情况。True/False 列指示是否可以在特定操作数位置使用 NULL
(True) 或不能使用 NULL
(False)。
Category | Syntax | Argument | True/False |
---|---|---|---|
Numeric function | ROUND( sql_exp, pos ) | pos | True |
String function | LIKE_REGEXPR( pcre = pcre, value = sql_exp[, case_sensitive = case\] ) | pcre case | True |
String function | LOCATE( sql_exp, sub[ ... \] ) | sub | True |
String function | LOCATE_REGEXPR( pcre = pcre, value = sql_exp[, case_sensitive = case\][ ... ] ) | pcre case | True |
String function | LOCATE_REGEXPR_AFTER( pcre = pcre, value = sql_exp[, case_sensitive = case\][ ... ] ) | pcre case | True |
String function | OCCURRENCES_REGEXPR( pcre = pcre, value = sql_exp[, case_sensitive = case\] ) | pcre case | True |
String function | REPLACE_REGEXPR( pcre = pcre, value = sql_exp1, with = sql_exp2[, case_sensitive = case\][ ... ] ) | pcre case | True |
String function | SUBSTRING_REGEXPR_AFTER( pcre = pcre, value = sql_exp[ ... \][, case_sensitive = case][ ... ] ) | pcre case | True |
Unit conversion | UNIT_CONVERSION( quantity = a1, source_unit = a2, target_unit = a3[, client = a4 \][ ... ] ) | a2 a3 a4 | False |
Currency conversion | CURRENCY_CONVERSION( amount = a1, source_currency = a2, target_currency = a3[, exchange_rate_date = ... | a2 a3 a4 a6 | False |
Window function | FIRST_VALUE( col|sql_null ) | sql_null | True |
Window function | LAST_VALUE( col|sql_null ) | sql_null | True |
Relational expression | BETWEEN operand1 AND operand2 | operand1 operand2 | True |
大多数正异常发生在字符串函数作为 pcre
、sub
和 case
的有效参数类型时。这里提到窗口函数是因为在引入 NULL
之前只允许将列作为参数。
陷阱
如上所述,使用 NULL
的两个最重要的要点是记住,必须能够派生类型,并且除了少数例外,几乎可以在所有 SQL 表达式位置指定 null 表达式。如果在关系表达式中使用 NULL
,则结果永远不会为 true,而是 unknown。Unknown 与 false 类似,但 AND
、OR
和 NOT
的行为不同。此外,在使用 UNIT_CONVERSION()
函数等测试错误处理时,另一个可能的陷阱会暴露出来。
根据第一个示例,您可以假设需要为没有固定长度的类型指定长度。例如,编写 CAST( NULL AS CHAR( 10 ) )
。这是真的,您需要为具有可变长度的所有类型的类型指定长度,以便使用 NULL
的强制转换。第二个示例显示了 NULL
的动态错误处理。此外,如上所述,表达式 NULL
看起来类似于关系表达式 IS NULL
。需要注意的是,虽然 NULL
是一个表达式,但 IS NULL
是具有谓词语法的关系表达式。
更多信息
SQL 表达式 NULL 处理 null 值,并且可以在 SQL 表达式中的大多数操作数位置指定。NULL 是类型相关的,对于强制转换表达式中具有可变长度的类型,需要指定的长度。不要将关系表达式与谓词语法 IS NULL 与表达式 NULL 混淆。牢记所有因素,您可以开始使用 NULL。下面列出了一些进一步的参考资料:
- Feature Matrix: Data Modeling with ABAP Core Data Services (Blog)
- SQL Expression NULL (ABAP Keyword Documentation)
- SQL Expression NULL – Example (ABAP Keyword Documentation)
现在,您应该知道如何在项目中使用 SQL 表达式 NULL
。在 ABAP SQL 中使用 NULL
进行 null 处理。本博客中给出的示例仅用于演示目的。您是否对使用特殊的 null 表达式感到兴奋?在评论部分写下您的想法。不要错过新的语言元素,并关注我的个人资料 (lenapadeken) 以获取类似的博客文章。
原文链接:Special ABAP SQL expression NULL