0 关注者 · 478 帖子

SQL 是在关系数据库中存储、操作和检索数据的标准语言。

文章 姚 鑫 · 十二月 30, 2021 3m read

第十章 SQL聚合函数 STDDEV, STDDEV_SAMP, STDDEV_POP

返回数据集的统计标准差的聚合函数。

大纲

STDDEV([ALL | DISTINCT [BY(col-list)]] expression [%FOREACH(col-list)] [%AFTERHAVING])

STDDEV_SAMP([ALL | DISTINCT [BY(col-list)]] expression [%FOREACH(col-list)] [%AFTERHAVING])

STDDEV_POP([ALL | DISTINCT [BY(col-list)]] expression [%FOREACH(col-list)] [%AFTERHAVING])

参数

  • ALL - 可选-指定标准偏差函数返回表达式的所有值的标准偏差。如果未指定关键字,则这是默认值。
  • DISTINCT - 可选-指定标准偏差函数返回不同(唯一)表达式值的标准偏差的DISTINCT子句。DISTINCT可以指定BY(COL-LIST)子句,其中COL-LIST可以是单个字段,也可以是逗号分隔的字段列表。
  • expression - 任何有效的表达式。通常是包含要分析标准偏差的数据值的列的名称。
  • %FOREACH(col-list) - 可选-列名或逗号分隔的列名列表。
  • %AFTERHAVING - 可选-应用HAVING子句中的条件。

除非表达式的数据类型为DOUBLE,否则这些函数将返回数字数据类型。如果表达式为DOUBLE,则返回DOUBLE

描述

这三个标准差聚合函数在丢弃NULL值后返回表达式值分布的统计标准差。 也就是说,从数据集的平均值的标准差的量,表示为一个正数。 返回值越大,值的数据集的变化就越大。

STDDEV、STDDEV_SAMP (sample)STDDEV_POP (population)函数是由相应的方差聚合函数派生而来的:

  
STDDEVVARIANCE
STDDEV_SAMPVAR_SAMP
STDDEV_POPVAR_POP

标准差是相应方差值的平方根。

这些标准差函数可以在引用表或视图的SELECT查询或子查询中使用。 它们可以在SELECT列表或HAVING子句中与普通字段值一起出现。

这些标准偏差函数不能在WHERE子句中使用。 它们不能在JOINON子句中使用,除非SELECT是子查询。

这些标准偏差函数返回数据类型NUMERIC的值,精度为36,刻度为17,除非表达式是数据类型DOUBLE,在这种情况下它返回数据类型DOUBLE

这些函数通常应用于具有数值的字段或表达式。 它们将非数值值(包括空字符串("))计算为零(0)。

这些标准偏差函数会忽略数据字段中的NULL值。 如果查询没有返回行,或者返回的所有行的数据字段值为NULL,则返回NULL

与所有聚合函数一样,标准差函数可以采用一个可选的DISTINCT子句。 STDDEV(DISTINCT col1)返回那些不同(唯一)的col1字段值的标准偏差。 STDDEV(DISTINCT BY(col2) col1)返回记录中col1字段值的标准差,其中col2值是不同的(唯一的)。 但是请注意,不同的col2值可能包含一个单独的NULL值。

当前事务期间所做的更改

与所有聚合函数一样,标准偏差函数总是返回数据的当前状态,包括未提交的更改,而不考虑当前事务的隔离级别。

示例

下面的示例使用STDDEV返回员工年龄的标准偏差。 ,以及一个或多个员工代表的不同年龄的标准差:

    avg = (37+26)/2 = 31.5
    
    min = (37 - 31.5)^2 + (26-31.5)^2 = 60.5
    
    res = \sqrt{60.5} = 7.778
SELECT STDDEV(Age) AS AgeSD,STDDEV(DISTINCT Age) AS PerAgeSD
     FROM Sample.Employee WHERE %ID IN (116,117) 

下面的示例使用STDDEV_POP返回员工年龄的总体标准差。 ,以及一个或多个员工代表的不同年龄的标准差:

SELECT STDDEV_POP(Age) AS AgePopSD,STDDEV_POP(DISTINCT Age) AS PerAgePopSD
     FROM Sample.Employee

0
0 309
文章 姚 鑫 · 十二月 29, 2021 3m read

[toc]

第九章 SQL聚合函数 MIN

返回指定列中的最小数据值的聚合函数。

大纲

MIN([ALL | DISTINCT [BY(col-list)]] expression [%FOREACH(col-list)] [%AFTERHAVING])

参数

  • ALL - 可选-将聚合函数应用于所有值。ALLMIN返回的值没有影响。提供它是为了与SQL-92兼容。
  • DISTINCT - 可选-指定考虑每个唯一值。DISTINCTMIN返回的值没有影响。它是为SQL-92兼容性提供的。
  • expression - 任何有效的表达式。通常是包含要从中返回最小值的值的列的名称。
  • %FOREACH(col-list) - 可选-列名或逗号分隔的列名列表。
  • %AFTERHAVING - 可选-应用HAVING子句中的条件。

MIN返回与表达式相同的数据类型。

描述

MIN聚合函数返回表达式的最小值(最小值)。通常,表达式是查询返回的多行中的字段名称(或包含一个或多个字段名称的表达式)。

MIN可以在引用表或视图的SELECT查询或子查询中使用。MIN可以出现在选择列表或HAVING子句中,与普通字段值一起出现。

MIN不能在WHERE子句中使用。除非SELECT是子查询,否则不能在联接的ON子句中使用MIN

与大多数其他聚合函数一样,min不能应用于流字段。尝试这样做会生成SQLCODE-37错误。

与大多数其他聚合函数不同,ALLDISTINCT关键字(包括MIN(DISTINCT BY(Col2)col1))在MIN中不执行任何操作。它们是为了与SQL-92兼容而提供的。

数据值

MIN使用的指定字段可以是数字或非数字。对于数字数据类型字段,最小值定义为数值中的最低值;因此-7低于-3。对于非数字数据类型字段,最小值定义为字符串整理顺序中的最低值;因此'-3'低于'-7'

空字符串(‘’)值被视为CHAR(0)

谓词使用为字段定义的排序规则类型。默认情况下,字符串数据类型字段使用SQLUPPER排序规则定义,该排序规则不区分大小写。

当字段定义的排序规则类型为SQLUPPER时,MIN将返回全部大写字母的字符串。因此,不管数据的原始字母是什么,SELECT MIN(Name)都会返回‘Aaron’。但是,因为比较是使用大写排序执行的,所以name=min(Name)子句选择名称值为'Aaron', 'AARON', and 'aaron'的行。

对于数值,返回的小数位数与表达式小数位数相同。

在派生最小聚合函数值时,数据字段中的空值将被忽略。如果查询没有返回任何行,或者返回的所有行的数据字段值为NULL,则MIN返回NULL

在当前事务期间所做的更改

与所有聚合函数一样,MIN始终返回数据的当前状态,包括未提交的更改,而不考虑当前事务的隔离级别。

示例

在下面的示例中,美元符号($)连接到工资金额。

以下查询返回Sample.Employee数据库中的最低(最低)工资:

SELECT '$' || MIN(Salary) AS LowSalary
     FROM Sample.Employee

下面的查询为每个州返回一行,每个州至少包含一名薪资大于75,000美元的员工。使用%AFTERHAVING关键字,每行返回大于75,000美元的最低员工工资。每行还返回该状态下所有员工的最低工资和最高工资:

SELECT Home_State,
       '$' || MIN(Salary %AFTERHAVING) AS MinSalaryAbove75K,
       '$' || MIN(Salary) AS MinSalary,
       '$' || MAX(Salary) AS MaxSalary
          FROM Sample.Employee
     GROUP BY Home_State
     HAVING Salary > 75000
     ORDER BY MinSalaryAbove75K

以下查询返回在Sample.Employee数据库中找到的排序规则序列中最小(最小)和最高(最大)的名称:

SELECT Name,MIN(Name),MAX(Name)
     FROM Sample.Employee

请注意,在比较之前,MINMAX会将NAME值转换为大写。

以下查询返回Sample.Employee数据库中Home_State‘VT’的员工的最低(最低)工资:

SELECT MIN(Salary)
     FROM Sample.Employee
     WHERE Home_State = 'VT'

以下查询返回Sample.Employee数据库中每个Home_State的员工数量和最低(最低)员工工资:

SELECT Home_State, 
     COUNT(Home_State) As NumEmployees, 
     MIN(Salary) As LowSalary
     FROM Sample.Employee
     GROUP BY Home_State
     ORDER BY LowSalary
0
0 259
文章 姚 鑫 · 十二月 28, 2021 3m read

第八章 SQL聚合函数 MAX

返回指定列中最大数据值的聚合函数。

大纲

MAX([ALL | DISTINCT [BY(col-list)]] expression [%FOREACH(col-list)] [%AFTERHAVING])

参数

  • ALL - 可选-将聚合函数应用于所有值。 ALLMAX返回的值没有影响。 它提供了SQL-92兼容性。
  • DISTINCT - 可选-一个DISTINCT子句,指定考虑每个惟一值。 DISTINCTMAX返回的值没有影响。 它提供了SQL-92兼容性。
  • expression - 任何有效的表达式。 通常是包含要返回的最大值的值的列的名称。
  • %FOREACH(col-list) - 可选-列名或以逗号分隔的列名列表。
  • %AFTERHAVING - 可选-应用在HAVING子句中的条件。

MAX返回与表达式相同的数据类型。

描述

MAX聚合函数返回表达式的最大值。 通常,表达式是查询返回的多行中字段的名称(或包含一个或多个字段名称的表达式)。

MAX可以在引用表或视图的SELECT查询或子查询中使用。 MAX可以在SELECT列表或HAVING子句中与普通字段值一起出现。

MAX不能在WHERE子句中使用。 MAX不能在JOINON子句中使用,除非SELECT是子查询。

与大多数其他聚合函数一样,MAX不能应用于流字段。 尝试这样做会产生一个SQLCODE -37错误。

与大多数其他聚合函数不同,ALLDISTINCT关键字,包括MAX(DISTINCT BY(col2) col1),在MAX中不执行任何操作。 它们是为了SQL-92的兼容性而提供的。

数据值

MAX使用的指定字段可以是数字或非数字。 对于数字数据类型字段,maximum被定义为数值中的最大值; 因此-3大于-7。 对于非数值型数据类型字段,maximum定义为字符串排序序列中的最大值; 因此'-7''-3'高。

一个空字符串 ('')值被视为CHAR(0)

谓词使用为字段定义的排序规则类型。 默认情况下,字符串数据类型字段是用SQLUPPER排序规则定义的,它不区分大小写。

当字段定义的排序类型为SQLUPPER时,MAX返回全大写字母的字符串。 因此,SELECT MAX(Name)返回'ZWIG',而不管数据的原始字母大小写。 但是因为比较是使用大写排序法执行的,所以HAVING Name=MAX(Name)子句选择的是Name值为 'Zwig', 'ZWIG', 'zwig'的行。

对于数值,返回的刻度与表达式刻度相同。

在派生MAX聚合函数值时,数据字段中的NULL值将被忽略。 如果查询没有返回行,或者返回的所有行的数据字段值为NULL,则MAX返回NULL

当前事务期间所做的更改

与所有聚合函数一样,MAX总是返回数据的当前状态,包括未提交的更改,而不考虑当前事务的隔离级别。

示例

以下查询返回Sample.Employee数据库中的最高(最高)工资:

SELECT '$' || MAX(Salary) As TopSalary
     FROM Sample.Employee

下面的查询为每个州返回一行,每个州至少包含一名薪水小于25,000美元的员工。使用%AFTERHAVING关键字,每行返回小于25,000美元的最高员工工资。每行还返回该状态下所有员工的最低工资和最高工资:

SELECT Home_State,
       '$' || MAX(Salary %AFTERHAVING) AS MaxSalaryBelow25K,
       '$' || MIN(Salary) AS MinSalary,
       '$' || MAX(Salary) AS MaxSalary
          FROM Sample.Employee
     GROUP BY Home_State
     HAVING Salary < 25000
     ORDER BY Home_State

以下查询返回在Sample.Employee数据库中找到的排序规则序列中最小(最小)和最高(最大)的名称:

SELECT Name,MIN(Name),MAX(Name)
     FROM Sample.Employee

请注意,在比较之前,MINMAX会将NAME值转换为大写。

以下查询返回Sample.Employee数据库中Home_State‘VT’的员工的最高(最高)工资:

SELECT MAX(Salary)
     FROM Sample.Employee
     WHERE Home_State = 'VT'

以下查询返回Sample.Employee数据库中每个Home_State的员工数量和最高(最高)员工工资:

SELECT Home_State, 
     COUNT(Home_State) As NumEmployees, 
     MAX(Salary) As TopSalary
     FROM Sample.Employee
     GROUP BY Home_State
     ORDER BY TopSalary
0
0 531
文章 姚 鑫 · 十二月 27, 2021 6m read

第七章 SQL聚合函数 LIST

创建逗号分隔值列表的聚合函数。

大纲

LIST([ALL | DISTINCT [BY(col-list)]] string-expr [%FOREACH(col-list)] [%AFTERHAVING])

参数

  • ALL - 可选-指定LIST返回string-expr的所有值的列表。 如果没有指定关键字,这是默认值。
  • DISTINCT - 可选-一个DISTINCT子句,指定LIST返回一个仅包含唯一的string-expr值的列表。 DISTINCT可以指定BY(colo -list)子句,其中colo -list可以是单个字段,也可以是用逗号分隔的字段列表。
  • string-expr - 计算结果为字符串的SQL表达式。 通常是所选表中列的名称。
  • %FOREACH(col-list) - 可选-列名或以逗号分隔的列名列表。
  • %AFTERHAVING - 可选-应用在HAVING子句中的条件。

描述

LIST聚合函数返回指定列中以逗号分隔的值列表。

一个简单的LIST(或LIST ALL)返回一个字符串,其中包含一个逗号分隔的列表,该列表由所选行中string-expr的所有值组成。 其中string-expr为空字符串(")的行由逗号分隔列表中的占位符逗号表示。 string-exprNULL的行不包含在逗号分隔的列表中。 如果只有一个string-expr值,并且是空字符串("),LIST返回空字符串。

LIST DISTINCT返回一个字符串,该字符串包含一个逗号分隔的列表,该列表由所选行中string-expr的所有不同(唯一)值组成:LIST(DISTINCT col1)NULLstring-expr不包含在逗号分隔的列表中。 LIST(DISTINCT BY(col2) col1)返回一个逗号分隔的列表,其中只包含那些col2值是不同(唯一的)的记录中的col1字段值。 但是请注意,不同的col2值可能包含一个单独的NULL值。

包含逗号的数据值

因为LIST使用逗号分隔string-expr值,所以LIST不应该用于包含逗号的数据值。 使用%DLISTJSON_ARRAYAGG代替。

LIST 和 %SelectMode

可以使用%SelectMode属性来指定LIST返回的数据显示模式:0=Logical(默认),1=ODBC, 2= display

注意,LIST用逗号分隔列值,而ODBC模式用逗号分隔%LIST列值中的元素。 因此,在%LIST结构上使用LIST时,使用ODBC模式会产生不明确的结果。

LIST 和 ORDER BY

LIST函数将多个行中的一个表列的值组合成一个逗号分隔的值列表。 因为在计算所有聚合字段之后,查询结果集中应用了一个ORDER BY子句,所以ORDER BY不能直接影响这个列表中的值序列。 在某些情况下,LIST结果可能会按顺序出现,但是不应该依赖这种顺序。 在给定聚合结果值中列出的值不能显式排序。

最大列表大小

允许的最大LIST返回值是最大字符串长度,3641,144个字符。

相关的聚合函数

  • LIST返回一个逗号分隔的值列表。
  • %DLIST返回一个包含每个值的元素的列表。
  • JSON_ARRAYAGG返回值的JSON数组。
  • XMLAGG返回一个串接的值字符串。

示例

下面的嵌入式SQL示例返回一个主机变量,该变量包含示例的Home_State列中列出的所有值的逗号分隔列表。 以字母A开头的人名表:

ClassMethod ListFunction()
{
	&sql(SELECT LIST(Home_State)
		INTO :statelist
		FROM Sample.Person
		WHERE Home_State %STARTSWITH 'A')
	w "The states are:",!,statelist
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).ListFunction()
The states are:
AR,AL,AZ,AZ,AZ,AR,AL,AZ,AR,AL,AL,AR

注意,这个列表包含重复的值。

下面的嵌入式SQL示例返回一个主机变量,该变量包含示例的Home_State列中列出的所有不同(唯一)值的逗号分隔列表。 以字母A开头的人名表:

ClassMethod ListFunction1()
{
	&sql(SELECT LIST(DISTINCT Home_State)
		INTO :statelist
		FROM Sample.Person
		WHERE Home_State %STARTSWITH 'A')
	w "The distinct states are:",!,statelist
}
DHC-APP> d ##class(PHA.TEST.SQLCommand).ListFunction1()
The distinct states are:
AR,AL,AZ

下面的SQL示例为每个州创建了一个逗号分隔的列表,其中包含在Home_City列中找到的所有值,以及按州列出的这些城市值的计数。 每个Home_State行包含该状态的所有Home_City值的列表。 这些名单可能包括重复的城市名称:

SELECT Home_State,
       COUNT(Home_City) AS CityCount,
       LIST(Home_City) AS ListAllCities
FROM Sample.Person
GROUP BY Home_State

也许更有用的方法是在Home_City列中列出每个州的不同值,用逗号分隔,如下所示:

SELECT Home_State,
       COUNT(DISTINCT Home_City) AS DistCityCount,
       COUNT(Home_City) AS TotCityCount,
       LIST(DISTINCT Home_City) AS DistCitiesList
FROM Sample.Person
GROUP BY Home_State

注意,这个示例返回每个州的不同城市名称和总城市名称的整数计数。

下面的示例返回以“A”开头的Home_State值列表。 它返回不同的Home_State值(distinct Home_State); 与不同的Home_City值(distinct BY(Home_City) Home_State)相对应的Home_State值,这可能包括一个唯一的Home_City NULL; 和所有Home_State值:

SELECT LIST(DISTINCT Home_State) AS DistStates,
       LIST(DISTINCT BY(Home_City) Home_State) AS DistCityStates,
       LIST(Home_State) AS AllStates
FROM Sample.Person
WHERE Home_State %STARTSWITH 'A'   

下面的动态SQL示例使用%SelectMode属性为DOB日期字段返回的值列表指定ODBC显示模式:

ClassMethod ListFunction2()
{
	s myquery = "SELECT LIST(DOB) AS DOBs FROM Sample.Person WHERE Name %STARTSWITH 'A'"
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).ListFunction2()
DOBs
1973-06-17,1943-05-22,1943-04-21,2011-07-07,1993-10-05,1953-02-25,1968-11-18
 
1 Rows(s) Affected
End of data

下面的动态SQL示例使用%FOREACH关键字。 它为每个不同的Home_State返回一行,其中包含该Home_State的年龄值列表:

ClassMethod ListFunction3()
{
	s myquery = 3
	s myquery(1) = "SELECT DISTINCT Home_State,"
	s myquery(2) = "LIST(Age %FOREACH(Home_State)) AgesForState "
	s myquery(3) = "FROM Sample.Person WHERE Home_State %STARTSWITH 'M'"
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(.myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).ListFunction3()
Home_State      AgesForState
MA      55
MD      10,36,31,85,10,94,28
ME      25,20,55,11
MI      11,75,46,17,71
MN      11,43,73,98
MO      77,33,42,55,89,26,87,45,34
MS      7,25,13
MT      4,35,54,6,23
 
8 Rows(s) Affected
End of data

下面的示例使用了%AFTERHAVING关键字。 它为每个Home_State返回一行,其中至少包含一个满足HAVING子句条件的Name值(以“M”开头的名称)。 第一个LIST函数返回该状态的所有名称的列表。 第二个LIST函数返回的列表只包含满足HAVING子句条件的名称:

SELECT Home_State,
       LIST(Name) AS AllNames,
       LIST(Name %AFTERHAVING) AS HavingClauseNames
    FROM Sample.Person
    GROUP BY Home_State
    HAVING Name LIKE 'M%'
    ORDER BY Home_State
0
0 178
文章 姚 鑫 · 十二月 26, 2021 6m read

第六章 SQL聚合函数 JSON_ARRAYAGG

创建JSON格式值数组的聚合函数。

注:IRIS可用,IRIS之前版本不可用。

大纲

JSON_ARRAYAGG([ALL | DISTINCT [BY(col-list)]] string-expr [%FOREACH(col-list)] [%AFTERHAVING])

参数

  • ALL - 可选-指定JSON_ARRAYAGG返回一个JSON数组,其中包含string-expr的所有值。 如果没有指定关键字,这是默认值。
  • DISTINCT - 可选-一个DISTINCT子句,指定JSON_ARRAYAGG返回一个仅包含唯一字符串expr值的JSON数组。 DISTINCT可以指定BY(colo -list)子句,其中colo -list可以是单个字段,也可以是用逗号分隔的字段列表。
  • string-expr - 计算结果为字符串的SQL表达式。 通常是所选表中列的名称。
  • %FOREACH(col-list) - 可选-列名或以逗号分隔的列名列表。
  • %AFTERHAVING - 可选-应用在HAVING子句中的条件。

描述

JSON_ARRAYAGG聚合函数返回指定列中值的JSON格式数组。

一个简单的JSON_ARRAYAGG(或JSON_ARRAYAGG ALL)返回一个JSON数组,其中包含所选行中string-expr的所有值。 字符串-expr为空字符串(")的行由数组中的(" u0000")表示。 字符串-expr为NULL的行不包含在数组中。 如果只有一个字符串-expr值,并且是空字符串("),JSON_ARRAYAGG将返回JSON数组["\u0000"]。 如果所有的string-expr值为NULL, JSON_ARRAYAGG返回一个空的JSON数组[]

JSON_ARRAYAGG DISTINCT返回一个JSON数组,由所选行中string-expr的所有不同(唯一)值组成:JSON_ARRAYAGG(DISTINCT col1)NULL字符串-expr不包含在JSON数组中。 JSON_ARRAYAGG(DISTINCT BY(col2) col1)返回一个JSON数组,该数组只包含记录中col2值是不同的(唯一的)的那些col1字段值。 但是请注意,不同的col2值可能包含一个单独的NULL值。

JSON_ARRAYAGGstring-expr不能是流字段。 指定流字段的结果是SQLCODE -37

包含转义字符的数据值

  • 双引号:如果一个string-expr值包含一个双引号字符("),JSON_ARRAYAGG使用字面转义序列\"来表示这个字符。
  • 反斜杠:如果string-expr值包含反斜杠字符(\),则JSON_ARRAYAGG使用文字转义序列\\表示该字符。
  • 单引号:当string-expr值包含一个单引号作为文字字符时, SQL要求必须将此字符作为两个单引号字符(''进行双倍转义。JSON_ARRAYAGG将此字符表示为单引号字符‘。

最大JSON数组大小

默认的JSON_ARRAYAGG返回类型是VARCHAR(8192)。 这个长度包括JSON数组格式化字符以及字段数据字符。 如果预期返回的值将需要大于8192,可以使用CAST函数指定一个更大的返回值。 例如CAST(JSON_ARRAYAGG(value)) AS VARCHAR(12000))。 如果实际返回的JSON数组长于JSON_ARRAYAGG返回类型长度,IRIS将在返回类型长度处截断JSON数组,而不会发出错误。 因为截断JSON数组会删除其关闭的]字符,这使得返回值无效。

JSON_ARRAYAGG 和 %SelectMode

可以使用%SelectMode属性为JSON数组中的元素指定数据显示值:0=Logical(默认值),1=ODBC, 2= display。 如果string-expr包含一个%List结构,则元素以ODBC模式表示,用逗号分隔,在逻辑和显示模式中以%List格式字符表示,用\转义序列表示。

JSON_ARRAYAGG和ORDER BY

JSON_ARRAYAGG函数将表中多行列的值组合成一个包含元素值的JSON数组。 因为在计算所有聚合字段之后,查询结果集中应用了一个ORDER BY子句,所以ORDER BY不能直接影响这个列表中的值序列。 在某些情况下,JSON_ARRAYAGG结果可能是按顺序出现的,但是不应该依赖于这种顺序。 在给定聚合结果值中列出的值不能显式排序。

相关的聚合函数

  • LIST返回一个逗号分隔的值列表。
  • %DLIST返回一个包含每个值的元素的IRIS列表。
  • XMLAGG返回一个串接的值字符串。

示例

下面的嵌入式SQL示例返回一个主机变量,该变量包含示例的Home_State列中所有值的JSON数组。 以字母A开头的人名表:

SELECT JSON_ARRAYAGG(Home_State)
			INTO :statearray
			FROM Sample.Person
			WHERE Home_State %STARTSWITH 'A'

SELECT JSON_ARRAYAGG(CTLOC_Desc) FROM CT_Loc

注意,这个JSON数组包含重复的值。

下面的动态SQL示例返回一个主机变量,该变量包含样本的Home_State列中所有不同(唯一)值的JSON数组。 以字母A开头的人名表:

ClassMethod JsonArrayagg()
{
	s myquery = 2
	s myquery(1) = "SELECT JSON_ARRAYAGG(DISTINCT Home_State) AS DistinctStates "
	s myquery(2) = "FROM Sample.Person WHERE Home_State %STARTSWITH 'A'"
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(.myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}

下面的SQL示例为每个州创建了一个JSON数组,其中包含在Home_City列中找到的所有值,以及按州列出的这些城市值的计数。 每个Home_State行包含该状态的所有Home_City值的JSON数组。 这些JSON数组可能包含重复的城市名称:

SELECT Home_State,
       COUNT(Home_City) AS CityCount,
       JSON_ARRAYAGG(Home_City) AS ArrayAllCities 
FROM Sample.Person
GROUP BY Home_State

更有用的是一个JSON数组的所有不同的值,发现在Home_City列为每个州,如下所示的动态SQL示例:

ClassMethod JsonArrayagg1()
{
	s myquery = 4
	s myquery(1) = "SELECT Home_State,COUNT(DISTINCT Home_City) AS DistCityCount,"
	s myquery(2) = "COUNT(Home_City) AS TotCityCount,"
	s myquery(3) = "JSON_ARRAYAGG(DISTINCT Home_City) AS ArrayDistCities "
	s myquery(4) = "FROM Sample.Person GROUP BY Home_State"
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(.myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}

注意,这个示例返回每个州的不同城市名称和总城市名称的整数计数。

下面的动态SQL示例使用%SelectMode属性为DOB日期字段返回的JSON值数组指定ODBC显示模式:

ClassMethod JsonArrayagg2()
{
	s myquery = 2
	s myquery(1) = "SELECT JSON_ARRAYAGG(DOB) AS DOBs "
	s myquery(2) = "FROM Sample.Person WHERE Name %STARTSWITH 'A'"
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(.myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}

下面的动态SQL示例使用%FOREACH关键字。 它为每个不同的Home_State返回一行,其中包含该Home_State的年龄值的JSON数组。

ClassMethod JsonArrayagg3()
{
	s myquery = 3
	s myquery(1) = "SELECT DISTINCT Home_State,"
	s myquery(2) = "JSON_ARRAYAGG(Age %FOREACH(Home_State)) AgesForState "
	s myquery(3) = "FROM Sample.Person WHERE Home_State %STARTSWITH 'M'"
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(.myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}

下面的动态SQL示例使用%AFTERHAVING关键字。 它为每个Home_State返回一行,其中至少包含一个满足HAVING子句条件的Name值(以“M”开头的名称)。 第一个JSON_ARRAYAGG函数返回一个包含该状态所有名称的JSON数组。 第二个JSON_ARRAYAGG函数返回的JSON数组只包含满足HAVING子句条件的名称:

ClassMethod JsonArrayagg4()
{
	s myquery = 4
	s myquery(1) = "SELECT Home_State,JSON_ARRAYAGG(Name) AS AllNames,"
	s myquery(2) = "JSON_ARRAYAGG(Name %AFTERHAVING) AS HavingClauseNames "
	s myquery(3) = "FROM Sample.Person GROUP BY Home_State "
	s myquery(4) = "HAVING Name LIKE 'M%' ORDER BY Home_State"
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(.myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
0
0 392
文章 姚 鑫 · 十二月 25, 2021 5m read

第五章 SQL聚合函数 %DLIST

创建值列表的聚合函数。

大纲

%DLIST([ALL | DISTINCT [BY(col-list)]] string-expr [%FOREACH(col-list)] [%AFTERHAVING])

参数

  • ALL - 可选-指定%DLIST返回string-expr的所有值的列表。如果未指定关键字,则这是默认值。
  • DISTINCT - 可选- DISTINCT子句,指定%DLIST返回一个结构化的%List,其中只包含唯一的string-expr值。 DISTINCT可以指定BY(colo -list)子句,其中colo -list可以是单个字段,也可以是用逗号分隔的字段列表。
  • string-expr - 计算结果为字符串的SQL表达式。 通常是所选表中列的名称。
  • %FOREACH(col-list) - 可选-列名或以逗号分隔的列名列表。
  • %AFTERHAVING - 可选-应用在HAVING子句中的条件。

描述

%DLIST聚合函数返回一个ObjectScript %List结构,其中包含指定列中的值作为列表元素。

一个简单的%DLIST(或%DLIST ALL)返回列表,该列表由所选行中string-expr的所有非null值组成。 string-exprNULL的行不会作为元素包含在列表结构中。

%DLIST DISTINCT返回一个列表,由所选行中string-expr的所有不同(唯一)非null值组成:%DLIST(DISTINCT col1)NULL不作为元素包含在%List结构中。 %DLIST(DISTINCT BY(col2) col1)返回一个元素的%List,其中只包含那些col1字段值在col2值不同(唯一)的记录中。 但是请注意,不同的col2值可能包含一个单独的NULL值。

%DLIST 和 %SelectMode

可以使用%SelectMode属性来指定%DLIST返回的数据显示模式:0=Logical(默认)1=ODBC, 2= display

请注意,在ODBC模式下,%DLIST用逗号分隔列值列表,而$LISTTOSTRING(默认情况下)返回%List列值中用逗号分隔的元素。

%DLIST和ORDER BY

%DLIST函数将表中多行列的值组合成%List结构的值列表。 因为在计算所有聚合字段之后,查询结果集中应用了一个ORDER BY子句,所以ORDER BY不能直接影响这个列表中的值序列。 在某些情况下,%DLIST结果可能会按顺序出现,但不应依赖此顺序。 在给定聚合结果值中列出的值不能显式排序。

相关的聚合函数

  • %DLIST返回一个IRIS列表的值。
  • LIST返回一个逗号分隔的值列表。
  • JSON_ARRAYAGG返回值的JSON数组。
  • XMLAGG返回一个串接的值字符串。

示例

下面的嵌入式SQL示例返回一个主机变量,该变量包含示例的Home_State列中列出的所有值的IRIS列表。 以字母A开头的人名表:

ClassMethod DList()
{
	&sql(
		SELECT %DLIST(Home_State)
			INTO :statelist
			FROM Sample.Person
			WHERE Home_State %STARTSWITH 'A')
	w "The states (as list):",statelist,!
	w "The states (as string):",$LISTTOSTRING(statelist,"^")
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).DList()
The states (as list):ARALAZAZAZARALAZARALALAR
The states (as string):AR^AL^AZ^AZ^AZ^AR^AL^AZ^AR^AL^AL^AR

请注意,这个IRIS列表包含具有重复值的元素。

下面的嵌入式SQL示例返回一个主机变量,该变量包含示例的Home_State列中列出的所有不同(唯一)值的IRIS列表。 以字母A开头的人名表:

ClassMethod DList1()
{
	&sql(
		SELECT %DLIST(DISTINCT Home_State)
			INTO :statelist
			FROM Sample.Person
			WHERE Home_State %STARTSWITH 'A')
	w "The states (as list):",statelist,!
	w "The states (as string):",$LISTTOSTRING(statelist,"^")
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).DList1()
The states (as list):ARALAZ
The states (as string):AR^AL^AZ

下面的SQL示例为每个州创建了一个 IRIS列表,其中包含在Home_City列中找到的所有值,以及按州列出的这些城市值的计数。 每个Home_State行包含该状态的所有Home_City值的列表。 这些名单可能包括重复的城市名称:

SELECT Home_State,
       %DLIST(Home_City) AS AllCities,
       COUNT(Home_City) AS CityCount
FROM Sample.Person
GROUP BY Home_State

也许更有用的方法是在Home_City列中列出每个州的所有不同值,如下例所示:

SELECT Home_State,
       %DLIST(DISTINCT Home_City) AS CitiesList,
       COUNT(DISTINCT Home_City) AS DistinctCities,
       COUNT(Home_City) AS TotalCities
FROM Sample.Person
GROUP BY Home_State

注意,这个示例返回每个州的不同城市名称和总城市名称的整数计数。

下面的例子返回以“A”开头的Home_State值的%List结构。 它以%List元素形式返回不同的Home_State值(distinct Home_State); 与不同的Home_City值(distinct BY(Home_City) Home_State)相对应的Home_State值,这可能包括一个唯一的Home_City NULL; 和所有Home_State值:

SELECT %DLIST(DISTINCT Home_State) AS DistStates,
       %DLIST(DISTINCT BY(Home_City) Home_State) AS DistCityStates,
       %DLIST(Home_State) AS AllStates
FROM Sample.Person
WHERE Home_State %STARTSWITH 'A'   

下面的动态SQL示例使用%SelectMode属性为%List结构FavoriteColors日期字段指定ODBC显示模式。 ODBC模式将每个列的值作为一个逗号分隔的列表返回,$LISTTOSTRING函数指定一个不同的分隔符(在这个例子中是||)来分隔不同列的值:

ClassMethod DList2()
{
	s myquery = "SELECT %DLIST(FavoriteColors) AS colors FROM Sample.Person WHERE Name %STARTSWITH 'A'"
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	while rset.%Next() {
		w $LISTTOSTRING(rset.colors,"||"),!
	}
	w !,"End of data"
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).DList2()
Orange,White||Red,White||Red||Blue||Green||Blue
 
End of data

下面的示例使用了%AFTERHAVING关键字。 它为每个Home_State返回一行,其中至少包含一个满足HAVING子句条件的Name值(以“M”开头的名称)。 第一个%DLIST函数返回该状态的所有名称的列表。 第二个%DLIST函数返回的列表只包含满足HAVING子句条件的名称:

SELECT Home_State,
       %DLIST(Name) AS AllNames,
       %DLIST(Name %AFTERHAVING) AS HaveClauseNames
    FROM Sample.Person
    GROUP BY Home_State
    HAVING Name LIKE 'M%'
    ORDER BY Home_state
0
0 119
文章 姚 鑫 · 十二月 24, 2021 4m read

第四章 SQL聚合函数 COUNT(二)

权限

要使用COUNT(*),必须对指定的表具有表级别的SELECT权限。 要使用COUNT(column-name),必须对指定的列具有列级的SELECT权限,或者对指定的表具有表级的SELECT权限。 可以通过调用%CHECKPRIV命令来确定当前用户是否具有SELECT权限。 可以通过调用$SYSTEM.SQL.Security.CheckPrivilege()方法来确定指定的用户是否具有表级SELECT权限。

性能

为了获得最优的COUNT性能,你应该按照以下方式定义索引:

  • 对于COUNT(*),如果需要,定义位图扩展索引。 这个索引可能是在创建表时自动定义的。
  • 对于COUNT(fieldname),为指定字段定义一个位片索引。 查询计划优化COUNT(fieldname)自动应用默认的排序规则到fieldname

未提交事务所做的更改

与所有聚合函数一样,COUNT总是返回数据的当前状态,包括未提交的更改,而不管当前事务的隔离级别如何,如下所示:

  • COUNT插入和更新的记录的计数,即使这些更改尚未提交并可能回滚。
  • COUNT不计算已删除的记录,即使这些删除还没有提交并且可以回滚。

示例

下面的示例返回Sample.Person中的总行数:

SELECT COUNT(*) AS TotalPersons
     FROM Sample.Person

下面的示例返回Sample.Person中的姓名、配偶和最喜欢的颜色的计数。这些计数不同,因为有些配偶和FavoriteColors字段为NULLCount不计算NULL

SELECT COUNT(Name) AS People,
       COUNT(Spouse) AS PeopleWithSpouses,
       COUNT(FavoriteColors) AS PeopleWithColorPref
FROM Sample.Person

下面的示例返回三个值:总行数、FavoriteColors字段中的非空值总数和FavoriteColors字段中不同的非空值的总数:

SELECT COUNT(*) As TotalPersons,
       COUNT(FavoriteColors) AS WithColorPref,
       COUNT(DISTINCT FavoriteColors) AS ColorPrefs
       FROM Sample.Person

下面的示例使用Count DISTINCT返回Sample.Person中不同FavoriteColors值的计数。(FavoriteColors包含多个数据值和多个Null。)。此示例还使用DISTINCT子句为每个不同的FavoriteColors值返回一行。行计数比COUNT(DISTINCT FavoriteColors)计数大1,因为DISTINCT返回单个NULL的行作为DISTINCT值,但COUNT DISTINCT不计算NULLCOUNT(DISTINCT BY(FavoriteColors)%ID)值与行计数相同,因为BY子句将单个NULL计数为DISTINCT值:

SELECT DISTINCT FavoriteColors,
       COUNT(DISTINCT FavoriteColors) AS DistColors,
       COUNT(DISTINCT BY(FavoriteColors) %ID) AS DistColorPeople
FROM Sample.Person

下面的例子使用GROUP BY为每个FavoriteColors值返回一行,包括一行NULL。与每行关联的是两个计数。第一个用FavoriteColors选项计算数字或记录;不计算空记录。第二个计算与每个favoritecor选择关联的名称数量;由于Name不包含空值,因此可以使用空值来计算有利颜色的数量:

SELECT FavoriteColors,
       COUNT(FavoriteColors) AS ColorPreference,
       COUNT(Name) AS People
       FROM Sample.Person
       GROUP BY FavoriteColors

以下示例返回Sample.Person中每个Home_State值的Person记录计数:

SELECT Home_State, COUNT(*) AS AllPersons
     FROM Sample.Person
     GROUP BY Home_State

以下示例使用%AFTERHAVING返回至少有一个人超过65岁的每个州的个人记录计数和超过65人的人数计数:

SELECT Home_State, COUNT(Name) AS AllPersons,
     COUNT(Name %AFTERHAVING) AS Seniors
     FROM Sample.Person
     GROUP BY Home_State
     HAVING Age > 65
     ORDER BY Home_State

以下示例同时使用%FOREACH%AFTERHAVING关键字。它为姓名以“A”“M”“W”(HAVING子句和GROUP BY子句)开头的人员所在的州返回一行。每个状态行包含下列值:

  • Count(Name):数据库中所有人员的计数。(此数字对于所有行都是相同的。)
  • COUNT(Name %FOREACH(Home_State)):该州所有人的计数。
  • COUNT(Name %AFTERHAVING):数据库中符合HAVING子句条件的所有人员的计数。(此数字对于所有行都是相同的。)
  • COUNT(Name %FOREACH(Home_State) %AFTERHAVING): 该州符合HAVING子句标准的所有人员的计数。
SELECT Home_State,
       COUNT(Name) AS NameCount,
       COUNT(Name %FOREACH(Home_State)) AS StateNameCount,
       COUNT(Name %AFTERHAVING) AS NameCountHaving,
       COUNT(Name %FOREACH(Home_State) %AFTERHAVING) AS StateNameCountHaving
FROM Sample.Person
GROUP BY Home_State
HAVING Name LIKE 'A%' OR Name LIKE 'M%' OR Name LIKE 'W%'
ORDER BY Home_State

下面的示例显示具有串联表达式的Count。它使用连接运算符(||)返回FavoriteColors字段中非空值的总数,以及FavoriteColors中与其他两个字段连接的非空值的总数:

SELECT COUNT(FavoriteColors) AS Color,
       COUNT(FavoriteColors||Home_State) AS ColorState,
       COUNT(FavoriteColors||Spouse) AS ColorSpouse
       FROM Sample.Person

当两个字段连接在一起时,COUNT只计算其中两个字段都没有空值的那些行。因为Sample.Person中的每一行都有一个非空的Home_State值,所以串联FavoriteColors||Home_State返回与FavoriteColors相同的计数。由于Sample.Person中的某些行的配偶值为NULL,因此串联FavoriteColors||SPOSPORT将返回FavoriteColors和配偶的值均为非NULL值的行数。

0
0 97
文章 姚 鑫 · 十二月 23, 2021 5m read

第三章 SQL聚合函数 COUNT(一)

返回表或指定列中的行数的聚合函数。

大纲

COUNT(*)

COUNT([ALL | DISTINCT [BY(col-list)]] expression [%FOREACH(col-list)] [%AFTERHAVING])

参数

  • * - 指定应计算所有行以返回指定表中的总行数。 COUNT(*)不接受其他参数,不能与ALLDISTINCT关键字一起使用。 COUNT(*)不接受表达式参数,也不使用任何特定列的信息。 COUNT(*)返回指定表或视图中的行数,但不消除重复项。 它分别计数每一行,包括包含NULL值的行。
  • ALL - 可选-指定COUNT返回表达式中所有值的计数。 如果没有指定关键字,这是默认值。
  • DISTINCT - 可选-一个DISTINCT子句,指定COUNT返回表达式的不同(唯一)值的计数。 不能与流字段一起使用。 DISTINCT可以指定BY(colo -list)子句,其中colo -list可以是单个列名,也可以是用逗号分隔的列名列表。
  • expression - 任何有效的表达式。 通常是包含要计算的数据值的列的名称。
  • %FOREACH(col-list) - 可选-列名或以逗号分隔的列名列表。
  • %AFTERHAVING - 可选-应用在HAVING子句中的条件。

COUNT返回BIGINT数据类型。

描述

COUNT聚合函数有两种形式:

  • COUNT(expression)以整数形式返回表达式中值的数目的计数。 通常,表达式是查询返回的多行中字段的名称(或包含一个或多个字段名称的表达式)。 COUNT(表达式)不计算NULL值。 它可以选择计数或不计数重复的字段值。 COUNT总是返回数据类型BIGINT,xDBC长度为8,精度为19,刻度为0
  • COUNT(*)以整数形式返回表中行数的计数。 COUNT(*)计数所有行,无论是否存在重复的字段值或NULL值。

COUNT可以在引用表或视图的SELECT查询或子查询中使用。 COUNT可以在SELECT列表或HAVING子句中与普通字段值一起出现。

COUNT不能用于WHERE子句。 COUNT不能在JOINON子句中使用,除非SELECT是子查询。

与所有聚合函数一样,COUNT(expression)可以接受一个可选的DISTINCT子句。 DISTINCT子句只计算那些具有不同(唯一)值的列。 什么是一个不同的值取决于字段的排序; 当字段具有默认的排序规则%SQLUPPER时,字母大小写不同的值将不作为不同的值计算。 要将每个字母大小写变量作为一个不同的值进行计数,请使用count (distinct (%EXACT(field)))COUNT DISTINCT不将NULL视为一个不同的值。 COUNT(DISTINCT BY(col2) col1)计数不同的col2值的col1值; 但是,不同的col2值可以包含一个NULL作为不同的值。

ALL关键字统计所有非null值,包括所有重复值。 如果没有指定关键字,ALL是默认行为。

没有行返回

如果没有选择行,COUNT返回0NULL,这取决于查询:

  • 如果除了提供给聚合函数的字段之外,选择列表不包含对FROM子句表中的字段的任何引用,那么COUNT返回0。 只有COUNT聚合函数返回0; 其他聚合函数返回NULL。 该查询返回%ROWCOUNT1。 如下示例所示:
ClassMethod Count()
{
	s myquery = 3
	s myquery(1) = "SELECT COUNT(*) AS Recs,COUNT(Name) AS People,"
	s myquery(2) = "AVG(Age) AS AvgAge,MAX(Age) AS MaxAge,CURRENT_TIMESTAMP AS Now"
	s myquery(3) = " FROM Sample.Employee WHERE Name %STARTSWITH 'ZZZ'"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(.myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"Rowcount:",rset.%ROWCOUNT
}
DHC-APP> d ##class(PHA.TEST.SQLCommand).Count()
Recs    People  AvgAge  MaxAge  Now
0       0                       2021-12-20 20:58:17
 
1 Rows(s) Affected
Rowcount:1
  • 如果select-list包含对FROM子句表中某个字段的任何直接引用,或者如果指定了TOP 0,那么COUNT返回NULL。 该查询返回%ROWCOUNT0。 以下示例不返回COUNT值,因为%ROWCOUNT值为0:
ClassMethod Count1()
{
	s myquery = 2
	s myquery(1) = "SELECT COUNT(*) AS Recs,COUNT(Name) AS People,$LENGTH(Name) AS NameLen"
	s myquery(2) = " FROM Sample.Employee WHERE Name %STARTSWITH 'ZZZ'"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(.myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"Rowcount:",rset.%ROWCOUNT
}
DHC-APP> d ##class(PHA.TEST.SQLCommand).Count1()
Recs    People  NameLen
 
0 Rows(s) Affected
Rowcount:0
  • 如果没有指定表,COUNT(*)返回1。 该查询返回%ROWCOUNT为1。 如下示例所示:
ClassMethod Count2()
{
	s myquery = "SELECT COUNT(*) AS Recs"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"Rowcount:",rset.%ROWCOUNT
}

DHC-APP> d ##class(PHA.TEST.SQLCommand).Count2()
Recs
1
 
1 Rows(s) Affected
Rowcount:1

流字段

可以使用COUNT(表达式)来计数流字段值,但有一些限制。 COUNT(streamfield)计算所有非null值。 它不会检查重复的值。

expression是一个流字段时,不能指定COUNT函数的DISTINCT关键字。 试图在流字段中使用DISTINCT关键字会导致SQLCODE -37错误。

不能在%FOREACH冒号列表中指定流字段。 尝试这样做会导致SQLCODE -37错误。

下面的例子显示了COUNT函数的有效使用,其中Title是字符串字段,NotesPicture是流字段:

SELECT DISTINCT Title,COUNT(Notes),COUNT(Picture %FOREACH(Title))
FROM Sample.Employee

Title为字符串字段,NotesPicture为流字段时,以下示例无效:

-- Invalid: DISTINCT keyword with stream field
SELECT Title,COUNT(DISTINCT Notes) FROM Sample.Employee
-- Invalid: %FOREACH col-list contains stream field
SELECT Title,COUNT(Notes %FOREACH(Picture))
FROM Sample.Employee
0
0 625
文章 姚 鑫 · 十二月 22, 2021 6m read

第二章 SQL聚合函数 AVG

返回指定列值的平均值的聚合函数。

大纲

AVG([ALL | DISTINCT [BY(col-list)]] expression [%FOREACH(col-list)] [%AFTERHAVING])

参数

  • ALL - 可选-指定AVG返回表达式所有值的平均值。 如果没有指定关键字,则为默认值。
  • DISTINCT - 可选 - DISTINCT子句,指定AVG只计算一个值的唯一实例的平均值。 DISTINCT可以指定BY(col-list)子句,其中col-list可以是单个字段,也可以是逗号分隔的字段列表。
  • expression - 任何有效的表达式。 通常是包含要取平均值的数据值的列的名称。
  • %FOREACH(col-list) - 可选—列名或以逗号分隔的列名列表。
  • %AFTERHAVING - 可选 - 应用在HAVING子句中找到的条件。

AVG返回NUMERICDOUBLE数据类型。 如果expressionDOUBLE类型,AVG返回DOUBLE; 否则,它返回NUMERIC

描述

AVG聚合函数返回表达式值的平均值。 通常,表达式是查询返回的多行中字段的名称(或包含一个或多个字段名称的表达式)。

AVG可以用于引用表或视图的SELECT查询或子查询。 AVG可以出现在SELECT列表或HAVING子句中,与普通字段值一起出现。

AVG不能在WHERE子句中使用。 AVG不能在JOINON子句中使用,除非SELECT是子查询。

像所有聚合函数一样,AVG可以带有一个可选的DISTINCT子句。 AVG(DISTINCT col1)仅对不同(唯一)的col1字段值进行平均。 AVG(DISTINCT BY(col2) col1)仅对col2值不同(唯一)的记录中的col1字段值进行平均值。 但是请注意,不同的col2值可能包含一个单独的NULL值。

数据值

对于非double表达式值,AVG返回双精度浮点数。 AVG返回的值的精度是18。 返回值的比例取决于表达式的精度和比例:AVG返回值的比例等于18减去表达式的精度,加上表达式的比例(as=ap-ep+es)

对于DOUBLE表达式值,精度为0。

AVG通常应用于具有数值值的字段或表达式,例如数字字段或日期字段。 默认情况下,聚合函数使用逻辑(内部)数据值,而不是Display值。 因为没有执行类型检查,所以可以(尽管很少有意义)对非数字字段调用类型检查; AVG计算非数值,包括空字符串(")为零(0)。如果expression是数据类型VARCHAR,则返回值为数据类型DOUBLE

在导出AVG聚合函数值时,数据字段中的NULL值将被忽略。 如果查询没有返回行,或者返回的所有行的数据字段值为NULL, AVG返回NULL

对单个值求平均值

如果提供给AVG的所有表达式值都是相同的,那么结果的平均值取决于访问表中的行数(除数)。 例如,如果表中的所有行对某个特定列具有相同的值,那么该列的平均值就是一个计算值,它可能与个别列中的值略有不同。 为了避免这种差异,可以使用DISTINCT关键字。

下面的例子展示了计算平均值如何产生轻微的不平等。 第一个查询不引用表行,所以AVG通过除以1进行计算。 第二个查询引用表的行,因此AVG通过除以表中的行数进行计算。 第三个查询引用了表行,但是平均了单个值的DISTINCT值; 在这种情况下,AVG计算除以1

ClassMethod Avg()
{
	s pi = $ZPI
	&sql(SELECT :pi,AVG(:pi) INTO :p,:av FROM Sample.Person)
	w p," pi的值",!
	w av," avg of pi/1",!
	&sql(SELECT Name,:pi,AVG(:pi) INTO :n,:p,:av FROM Sample.Person)
	w av," avg calculated using numrows",!
	&sql(SELECT Name,:pi,AVG(DISTINCT :pi) INTO :n,:p,:av FROM Sample.Person)
	w av," avg of pi/1"
}

3.141592653589793238 pi的值
3.141592653589793238 avg of pi/1
3.141592653589793206 avg calculated using numrows
3.141592653589793206 avg of pi/1

优化

SQL优化AVG计算可以使用位片索引,如果这个索引是为字段定义的。

当前事务期间所做的更改

与所有聚合函数一样,无论当前事务的隔离级别如何,AVG总是返回数据的当前状态,包括未提交的更改。

示例

下面的查询列出了Sample中所有员工的平均工资。 员工的数据库。 因为查询返回的所有行对于这个平均值具有相同的值,所以该查询只返回一行,其中包含平均工资。 为了显示目的,该查询将一个美元符号连接到值(使用||操作符),并使用AS子句标记列:

SELECT '$' || AVG(Salary) AS AverageSalary
     FROM Sample.Employee

下面的查询列出了每个州的员工的平均工资:

SELECT Home_State,'$' || AVG(Salary) AS AverageSalary
     FROM Sample.Employee
GROUP BY Home_State

下面的查询列出了那些工资大于平均工资的员工的姓名和工资。 它还列出了所有员工的平均工资; 这个值对于查询返回的所有行都是相同的:

SELECT Name,Salary,
       '$' || AVG(Salary) AS AverageAllSalary
FROM Sample.Employee
HAVING Salary>AVG(Salary)
ORDER BY Salary

下面的查询列出了那些工资大于平均工资的员工的姓名和工资。 它还列出了高于平均水平的员工的平均工资; 这个值对于查询返回的所有行都是相同的:

SELECT Name,Salary,
       '$' || AVG(Salary %AFTERHAVING) AS AverageHighSalary
FROM Sample.Employee
HAVING Salary>AVG(Salary)
ORDER BY Salary

以下查询列出了那些包含三名以上员工的州,这些员工的平均工资为该州员工的平均工资,以及该州收入超过20,000美元的员工的平均工资:

SELECT Home_State,
       '$' || AVG(Salary) AS AvgStateSalary,
       '$' || AVG(Salary %AFTERHAVING) AS AvgLargerSalaries
FROM Sample.Employee
GROUP BY Home_State
HAVING COUNT(*) > 3 AND Salary > 20000
ORDER BY Home_State

以下查询使用DISTINCT子句的几种形式。AVG(DISTINCT BY COLLIST)示例可以在平均值中包括附加的年龄值,因为如果Home_City包含一个或多个Null,则BY子句可以包括单个NULL作为DISTINCT值:

SELECT AVG(Age) AS AveAge,AVG(ALL Age) AS Synonym,
       AVG(DISTINCT Age) AS AveDistAge,
       AVG(DISTINCT BY(Home_City) Age) AS AvgAgeDistCity,
       AVG(DISTINCT BY(Home_City,Home_State) Age) AS AvgAgeDistCityState
     FROM Sample.Person

以下查询同时使用%FOREACH%AFTERHAVING关键字。它为那些包含姓名以AMW (HAVING子句和GROUP BY子句)开头的人的州返回一行。每个状态行包含下列值:

  • LIST(Age %FOREACH(Home_State)):该州所有人的年龄列表。
  • AVG(Age %FOREACH(Home_State)):全州所有人的平均年龄。
  • AVG(Age %AFTERHAVING):数据库中符合HAVING子句条件的所有人员的平均年龄。(此数字对于所有行都是相同的。)
  • LIST(Age %FOREACH(Home_State) %AFTERHAVING): 该州符合HAVING子句标准的所有人员的年龄列表。
  • AVG(Age %FOREACH(Home_State) %AFTERHAVING):该州所有符合HAVING子句标准的人的平均年龄。
SELECT Home_State,
       LIST(Age %FOREACH(Home_State)) AS StateAgeList,
       AVG(Age %FOREACH(Home_State)) AS StateAgeAvg,
       AVG(Age %AFTERHAVING ) AS AgeAvgHaving,
       LIST(Age %FOREACH(Home_State)%AFTERHAVING ) AS StateAgeListHaving,
       AVG(Age %FOREACH(Home_State)%AFTERHAVING ) AS StateAgeAvgHaving
FROM Sample.Person
GROUP BY Home_State
HAVING Name LIKE 'A%' OR Name LIKE 'M%' OR Name LIKE 'W%'
ORDER BY Home_State
0
0 453
文章 姚 鑫 · 十二月 21, 2021 7m read

第一章 聚合函数概述

计算列的所有值并返回单个聚合值的函数。

支持聚合函数

聚合函数执行与单个列中的一个或多个值相关的任务,并返回单个值。 支持的功能有:

  • SUM - 返回指定列的值的和。
  • AVG - 返回指定列值的平均值。
  • COUNT - 返回表中的行数,或指定列中非空值的个数。
  • MAX - 返回指定列中使用的最大值。
  • MIN - 返回指定列中使用的最小值。
  • VARIANCEVAR_SAMP, VAR_POP - 返回指定列的值的统计方差。
  • STDDEV, STDDEV_SAMP, STDDEV_POP - 返回指定列值的统计标准偏差。
  • LIST - 以逗号分隔的列表形式返回指定列中使用的所有值。
  • %DLIST - 返回指定列中使用的所有值,作为 IRIS列表结构中的元素。
  • XMLAGG - 将指定列中使用的所有值作为连接字符串返回。
  • JSON_ARRAYAGG - 返回指定列中使用的所有值作为JSON格式数组。

可以使用CREATE aggregate命令定义其他用户定义的聚合函数。

聚合函数忽略为NULL的字段。 例如,LIST%DLIST不包含指定字段为NULL的行的元素。 COUNT只计算指定字段的非空值。

聚合函数(COUNT除外)不能应用于流字段。 这样做会产生一个SQLCODE -37错误。 可以使用COUNT来计数流字段值,但有一些限制。

注意:聚合函数类似于窗口函数。 但是,聚合函数从一组行中获取列的值,并将结果作为单个值返回。 窗口函数从一组行中获取一列的值,并为每一行返回一个值。 聚合函数可以在窗口函数中指定。 不能在聚合函数中指定窗口函数。 SUM既可以用作聚合函数,也可以用作窗口函数。

使用聚合函数

聚合函数可用于:

  • SELECT列表,可以作为列出的选择项,也可以作为子查询的选择项。
  • HAVING 子句。 然而,HAVING子句必须显式指定聚合函数; 它不能使用相应的选择项列别名或选择项序列号指定聚合。
  • DISTINCT BY子句。 然而,单独指定聚合函数本身是没有意义的,而且总是返回单行。 更有意义的是将聚合函数指定为表达式的一部分,例如DISTINCT BY(MAX(Age)-Age)

聚合函数不能直接用于:

  • ORDER BY子句。 尝试这样做会产生一个SQLCODE -73错误。 但是,通过指定相应的列别名或选择项序列号,可以在ORDER BY子句中使用聚合函数。
  • WHERE子句。 尝试这样做会产生一个SQLCODE -19错误。
  • GROUP BY。 尝试这样做会产生一个SQLCODE -19错误。
  • TOP。 尝试这样做会产生一个SQLCODE -1错误。
  • JOIN。 尝试在ON子句中指定聚合将产生SQLCODE -19错误。 试图在USING子句中指定聚合将生成SQLCODE -1错误。

但是,可以使用提供列别名的子查询为这些子句提供聚合函数值(TOP子句除外)。 例如,要使用WHERE子句来选择年龄值小于平均年龄值,可以将AVG聚合函数放在一个子查询中:

SELECT Name,Age,AvgAge
FROM (SELECT Name,Age,AVG(Age) AS AvgAge FROM Sample.Person)
WHERE Age < AvgAge
ORDER BY Age

组合聚合和字段

SQL允许在查询中使用其他SELECT项指定聚合函数。诸如COUNT(*)之类的聚合不需要在单独的查询中。

SELECT TOP 5 COUNT(*),Name,AVG(Age)
FROM Sample.Person
ORDER BY Name

当指定聚合函数并且在选择列表中未指定字段选择项时,SQL将返回一行。将忽略TOP子句,除非它是TOP 0(不返回行):

SELECT TOP 7 AVG(Age),LIST(Age)
FROM Sample.Person
WHERE Age > 75

指定聚合函数并在选择列表中指定一个或多个字段选择项时,SQL将根据字段项所需的行数返回:

SELECT DISTINCT Age,AVG(Age),LIST(Age)
FROM Sample.Person
WHERE Age > 75

列名和别名

默认情况下,分配给聚合函数结果的列名是Aggregate_n,其中n数字后缀是SELECT列表中指定的列序列号。因此,下面的示例创建列名Aggregate_2Aggregate_5

SELECT TOP 5 Home_State,COUNT(*),Name,Age,AVG(Age)
FROM Sample.Person
ORDER BY Name

要指定另一个列名(列别名),请使用AS关键字:

SELECT COUNT(*) AS PersonCount
FROM Sample.Person,Sample.Employee

可以使用列别名在ORDER BY子句中指定聚合字段。以下示例按年龄与平均年龄不同的顺序列出人员:

SELECT Name,Age,
    AVG(Age) AS AvgAge,
    ABS(Age - AVG(Age)) AS RelAge
FROM Sample.Person
ORDER BY RelAge

使用ORDER BY

LIST%DLISTXMLAGGJSON_ARRAYAGG函数将多行中的表列的值合并为单个聚合值。由于ORDER BY子句是在计算所有聚合字段之后应用于查询结果集的,因此ORDER BY不能直接影响这些聚合中的值序列。在某些情况下,这些聚合的结果可能会按顺序显示,但不应依赖此顺序。给定聚合结果值中列出的值不能显式排序。

DISTINCT关键字子句

所有聚合函数都支持可选的DISTINCT关键字子句。此关键字将聚合操作限制为只有不同的(唯一)字段值。使用默认字段排序规则(%SQLUPPER)时,仅字母不同的字段值不被视为不同的值。如果未指定DISTINCT,则默认为对所有非空值(包括重复值)执行聚合操作。MINMAX聚合函数支持DISTINCT关键字,尽管它不执行任何操作。

聚合函数DISTINCT field1子句忽略为NULLfield1值。这与SELECT语句的DISTINCT子句不同:SELECT DISTINCT子句为DISTINCT NULL返回一行,就像它为每个DISTINCT字段值返回一行一样。但是,由(Field2)field1区分的聚合函数不会忽略field2的不同NULL。例如,如果FavoriteColors50个不同的值和多个NULL,则返回的不同行数为51,计数(DISTINCT FavoriteColors)50,计数(DISTINCT BY(FavoriteColors)%ID)51

SELECT DISTINCT FavoriteColors,
       COUNT(DISTINCT FavoriteColors),
       COUNT(DISTINCT BY(FavoriteColors) %ID)
 FROM Sample.Person

使用DISTINCT和GROUP BY

带有SELECT-ITEM聚合函数和GROUP BY子句的SELECT DISTINCT返回的结果与DISTINCT关键字不存在时返回的结果相同。要获得所需的结果,请将聚合函数放入子查询中。

例如,返回各州不同计数的人数(有些州有4个人,有些州有6个人,依此类推)。可以按如下方式实现此结果:

SELECT DISTINCT COUNT(*) AS PersonCounts
FROM Sample.Person
GROUP BY Home_State

相反,你会得到每个州的人数统计,就像DISTINCT关键字不存在一样:

SELECT COUNT(*) AS PersonCounts
FROM Sample.Person
GROUP BY Home_State

为了达到预期的结果,需要使用子查询,如下所示:

SELECT DISTINCT * 
FROM (SELECT COUNT(*) AS PersonCounts FROM Sample.Person
      GROUP BY Home_State)

行数

当查询返回聚合值时,%ROWCOUNT值取决于查询:

  • 仅聚合函数:计算聚合值并返回%ROWCOUNT 1。 如果只选择聚合的查询没有选择行,它仍然返回%ROWCOUNT 1: COUNT=0,其他聚合函数返回NULL.
  • 只使用GROUP BY的聚合函数:返回GROUP BY子句选择的每个组的聚合值。 %ROWCOUNT是选定的组数。 如果查询没有选择行,则groupby不选择组,并且查询返回%ROWCOUNT 0
  • 仅使用DISTINCT的聚合函数:计算聚合值并返回%ROWCOUNT 1。 如果查询没有选择行,DISTINCT就不会选择不同的值,并且查询返回%ROWCOUNT 0
  • 只包含TOP子句的聚合函数:对于任何非零的TOP值,计算聚合值并返回%ROWCOUNT 1。 对于TOP=0,返回%ROWCOUNT 0,不计算聚合。
  • 与字段聚合:如果查询返回字段值和聚合函数,则返回的行数就是所选择的行数。 如果查询没有选择行,则返回%ROWCOUNT 0,并且不计算聚合。

这些结果在子查询或表达式的选择项中不受影响。

聚合、事务和锁定

在查询中包含一个聚合函数会导致查询将数据的当前状态返回给所有结果集字段,包括未提交的数据更改。 因此,对于包含聚合函数的查询,将忽略ISOLATION LEVEL READ COMMITTED设置。 未提交数据的当前状态如下:

  • INSERTUPDATE:聚合计算确实包含修改的值,即使这些修改尚未提交并可能回滚。
  • DELETETRUNCATE TABLE:聚合计算不包括已删除的行,即使这些删除尚未提交并可能回滚。

因为聚合函数通常涉及来自大量行的数据,所以在聚合计算中涉及的所有行上发出事务锁是不可接受的。 因此,在进行聚合计算时,另一个用户可能正在执行修改数据的事务。

聚合和分片表

分片表对聚合函数的支持受到限制。 例如,切分表不支持聚合函数DISTINCT%FOREACH%AFTERHAVING子句。

0
0 159
文章 姚 鑫 · 十二月 19, 2021 5m read

第二十章 SQL谓词 %STARTSWITH(二)

首尾空格

在大多数情况下,%STARTSWITH将前导空格视为与任何其他字符相同的字符。 例如,%STARTSWITH ' B'可用于选择只有一个前导空白后跟字母B的字段值。然而,只包含空白的子字符串不能选择前导空白; 它选择非空值。

尾随空格的%STARTSWITH行为取决于数据类型和排序规则类型。 %STARTSWITH忽略定义为SQLUPPER的字符串子串的尾随空格。 %STARTSWITH不会忽略数字、日期或列表子字符串中的尾随空格。

在下面的示例中,%STARTSWITH将结果集限制为以“M”开头的名称。 因为Name是一个SQLUPPER字符串数据类型,子字符串的末尾空格将被忽略:

SELECT Name FROM Sample.Person
WHERE Name %STARTSWITH 'M      '

在下面的示例中,%STARTSWITH从结果集中删除所有行,因为对于数值,子字符串的末尾空格不会被忽略:

SELECT Name,Age FROM Sample.Person
WHERE Age %STARTSWITH '6      '

在下面的示例中,%STARTSWITH从结果集中删除所有行,因为对于列表值,子字符串中的末尾空不会被忽略:

SELECT Name,FavoriteColors FROM Sample.Person
WHERE %EXTERNAL(FavoriteColors) %STARTSWITH 'Blue '

但是,在下面的示例中,结果集由这些列表值组成,这些列表值以Blue开头,然后是列表分隔符(显示为空白); 换句话说,以“Blue”开头的列表包含多个项:

SELECT Name,FavoriteColors FROM Sample.Person
WHERE %EXTERNAL(FavoriteColors) %STARTSWITH 'Blue'||CHAR(13)||CHAR(10)

下标的范围

当从下标中检索标量表达式时,%STARTSWITH可以用作一个索引限制范围条件,从而缩小需要遍历的标量表达式下标值的范围。 其逻辑是用给定的子字符串前缀值开始下标范围,并在下标值不再以子字符串开头时停止。

国家排序歧义字符

在一些国家语言中,两个字符或字符组合被认为是等价的。 通常这是一个有或没有重音标记的字符,例如在Czech2区域设置中,其中CHAR(65)CHAR(193)都排序为“a”。 %STARTSWITH将这些字符识别为等效字符。

下面的示例显示了Czech2 CHAR(65) (A)CHAR(193) (Á)的首次遍历排序:

M
MA
MÁ
MAC
MÁC
MACX
MÁCX
MAD
MÁD
MB 

需要注意的是,无法在查询编译时知道在运行时将使用哪种国家排序规则。 因此,必须编写%STARTSWITH下标遍历代码,以便正确地满足任何可能的运行时情况。

其他等价的比较

%STARTSWITH对字符串的初始字符执行等价比较。 可以使用字符串比较操作符执行其他类型的等价比较。 这些措施包括:

使用等号操作符对整个字符串进行等价比较:

SELECT Name,Home_State FROM Sample.Person
WHERE Home_State = 'VT'

这个例子选择任何包含Home_State字段值“VT”的记录。 因为Home_State被定义为SQLUPPER,所以这个字符串比较不区分大小写。

还可以使用不相等操作符(<>)对整个字符串执行非等价比较。

  • 子字符串与值的等价比较,使用Contains操作符:
SELECT Name FROM Sample.Person
WHERE Name [ 'y'

此示例选择包含小写字母“y”的所有Name记录。 默认情况下,Contains操作符比较是区分大小写的,即使字段被定义为不区分大小写。

  • 使用SQL Search进行上下文感知的等价比较。 SQL Search的一个用途是确定一个值是否包含指定的单词或短语。 SQL搜索不区分大小写。
  • 使用IN关键字操作符对整个字符串与多个值进行等价比较:
SELECT Name,Home_State FROM Sample.Person
WHERE Home_State IN ('VT','MA','NH','ME')
ORDER BY Home_State

这个示例选择任何包含任何指定Home_State字段值的记录。

  • 使用%pattern关键字操作符对整个字符串与值模式进行等价比较:
SELECT Name,Home_State FROM Sample.Person
WHERE Home_State %PATTERN '1U1"C"'
ORDER BY Home_State

这个示例选择任何包含Home_State字段值的记录,该字段值匹配1U(一个大写字母)后跟1个“C”(一个字母“C”)的模式。 这个模式可以通过Home_State缩写“NC”“SC”来实现。

  • 使用LIKE关键字操作符将具有一个或多个通配符的子字符串与一个值进行等价比较:
SELECT Name FROM Sample.Person
WHERE Name LIKE '_a%'

这个示例选择包含字母“a”作为第二个字母的所有Name记录。 此字符串比较使用Name排序规则类型来确定比较是否区分大小写。

注意:当在运行时提供谓词值时(使用?输入参数或:var输入主机变量),结果谓词%STARTSWITH 'abc'提供了比等价的结果谓词'abc%'更好的性能。

示例

下面的示例使用WHERE子句选择以字母“R”“r”开头的Name值。 默认情况下,%STARTSWITH字符串比较不区分大小写:

SELECT Name FROM Sample.Person
WHERE Name %STARTSWITH 'r'

下面的示例为每个以“M”开头的Home_State名称返回一条记录:

SELECT DISTINCT Home_State FROM Sample.Person
WHERE Home_State %STARTSWITH 'M'
ORDER BY Home_State

下面的示例使用HAVING子句为年龄以2开头的人选择记录,显示所有年龄的平均值和HAVING子句选择的年龄的平均值。 它将结果按年龄排序:

SELECT Name,
       Age,
       AVG(Age) AS AvgAge,
       AVG(Age %AFTERHAVING) AS Avg20
FROM Sample.Person
HAVING Age %STARTSWITH 2
ORDER BY Age

下面的示例执行%STARTSWITHDOB(出生日期)字段的内部日期格式值的比较。 在本例中,它选择从11/5/1988 ($H=54000)到08/1/1991 ($H=54999)的所有日期:

SELECT Name,DOB
FROM Sample.Person
WHERE DOB %STARTSWITH 54
ORDER BY DOB
0
0 75
文章 姚 鑫 · 十二月 18, 2021 5m read

第十九章 SQL谓词 %STARTSWITH(一)

用指定初始字符的子字符串匹配值。

大纲

scalar-expression %STARTSWITH substring

参数

  • scalar-expression - 将其值与子字符串进行比较的标量表达式(最常见的是数据列)。
  • substring - 解析为包含与标量表达式中的值匹配的第一个或多个字符的字符串或数字的表达式。

描述

%STARTSWITH谓词允许选择以子字符串中指定的字符开头的数据值。 如果substring不匹配任何标量表达式值,%STARTSWITH返回空字符串。 无论显示模式如何,这个匹配总是在逻辑(内部存储)数据值上执行。

下面的示例选择所有以“M”开头的名称:

SELECT Name FROM Sample.MyTest WHERE Name %STARTSWITH 'M'

可以用NOT来颠倒谓词的意思。 下面的示例选择除了以“M”开头的名称以外的所有名称:

SELECT Name FROM Sample.MyTest WHERE NOT Name %STARTSWITH 'M'

排序类型

%STARTSWITH使用与它匹配的字段相同的排序规则类型。 默认情况下,字符串数据类型字段是用SQLUPPER排序规则定义的,它不区分大小写。

在下面的例子中,UpName被定义为SQLUPPER; 子字符串匹配不区分大小写:

SELECT UpName FROM Sample.MyTest WHERE UpName %STARTSWITH 'mo'

如果为WHERE子句中的列分配不同的排序规则类型,则该排序规则类型将匹配%STARTSWITH子字符串的文字值。

在下面的例子中,UpName被定义为SQLUPPER; 但是子字符串匹配是EXACT(区分大小写):

SELECT UpName FROM Sample.MyTest WHERE %EXACT(UpName) %STARTSWITH 'mo'

有些排序规则函数向字段值追加一个空格字符。 这可能导致%STARTSWITH不匹配任何值,除非对子字符串应用等效的排序函数。

在下例中,ExactName被定义为EXACT; 因为查询将%SQLUPPER应用于标量表达式,所以比较现在涉及一个以附加空格字符开头的字符串。 这个比较不会返回任何字段:

SELECT ExactName FROM Sample.MyTest WHERE %SQLUPPER(ExactName) %STARTSWITH 'Ra'

因此,还必须向子字符串追加一个空格字符。 下面的示例对EXACT字段应用非区分大小写的匹配:

SELECT ExactName FROM Sample.MyTest WHERE %SQLUPPER(ExactName) %STARTSWITH %SQLUPPER('Ra')

%SelectMode

%STARTSWITH谓词不能使用当前的%SelectMode设置。 子字符串必须以逻辑格式指定,无论%SelectMode设置如何。 在ODBC或Display格式中指定谓词值通常会导致没有数据匹配或意外的数据匹配。 这主要适用于日期、时间和IRIS格式列表(%List)。

在下面的动态SQL示例中,%STARTSWITH谓词必须以逻辑格式指定日期子字符串,而不是%SelectMode=1 (ODBC)格式。 从41开始的逻辑值(日期从1953年4月4日($HOROLOG 41000)到1955年12月28日($HOROLOG 41999))被选中:

ClassMethod StartsWith()
{
	s q1 = "SELECT Name,DOB FROM Sample.Person "
	s q2 = "WHERE DOB %STARTSWITH '41%'"
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}

列表字段

如果标量表达式是一个列表字段,%STARTSWITH可以使用%EXTERNAL来比较列表值和子字符串。 例如,要确定FavoriteColors列表字段以'Bl'开头的所有记录:

SELECT Name,FavoriteColors FROM Sample.Person
WHERE %EXTERNAL(FavoriteColors) %STARTSWITH 'Bl'

%EXTERNAL将列表转换为DISPLAY格式时,显示的列表项似乎用空格分隔。 这个“空格”实际上是两个非显示字符CHAR(13)CHAR(10)。 要在列表中多个元素中使用%STARTSWITH,必须指定以下字符:

SELECT Name,FavoriteColors FROM Sample.Person
WHERE %EXTERNAL(FavoriteColors) %STARTSWITH 'Orange'||CHAR(13)||CHAR(10)||'B'

过滤null

  • 如果标量表达式是任何非空数据值且子字符串是“空”值,%STARTSWITH总是返回标量表达式。
  • 如果标量表达式为空且子字符串为“空”值,%STARTSWITH不返回标量表达式。

“空”子字符串值可以是以下任意一种:NULL, CHAR(0),空字符串("),仅由空格('')组成的字符串,CHAR(32)空格字符,CHAR(9)制表符。 默认情况下,%STARTSWITH使用所有这些值来过滤空值。

要返回仅由空格字符组成的标量表达式值,必须使用%EXACT排序规则。

在以下所有示例中,%STARTSWITH返回相同的结果。 它将结果集限制为非空的FavoriteColors值:

SELECT Name,FavoriteColors FROM Sample.Person
WHERE FavoriteColors %STARTSWITH NULL
SELECT Name,FavoriteColors FROM Sample.Person
WHERE FavoriteColors %STARTSWITH ''
SELECT Name,FavoriteColors FROM Sample.Person
WHERE FavoriteColors %STARTSWITH '   '
SELECT Name,FavoriteColors FROM Sample.Person
WHERE FavoriteColors %STARTSWITH CHAR(9)

注意,当从列表字段过滤空值时,%EXTERNAL排序规则类型不用于标量表达式。

由于NULL和空字符串的定义,%STARTSWITH NULL和空字符串的行为与复合子字符串不同。 当将一个值与NULL连接时,结果是NULL。 当将一个值与空字符串连接时,结果就是该值。 下面的例子说明了这一点:

SELECT Name,FavoriteColors
FROM Sample.Person
WHERE %EXTERNAL(FavoriteColors) %STARTSWITH 'B'||NULL
/* Selects all non-null rows */
SELECT Name,FavoriteColors
FROM Sample.Person
WHERE %EXTERNAL(FavoriteColors) %STARTSWITH 'B'||''
/* Selects all values that begin with B */
0
0 194
文章 姚 鑫 · 十二月 17, 2021 1m read

第十八章 SQL谓词 SOME

将值与子查询中的至少一个匹配值匹配。

大纲

scalar-expression comparison-operator SOME (subquery)

参数

  • scalar-expression - 将其值与子查询生成的结果集进行比较的标量表达式(最常见的是数据列)。
  • comparison-operator - 以下比较操作符之一:=(等于),<>!=(不等于),<(小于),<=(小于或等于),>(大于),>=(大于或等于),[(包含),或](跟随)。
  • subquery - 一个用括号括起来的子查询,它返回一个用于与标量表达式比较的结果集。

描述

SOME关键字与比较操作符一起创建谓词(量化比较条件),如果标量表达式的值与子查询检索到的一个或多个对应值匹配,则该谓词为真。 SOME谓词将单个标量表达式项与单个子查询SELECT项进行比较。 具有多个选择项的子查询将生成SQLCODE -10错误。

注意:SOMEANY关键字是同义词。

示例

下面的例子选择了居住在密西西比河以西任何一个州的工资超过75,000美元的员工:

SELECT Name,Salary,Home_State FROM Sample.Employee
WHERE Salary > 75000
AND Home_State = SOME
 (SELECT State FROM Sample.USZipCode
  WHERE Longitude < -93)
ORDER BY Home_State
0
0 88
文章 姚 鑫 · 十二月 16, 2021 5m read

第十七章 SQL谓词 %PATTERN

用包含字面值、通配符和字符类型代码的模式字符串匹配值。

大纲

scalar-expression %PATTERN pattern

参数

  • scalar-expression - 一个标量表达式(最常见的是数据列),它的值正在与模式进行比较。
  • pattern - 一个带引号的字符串,表示要与标量表达式中的每个值匹配的字符模式。 模式字符串可以包含双引号括起来的文字字符、指定字符类型的字母代码以及数字和作为通配符的句点(.)字符。

描述

%PATTERN谓词允许将字符类型代码和字面值的模式匹配到由标量表达式提供的数据值。 如果模式匹配完整的标量表达式值,则返回该值。 如果pattern没有完全匹配任何标量表达式值,%pattern将返回空字符串。

%PATTERN使用与ObjectScript模式匹配操作符相同的模式代码(? 操作符)。 模式由一对或多对重复计数和一个值组成。 重复计数可以是整数,句点(.)表示“任意数量的字符”,或者使用句点和整数的组合指定的范围。 值可以是字符类型代码字母或字符串字面值(在引号中指定)。

请注意,一个模式通常由多个重复/值对组成,因为该模式必须与整个数据值完全匹配。因此,许多模式都以“.E”对结尾,这意味着数据值的其余部分可以由任意数量的任意类型的字符组成。

模式匹配对的几个简单示例:

  • 1L表示一个(而且只有一个)小写字母。
  • 1“L”表示一个文字字符“L”
  • 1“617”表示一个文字字符串“617”
  • .U表示任意数量的大写字母。
  • .E表示任意数量的任何类型的可打印字符。
  • .3A指不超过三个(三个或以下)字母(大写或小写)的任何数字。
  • 3.N表示三位或三位以上的数字。
  • 3.6N表示三到六位(含)数字。

模式匹配区分大小写。模式匹配基于标量表达式的精确值,而不是其排序规则值。因此,即使标量表达式的排序规则类型不区分大小写,%Pattern操作中指定的文字字母也始终区分大小写。

在动态SQL中,SQL查询被指定为ObjectScript字符串,用双引号分隔。 因此,模式字符串中的双引号必须是双引号。 因此,美元金额的模式是:'1"$"1.N1"."2N'将在动态SQL中指定为'1""$""1.N1"".""2N'

%SelectMode

%PATTERN谓词不使用当前的``%SelectMode设置。 应该以逻辑格式指定模式,无论%SelectMode设置如何。 尝试以ODBC格式或Display`格式指定模式通常会导致没有数据匹配或意外的数据匹配。

可以使用%EXTERNAL%ODBCOUT格式转换函数来转换谓词操作的标量表达式字段。 这允许以Display格式或ODBC格式指定模式。 但是,使用格式转换函数会阻止对字段使用索引,因此会对性能产生重大影响。

在下面的动态SQL示例中,%PATTERN谓词以逻辑格式指定日期模式,而不是%SelectMode=1 (ODBC)格式。 从41开始的逻辑值(日期从1953年4月4日($HOROLOG 41000)到1955年12月28日($HOROLOG 41999))被选中:

/// d ##class(PHA.TEST.SQLCommand).Pattern()

ClassMethod Pattern()
{
	s q1 = "SELECT Name,DOB FROM Sample.Person "
	s q2 = "WHERE DOB %PATTERN '1""41""3N' "
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Pattern()
Name    DOB
Houseman,Martin D.      1955-09-25
Ingrahm,Yan S.  1954-06-15
Smith,Elvis Y.  1955-06-29
Ng,Liza Z.      1955-10-05
Zweifelhofer,Zelda J.   1954-02-19
Zampitello,Josephine Q. 1953-08-14
Hertz,Uma C.    1954-07-25
Davis,Jane E.   1953-07-28
Vanzetti,Alexandra O.   1953-12-29
 
9 Rows(s) Affected
End of data

下面的动态SQL示例使用%ODBCOUT格式转换函数来转换谓词匹配的DOB字段。 这允许以ODBC格式指定%PATTERN模式。 它选择DOB字段ODBC值以195开头的行(日期范围从1950年到1959年)。 但是,指定格式转换函数会阻止对DOB字段值使用索引:

ClassMethod Pattern1()
{
	s q1 = "SELECT Name,DOB FROM Sample.Person "
	s q2 = "WHERE %ODBCOUT(DOB) %PATTERN '1""195"".E' "
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}

示例

下面的示例在WHERE子句中使用%PATTERN操作符来选择Home_State值,其中第一个字符是大写字母,第二个字符是字母“C”:

SELECT Name,Home_State FROM Sample.Person
WHERE Home_State %PATTERN '1U1"C"'

这个示例选择Home_State of North Carolina (NC)South Carolina (SC)的记录。

下面的示例在WHERE子句中使用%PATTERN操作符来选择以大写字母开头,后跟小写字母的Name值。

SELECT Name FROM Sample.Person
WHERE Name %PATTERN '1U1L.E'

这里的模式翻译为:1U(一个大写字母),跟着1L(一个小写字母),然后是. e(任意数量的任意类型字符)。 注意,此模式将排除“JONES”“O'Reilly”“deGastyne”等名称。

下面的示例在HAVING子句中使用%PATTERN操作符为姓名以字母“Jo”开头的人选择记录,并返回搜索记录和返回记录的计数。

SELECT Name,
       COUNT(Name) AS TotRecs,
       COUNT(Name %AFTERHAVING) AS JoRecs
FROM Sample.Person
HAVING Name %PATTERN '1U.L1","1"Jo".E'

在本例中,Name字段值被格式化为LastnameFirstname,并可能包含一个可选的中间名或首字母。 为了反映这种名称格式,这里的模式翻译为:1U(一个大写字母),后跟. l(任意数量的小写字母),后跟1个","(一个逗号字符),后跟1个"Jo"(一个值为"Jo"的字符串),后跟. e(任意数量的任何类型的字符)。

0
0 135
文章 姚 鑫 · 十二月 15, 2021 5m read

第十六章 SQL谓词 %MATCHES

用包含字面值、通配符和范围的模式字符串匹配值。

大纲

scalar-expression %MATCHES pattern [ESCAPE char]

参数

  • scalar-expression - 一个标量表达式(最常见的是数据列),它的值正在与模式进行比较。
  • pattern - 一个带引号的字符串,表示要与标量表达式中的每个值匹配的字符模式。 模式字符串可以包含文字字符,问号(?)和星号(*)通配符,方括号用于指定允许的值,反斜杠(\)用于指定紧跟其后的字符被视为文字。 模式也可以是空字符串或NULL,尽管它不匹配或返回NULL项。
  • ESCAPE char - 可选-包含单个字符的字符串。 这个字符字符可以在模式中用于指定紧跟在它后面的字符将被视为文字。 如果未指定,默认转义字符是反斜杠(\)。

描述

%MATCHES谓词是 IRIS扩展,用于将值匹配到模式字符串。 %MATCHES返回TrueFalse用于匹配操作。 模式字符串可以由字面量字符、通配符字符和匹配字面量的列表或范围组成。

模式匹配区分大小写。 模式匹配基于标量表达式的EXACT值,而不是它的排序规则值。 因此,%MATCHES操作始终是大小写敏感的,即使标量表达式的排序规则类型不区分大小写。

%MATCHES支持以下模式通配符:

  • ? - 匹配任意类型的任意单个字符。
  • * - 匹配零个或多个任意类型的字符。
  • [abc] - 匹配括号中指定的任意一个字符。
  • [a-z] - 匹配括号中指定的范围内的字符,包括指定的字符。
  • [^A-Z] [^a-z] [^0–9] - 这些范围匹配括号中指定的字符以外的任何字符。 可以使用此语法不指定大写字母、小写字母或数字。 只支持显示的指定文字范围。
  • \ - 将后面的字符视为文字字符,而不是通配符。 反斜杠是默认的转义字符; 可以使用可选的escape子句指定另一个字符作为转义字符。

与大多数谓词一样,%MATCHES可以使用NOT操作符:item NOT %MATCHES pattern进行反转。 %MATCHESNOT %MATCHES都不能返回空字段。 返回NULL字段使用IS NULL

反斜杠(\)字符是默认的转义字符。 它可以用来指定在指定的模式位置将通配符用作文本匹配。 例如,要匹配一个问号作为字符串的第一个字符,请指定'\?*'。 要匹配问号作为字符串的第四个字符,请指定'?? \?*'。 要匹配字符串中的任何地方的问号,请指定'*\?*'。 要匹配只包含星号字符的字符串,请指定'\*'。 要匹配至少包含一个星号字符的字符串,请指定'*\**'。 要匹配字符串中的反斜杠字符,请指定'*\\*'

支持%MATCHES是为了与Informix SQL兼容。

%SelectMode

%MATCHES谓词不使用当前的%SelectMode设置。 应该以逻辑格式指定模式,无论%SelectMode设置如何。 尝试以ODBC格式或Display格式指定模式通常会导致没有数据匹配或意外的数据匹配。

可以使用%EXTERNAL%ODBCOUT格式转换函数来转换谓词操作的标量表达式字段。 这允许以Display格式或ODBC格式指定模式。 但是,使用格式转换函数会阻止对字段使用索引,因此会对性能产生重大影响。

在下面的动态SQL示例中,%MATCHES谓词以逻辑格式指定日期模式,而不是%SelectMode=1 (ODBC)格式。 从41开始的逻辑值(日期从1953年4月4日($HOROLOG 41000)到1955年12月28日($HOROLOG 41999))被选中:

ClassMethod Matches()
{
	s q1 = "SELECT Name,DOB FROM Sample.Person "
	s q2 = "WHERE DOB %MATCHES '41*'"
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).Matches()
Name    DOB
Houseman,Martin D.      1955-09-25
Ingrahm,Yan S.  1954-06-15
Smith,Elvis Y.  1955-06-29
Ng,Liza Z.      1955-10-05
Zweifelhofer,Zelda J.   1954-02-19
Zampitello,Josephine Q. 1953-08-14
Hertz,Uma C.    1954-07-25
Davis,Jane E.   1953-07-28
Vanzetti,Alexandra O.   1953-12-29
 
9 Rows(s) Affected
End of data

下面的动态SQL示例使用%ODBCOUT格式转换函数来转换谓词匹配的DOB字段。 这允许以ODBC格式指定%MATCHES模式。 它选择DOB字段ODBC值以195开头的行(日期范围从1950年到1959年)。 但是,指定格式转换函数会阻止对DOB字段值使用索引:

ClassMethod Matches1()
{
	s q1 = "SELECT Name,DOB FROM Sample.Person "
	s q2 = "WHERE %ODBCOUT(DOB) %MATCHES '195*'"
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Matches1()
Name    DOB
Houseman,Martin D.      1955-09-25
Ingrahm,Yan S.  1954-06-15
Smith,Elvis Y.  1955-06-29
Gore,Alfred M.  1958-09-15
Yoders,Liza U.  1959-06-05
Ng,Liza Z.      1955-10-05
Yeats,Debby G.  1951-12-06
Zweifelhofer,Zelda J.   1954-02-19
Solomon,Emily D.        1953-01-28
Isaacs,Elvis V. 1952-04-05
Pantaleo,Robert U.      1950-03-29

示例

下面的示例返回所有以“A”开头的姓氏:

SELECT Name FROM Sample.Person 
WHERE Name %MATCHES 'A*'

下面的示例返回所有以“A”开头的名字:

SELECT Name FROM Sample.Person 
WHERE Name %MATCHES '*,A*'

下面的示例返回包含字母“A”的所有名称(姓、名或中间首字母):

SELECT Name FROM Sample.Person 
WHERE Name %MATCHES '*A*'

下面的示例返回不包含字母 “A”, “a”, “E” , “e”的所有名称:

SELECT Name FROM Sample.Person 
WHERE Name NOT %MATCHES '*[AaEe]*'

下面的示例返回所有以“A”“D”开头的五个字母的姓氏:

SELECT Name FROM Sample.Person 
WHERE Name %MATCHES '?????,[A-D]*'
0
0 134
文章 姚 鑫 · 十二月 14, 2021 7m read

第十五章 SQL谓词 LIKE

用包含字面值和通配符的模式字符串匹配值。

大纲

scalar-expression LIKE pattern [ESCAPE char]

参数

  • scalar-expression - 一个标量表达式(最常见的是数据列),它的值正在与模式进行比较。
  • pattern - 一个带引号的字符串,表示要与标量表达式中的每个值匹配的字符模式。 模式字符串可以包含字面字符、下划线(_)和百分比(%)通配符。
  • ESCAPE char 可选-包含单个字符的字符串。 这个字符字符可以在模式中用于指定紧跟在它后面的字符将被视为文字。

描述

LIKE谓词允许选择那些匹配模式中指定的字符的数据值。 模式可以包含通配符。 如果pattern不匹配任何标量表达式值,LIKE返回空字符串。

LIKE可以在任何可以指定谓词条件的地方使用,如本手册的谓词概述页面所述。

LIKE谓词支持以下通配符:

  • _ - 任何单个字符
  • % - 由0个或多个字符组成的序列。 (根据SQL标准,NULL不被认为是一个0字符的序列,因此不被这个通配符选中。)

在动态SQL或嵌入式SQL中,模式可以将通配符和输入参数或输入主机变量表示为连接的字符串,如示例部分所示。

注意:当在运行时提供谓词值时(使用? 输入参数或:var输入主机变量),结果谓词%STARTSWITH 'abc'提供了比等价的结果谓词'abc%'更好的性能。

排序类型

模式字符串使用与它匹配的列相同的排序规则类型。 默认情况下,字符串数据类型字段是用SQLUPPER排序规则定义的,它不区分大小写。

如果LIKE应用于具有SQLUPPER默认排序类型的字段,则LIKE子句返回忽略字母大小写的匹配项。 可以使用SQLSTRING排序规则类型执行区分大小写的LIKE字符串比较。

下面的示例返回包含子字符串“Ro”的所有名称。 因为LIKE不区分大小写,LIKE '%Ro%'返回Robert, Rogers, deRocca, LaRonga, Brown, Mastroni等:

SELECT Name FROM Sample.Person
WHERE Name LIKE '%Ro%'

将其与Contains操作符([)进行比较,后者使用EXACT(区分大小写)排序:

SELECT Name FROM Sample.Person
WHERE Name [ 'Ro'

通过使用%SQLSTRING排序类型,可以使用LIKE只返回那些包含区分大小写的子字符串“Ro”的名称。 MastroniBrown都不会回来:

SELECT Name FROM Sample.Person
WHERE %SQLSTRING(Name) LIKE '%Ro%'

在上面的示例中,%SQLSTRING附加到Name值的前导空格由%通配符处理。 一个更健壮的例子是在谓词两边指定排序规则类型:

SELECT Name FROM Sample.Person
WHERE %SQLSTRING(Name) LIKE %SQLSTRING('%Ro%')

所有值,空字符串值,和NULL

如果模式值是percent (%)LIKE选择指定字段的所有值,包括空字符串值:

SELECT Name,FavoriteColors FROM Sample.Person
WHERE FavoriteColors LIKE '%'

它不选择NULL字段。

指定空字符串的模式值将返回空字符串值。

SELECT Name,FavoriteColors FROM Sample.Person
WHERE FavoriteColors LIKE ''

指定模式值为NULL不是一个有意义的操作。 它成功完成,但没有返回值。

SELECT Name,FavoriteColors FROM Sample.Person
WHERE FavoriteColors LIKE NULL

像大多数谓词一样,Like可以使用NOT逻辑运算符进行反转。 LIKENOT LIKE都不能用于返回NULL字段。 返回NULL字段使用IS NULL

ESCAPE子句

ESCAPE允许在模式中使用通配符作为文本字符。 如果提供了ESCAPE字符并且它是单个字符,则表示模式中直接跟在它后面的任何字符都应该被理解为文字字符,而不是通配符或格式化字符。 下面的例子展示了如何使用ESCAPE返回包含字符串“_SYS”的值:

SELECT * FROM MyTable
WHERE symbol_field LIKE '%\_SYS%' ESCAPE '\'

%SelectMode

LIKE谓词不使用当前的%SelectMode设置。 应该以逻辑格式指定模式,无论%SelectMode设置如何。 尝试以ODBC格式或Display格式指定模式通常会导致没有数据匹配或意外的数据匹配。

可以使用%EXTERNAL%ODBCOUT格式转换函数来转换谓词操作的标量表达式字段。 这允许以Display格式或ODBC格式指定模式。 但是,使用格式转换函数会阻止对字段使用索引,因此会对性能产生重大影响。

在下面的动态SQL示例中,LIKE谓词以逻辑格式指定日期模式,而不是%SelectMode=1 (ODBC)格式。 从41开始的逻辑值(日期从1953年4月4日($HOROLOG 41000)到1955年12月28日($HOROLOG 41999))被选中:

/// d ##class(PHA.TEST.SQLCommand).Like()
ClassMethod Like()
{
	s q1 = "SELECT Name,DOB FROM Sample.Person "
	s q2 = "WHERE DOB LIKE '41%'"
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Like()
Name    DOB
Houseman,Martin D.      1955-09-25
Ingrahm,Yan S.  1954-06-15
Smith,Elvis Y.  1955-06-29
Ng,Liza Z.      1955-10-05
Zweifelhofer,Zelda J.   1954-02-19
Zampitello,Josephine Q. 1953-08-14
Hertz,Uma C.    1954-07-25
Davis,Jane E.   1953-07-28
Vanzetti,Alexandra O.   1953-12-29
 
9 Rows(s) Affected
End of data

下面的动态SQL示例使用%ODBCOUT格式转换函数来转换谓词匹配的DOB字段。 这允许以ODBC格式指定LIKE模式。 它选择DOB字段ODBC值以195开头的行(日期范围从1950年到1959年)。 但是,指定格式转换函数会阻止对DOB字段值使用索引:

ClassMethod Like1()
{
	s q1 = "SELECT Name,DOB FROM Sample.Person "
	s q2 = "WHERE %ODBCOUT(DOB) LIKE '195%'"
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
HC-APP>d ##class(PHA.TEST.SQLCommand).Like1()
Name    DOB
Houseman,Martin D.      1955-09-25
Ingrahm,Yan S.  1954-06-15
Smith,Elvis Y.  1955-06-29
Gore,Alfred M.  1958-09-15
Yoders,Liza U.  1959-06-05
Ng,Liza Z.      1955-10-05
Yeats,Debby G.  1951-12-06
Zweifelhofer,Zelda J.   1954-02-19
Solomon,Emily D.        1953-01-28
Isaacs,Elvis V. 1952-04-05
Pantaleo,Robert U.      1950-03-29
Zampitello,Josephine Q. 1953-08-14
Xiang,Molly F.  1953-03-21
Nichols,Heloisa M.      1957-07-19
Hertz,Uma C.    1954-07-25
LaRocca,David X.        1956-01-11
Houseman,Alice R.       1957-12-07
Alton,Phil T.   1953-02-25
Davis,Jane E.   1953-07-28
Vanzetti,Alexandra O.   1953-12-29
Uhles,Dmitry P. 1951-08-23
Jafari,Christine Z.     1950-04-11
 
22 Rows(s) Affected
End of data

文字替换覆盖

在编译预解析期间,可以用双括号将LIKE谓词参数括起来,从而重写文字替换。 例如,WHERE Name LIKE (('Mc%'))WHERE Name LIKE (('%son%'))。 这可以通过改善整体选择性和/或下标边界选择性来提高查询性能。 但是,当使用不同的值多次调用同一个查询时,应该避免使用这种方法,因为这将导致为每个查询调用创建一个单独的缓存查询。

示例

下面的示例使用WHERE子句选择包含“son”Name值,包括以“son”开头或结尾的值。 默认情况下,LIKE字符串比较是不区分大小写的:

SELECT %ID,Name FROM Sample.Person
WHERE Name LIKE '%son%'

下面的嵌入式SQL示例返回与前一个示例相同的结果集。 注意如何在LIKE模式中使用连接操作符指定输入主机变量(:subname):

ClassMethod Like2()
{
	s subname = "son"
	&sql(
		DECLARE C1 CURSOR FOR SELECT %ID,Name INTO :id,:nameout FROM Sample.Person
		WHERE Name LIKE '%'_:subname_'%'
	)
	&sql(OPEN C1)
	q:(SQLCODE'=0)
	&sql(FETCH C1)
	while (SQLCODE = 0) {
		w id," ",nameout,!
		&sql(FETCH C1) 
	}
	&sql(CLOSE C1)
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Like2()
86 Anderson,Mario L.
131 Anderson,Valery N.
67 Donaldson,Julie I.
50 Emerson,Edgar T.
43 Hanson,George C.
164 Jackson,Ralph V.
119 Jackson,Terry L.
100 Johnson,Danielle I.
54 Larson,Nataliya Z.
103 Nathanson,Norbert Z.
52 Nelson,Neil E.
143 Nelson,Paul O.
214 Peterson,Alice E.
118 Peterson,Janice N.
196 Peterson,Kirsten R.
140 Peterson,Sophia A.
123 Sorenson,Samantha X.
149 Thompson,Umberto Q.
184 Wilson,Andrew O.
58 Wilson,Quentin Z.

下面的动态SQL示例返回与前一个示例相同的结果集。 注意如何在LIKE模式中使用连接操作符指定输入参数(?):

ClassMethod Like3()
{
	s myquery = "SELECT %ID,Name FROM Sample.Person WHERE Name LIKE '%'_?_'%'"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute("son")
	d rset.%Display()
}

下面的示例使用WHERE子句选择包含“blue”FavoriteColors值。 FavoriteColors字段是一个%List字段; %通配符处理%List格式字符:

SELECT Name,FavoriteColors FROM Sample.Person
WHERE FavoriteColors LIKE '%blue%'

下面的示例使用HAVING子句为年龄以1开头后跟一个字符的人选择记录。 它显示所有年龄的平均值和HAVING子句选择的年龄的平均值。 它根据年龄对结果排序。 所有返回值的年龄从1019

SELECT Name,
       Age,
       AVG(Age) AS AvgAge,
       AVG(Age %AFTERHAVING) AS AvgTeen
FROM Sample.Person
HAVING Age LIKE '1_'
ORDER BY Age
0
0 128
文章 姚 鑫 · 十二月 13, 2021 1m read

第十四章 SQL谓词 IS NULL

确定一个数据值是否为NULL

大纲

scalar-expression IS [NOT] NULL

描述

IS NULL谓词检测未定义的值。 可以检测到所有空值,或所有非空值:

SELECT Name, FavoriteColors FROM Sample.Person
WHERE FavoriteColors IS NULL 
SELECT Name, FavoriteColors FROM Sample.Person
WHERE FavoriteColors IS NOT NULL

IS NULL / IS NOT NULL谓词是少数几个可以在WHERE子句中用于流字段的谓词之一。 如下面的例子所示:

SELECT Title,%OBJECT(Picture) AS PhotoOref FROM Sample.Employee
WHERE Picture IS NOT NULL

不应将IS NULL谓词与SQL ISNULL函数混淆。

0
0 81
文章 Johnny Wang · 十二月 12, 2021 3m read

    您可能已经听说,我们目前正在为所有正在使用 Caché 和 Ensemble 的客户提供限时免费迁移到我们的下一代数据平台 InterSystems IRIS 的机会。

    虽然我们依旧如往常一样全力支持那些正在使用 Caché 数据库和 Ensemble 集成引擎的客户,但我们还是认为 InterSystems IRIS 是未来的关键。它结合了 Caché 和 Ensemble 的所有功能,并添加了大量令人兴奋的强大功能,从机器学习到原生 Python。

    这也正是我们为现有客户提供迁移到 InterSystems IRIS 并使用这些新功能的原因。 我们也通过就地迁移支持轻松迁移,这意味着无需数据库转换、分步迁移指南、教程等。

    听起来挺有趣对吗? 以下是我针对当前 Caché 和 Ensemble 应迁移到 InterSystems IRIS 的五个主要原因。

0
0 333
文章 姚 鑫 · 十二月 12, 2021 3m read

第十三章 SQL谓词 IS JSON

确定数据值是否为JSON格式。

注意:IRIS版本可用。其他不行。

大纲

scalar-expression IS [NOT] JSON [keyword]

参数

  • scalar-expression - 正在检查JSON格式的标量表达式。
  • keyword - 可选—可选值、标量、数组或对象。 默认为VALUE

描述

IS JSON谓词确定数据值是否为JSON格式。 下面的示例确定谓词是否是格式化正确的JSON字符串,是JSON对象还是JSON数组:

ClassMethod IsJson()
{
	s q1 = "SELECT TOP 5 Name FROM Sample.Person "
	s q2 = "WHERE '{""name"":""Fred"",""spouse"":""Wilma""}' IS JSON"
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
}

IS JSON(带或不带可选关键字VALUE)对任何JSON数组或JSON对象返回true。 这包括一个空JSON数组'[]'或一个空JSON对象'{}'

关键字VALUE和关键字SCALAR是同义词。

对于JSON数组oref返回true。 对于JSON对象oref, IS JSON对象返回true。 下面的例子说明了这一点:

ClassMethod IsJson1()
{
	s jarray=[1,2,3,5,8,13,21,34]
	w "JSON array: ",jarray,!
	s myquery = "SELECT TOP 5 Name FROM Sample.Person WHERE ? IS JSON ARRAY"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(jarray)
	d rset.%Display()
}
ClassMethod IsJson2()
{
	s jarray=[1,2,3,5,8,13,21,34]
	w "JSON array: ",jarray,!
	s myquery = "SELECT TOP 5 Name FROM Sample.Person WHERE ? IS JSON OBJECT"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(jarray)
	d rset.%Display()
}
ClassMethod IsJson3()
{
	s jobj={"name":"Fred","spouse":"Wilma"}
	w "JSON object: ",jobj,!
	s myquery = "SELECT TOP 5 Name FROM Sample.Person WHERE ? IS JSON OBJECT"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(jobj)
	d rset.%Display()
}

IS NOT JSON谓词是少数几个可以在WHERE子句中用于流字段的谓词之一。 它的行为与is NOT NULL相同。 如下面的例子所示:

ClassMethod IsJson4()
{
	s q1 = "SELECT Title,%OBJECT(Picture) AS PhotoOref FROM Sample.Employee "
	s q2 = "WHERE Picture IS NOT JSON"
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
}

IS JSON可以在任何可以指定谓词条件的地方使用,如本手册的谓词概述页面所述。

0
0 105
文章 姚 鑫 · 十二月 11, 2021 2m read

第十二章 SQL谓词 %INSET

将一个值匹配到一组生成的值。

大纲

scalar-expression %INSET valueset [SIZE ((nn))]

参数

  • scalar-expression - 一个标量表达式(最常见的是表的RowId字段),它的值正在与值集进行比较。
  • valueset - 对实现ContainsItem()方法的用户定义对象的对象引用(oref)。 该方法接受一组数据值,并在与标量表达式中的值匹配时返回一个布尔值。
  • SIZE ((nn)) - 可选-用于查询优化的数量级整数(10、100、1000等)。

描述

%INSET谓词允许通过选择与值集中指定的值相匹配的数据值来筛选结果集。 当标量表达式的值与valueset中的值匹配时,此匹配将成功。 如果值集值不匹配任何标量表达式值,%INSET返回空字符串。 无论显示模式如何,这个匹配总是在逻辑(内部存储)数据值上执行。

对于NULL值,%INSET永远不为真。 因此,它不会将标量表达式中的NULL与值集中的NULL相匹配。

与其他比较条件一样,%INSET用于SELECT语句的WHERE子句或HAVING子句中。

%INSET启用使用抽象的、编程指定的匹配值集过滤字段值。 具体地说,它使用抽象的、编程指定的临时文件或位图索引来过滤RowId字段值,其中的值集行为类似于位图索引或常规索引的最低下标层。

用户定义的类派生自抽象类%SQL.AbstractFind。此抽象类定义ContainsItem()方法,该方法是%inset唯一支持的方法。ContainsItem()方法返回值集。

排序类型

%INSET使用与它匹配的列相同的排序规则类型。 默认情况下,字符串数据类型字段是用SQLUPPER排序规则定义的,它不区分大小写。

如果为列分配不同的排序规则类型,则还必须将此排序规则类型应用于%INSET子字符串。

Size子句

可选的%INSET SIZE子句提供整数nn,它指定valueset中值数量的数量级估计值。 IRIS使用这个数量级估计来确定最佳查询计划。 指定nn为以下文字之一:10、100、1000、10000,等等。 因为nn必须在编译时作为常量值可用,所以在所有SQL代码中必须将其指定为文字。 注意,必须为所有SQL指定嵌套括号,嵌入式SQL除外。

%INSET和%FIND比较

  • INSET是最简单和最通用的接口。 它支持ContainsItem()方法。
  • %FIND支持使用位图索引对位图块进行迭代。 它模拟了ObjectScript $ORDER函数的功能,支持NextChunk()PreviousChunk()GetChunk()迭代方法,以及ContainsItem()方法。
0
0 128
文章 姚 鑫 · 十二月 10, 2021 8m read

第十一章 SQL谓词 %INLIST

将一个值匹配到%List结构化列表中的元素。

大纲

scalar-expression %INLIST list [SIZE ((nn))]

参数

  • scalar-expression - 将其值与列表元素进行比较的标量表达式(最常见的是数据列)。
  • list - 包含一个或多个元素的%List结构。
  • SIZE ((nn)) - 可选-指定列表中元素数量估计值的整数。 必须指定为具有下列值之一的字面值:10100100010000,等等。

描述

%INLIST谓词是 IRIS扩展,用于将字段的值与列表结构的元素匹配。 %INLISTIN都允对多个指定值执行这样的相等比较。 %INLIST将这些多个值指定为单个列表参数的元素。 因此,%INLIST允许改变要匹配的值的数量,而无需创建单独的缓存查询。

可选的%INLIST SIZE子句提供整数nn,它指定list中列表元素数量的数量级估计数。 IRIS使用这个数量级估计来确定最佳查询计划。 因为不管列表中元素的数量是多少,都会使用相同的缓存查询,所以指定SIZE允许创建缓存查询,针对列表中预期的元素的大致数量进行优化。 更改SIZE字面值将创建一个单独的缓存查询。 指定nn为以下文字之一:10100100010000,等等。 因为nn必须在编译时作为常量值可用,所以在所有SQL代码中必须将其指定为文字。 注意,必须为所有已编译SQL (Dynamic SQL)指定双括号。 双括号不用于嵌入式SQL。

%INLISTlist中的每个元素执行相等比较。 %INLIST比较使用为标量表达式定义的排序规则类型。 因此,列表元素的比较可能区分大小写,也可能不区分大小写,这取决于标量表达式的排序规则。 默认情况下,字符串数据类型字段是用SQLUPPER排序规则定义的,它不区分大小写。

指定NULL作为比较值是没有意义的。 NULL表示没有值,因此无法通过所有相等测试。 指定%INLIST谓词(或任何其他谓词)将消除指定字段的任何NULL实例。 必须指定IS NULL谓词,以便在谓词结果集中包含带有NULL的字段。

与大多数谓词一样,%INLIST可以使用NOT逻辑操作符进行反转。 %INLISTNOT %INLIST都不能返回空字段。 返回NULL字段使用IS NULL

如果匹配表达式不是%List格式,%INLIST将生成一个SQLCODE -400错误。 例如,如果集合属性的SqlListTypeDELIMITED,则列表字段的逻辑值不是%list格式。

要将值匹配到非结构化的项系列,如逗号分隔的值列表,请使用IN谓词。 IN可以执行相等比较和子查询比较。

%SelectMode

%INLIST谓词不使用当前的%SelectMode设置。 列表的元素应该以逻辑格式指定,无论%SelectMode设置如何。 试图以ODBC格式或Display格式指定列表元素通常会导致没有数据匹配或意外的数据匹配。

可以使用%EXTERNAL%ODBCOUT格式转换函数来转换谓词操作的标量表达式字段。 这允许以Display格式或ODBC格式指定列表元素。 但是,使用格式转换函数会阻止对字段使用索引,因此会对性能产生重大影响。

在下面的Dynamic SQL示例中,%INLIST谓词指定一个包含1978年日期值元素的列表,其格式为逻辑格式,而不是%SelectMode=1 (ODBC)格式。 与这些$HOROLOG格式日期对应的日期被选中:

ClassMethod List()
{
	s bday = $lb(50039)
	for i = 50039 : 1 : 50403 {
		s bday = bday _ $lb(i) 
	}
	s q1 = "SELECT Name,DOB FROM Sample.Person "
	s q2 = "WHERE DOB %INLIST ?"
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode = 1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(bday)
	d rset.%Display()
}
DHC-APP> d ##class(PHA.TEST.SQLCommand).List()
Name    DOB
姚鑫    1978-01-28
Chadwick,Zelda S.Chadwick,Zelda S.Chadwick,Zelda S.Chadwick,Zelda S.Chadwick,Zelda S.   1978-01-28
Isaacs,Chad N.  1978-09-13
Ximines,Kim S.  1978-04-07
 
4 Rows(s) Affected

下面的动态SQL示例使用%ODBCOUT格式转换函数来转换谓词匹配的DOB字段。 这允许以ODBC格式指定%INLIST列表元素。 但是,指定格式转换函数会阻止对DOB字段值使用索引:

ClassMethod List1()
{
	s births = $LISTBUILD("1978-01-15", "1978-08-22", "1990-04-25")
	s q1 = "SELECT Name,DOB FROM Sample.Person "
	s q2 = "WHERE %ODBCOUT(DOB) %INLIST ?"
	s myquery = q1 _ q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode = 1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(births)
	d rset.%Display()
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).List1()
Name    DOB
yaoxin  1990-04-25
 
1 Rows(s) Affected

%INLIST and IN

%INLISTIN谓词都可以用于提供多个值来进行相等比较。 下面的动态SQL示例返回相同的结果:

ClassMethod List2()
{
	s states = $lb("VT","NH","ME")
	s myquery = "SELECT Name,Home_State FROM Sample.Person WHERE Home_State %INLIST ?"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(states)
	d rset.%Display()
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).List2()
Name    Home_State
Lepon,Jeff Z.   NH
Ingleman,Terry A.       NH
Jung,Keith W.   NH
Xiang,Kirsten U.        ME
Jackson,Ralph V.        VT
Tesla,Geoffrey O.       NH
Tweed,Al O.     NH
Fives,Kristen F.        NH
Ingrahm,Susan N.        ME
Lepon,Janice T. ME
Wilson,Andrew O.        ME
Olsen,Ashley G. NH
 
12 Rows(s) Affected
ClassMethod List3()
{
	s s1="VT"
	s s2="NH"
	s s3="ME"
	s myquery = "SELECT Name,Home_State FROM Sample.Person WHERE Home_State IN(?,?,?)"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(s1,s2,s3)
	d rset.%Display()
}

然而,在动态SQL中,可以提供%INLIST谓词值作为单个主机变量; 必须将IN谓词值作为单独的主机变量提供。 因此,更改IN谓词值的数量将导致创建一个单独的缓存查询。 更改%INLIST谓词值的数量不会导致创建单独的缓存查询。

示例

下面的示例将Home_State列值与新英格兰北部州的结构化列表的元素匹配:

ClassMethod List4()
{
	s states=$LISTBUILD("VT","NH","ME")
	s myquery="SELECT Name,Home_State FROM Sample.Person "_
	          "WHERE Home_State %INLIST ?"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(states)
	d rset.%Display()
}

下面两个示例说明排序规则匹配是基于标量表达式排序规则的。 Home_State字段是用SQLUPPER排序规则定义的,它不区分大小写。 这些例子中的列表将新罕布什尔州指定为“nH”,而不是“NH”。 第一个示例返回NH Home_State值,第二个示例不返回NH Home_State值:

ClassMethod List5()
{
	s states=$LISTBUILD("VT","nH","ME")
	s myquery="SELECT Name,Home_State FROM Sample.Person "_
	          "WHERE Home_State %INLIST ?"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(states)
	d rset.%Display()
}
ClassMethod List6()
{
	s states=$LISTBUILD("VT","nH","ME")
	s myquery="SELECT Name,Home_State FROM Sample.Person "_
	          "WHERE %EXACT(Home_State) %INLIST ?"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(states)
	d rset.%Display()
}

下面的示例创建了一个SIZE10的缓存查询。 对于该查询,指定SIZE 10是最优的,因为10对应于列表中的实际元素数量。 改变列表中的元素数量并不会创建一个单独的缓存查询。 改变SIZE字面值确实会创建一个单独的缓存查询:

ClassMethod List7()
{
	s states=$LISTBUILD("VT","NH","ME")
	s myquery="SELECT Name,Home_State FROM Sample.Person "_
	          "WHERE Home_State %INLIST ? SIZE ((10))"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(states)
	d rset.%Display()
}

ClassMethod List8()
{
	s states=$LISTBUILD("VT","nH","ME")
	s myquery="SELECT Name,Home_State FROM Sample.Person "_
	          "WHERE Home_State %INLIST ?"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(states)
	d rset.%Display()
}

下面的示例创建了一个SIZE10的缓存查询。 对于该查询,指定SIZE 10是最优的,因为10对应于列表中的实际元素数量。 改变列表中的元素数量并不会创建一个单独的缓存查询。 改变SIZE字面值确实会创建一个单独的缓存查询:

ClassMethod List9()
{
	s states=$LISTBUILD("VT","NH","ME")
	s myquery="SELECT Name,Home_State FROM Sample.Person "_
	          "WHERE Home_State %INLIST ? SIZE ((10))"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT}
	s rset = tStatement.%Execute(states)
	d rset.%Display()
}
0
0 64
文章 姚 鑫 · 十二月 9, 2021 5m read

第十章 SQL谓词 IN

将值匹配到以逗号分隔的非结构化列表中的项。

大纲

scalar-expression IN (item1,item2[,...])

scalar-expression IN (subquery)

参数

  • scalar-expression - 标量表达式(最常见的是数据列),将其值与以逗号分隔的值列表或子查询生成的结果集进行比较。
  • item - 一个或多个文本值、输入主机变量或解析为文本值的表达式。 以任何顺序列出,以逗号分隔。
  • subquery - 一个用括号括起来的子查询,它从单个列返回一个结果集,用于与标量表达式进行比较。

描述

IN谓词用于将值匹配到非结构化的项系列。 通常,它将列数据值与以逗号分隔的值列表进行比较。 IN可以执行相等比较和子查询比较。

与大多数谓词一样,可以使用NOT逻辑操作符反转ININNOT IN都不能用于返回空字段。 返回NULL字段使用IS NULL

可以在任何可以指定谓词条件的地方使用IN,如本手册的谓词概述页面所述。

相等测试

IN谓词可以用作多个相等比较的简写,这些比较用OR操作符连接在一起。 例如:

SELECT Name, Home_State FROM Sample.Person
WHERE Home_State IN ('ME','NH','VT','MA','RI','CT') 

如果Home_State等于逗号分隔列表中的任何值,则计算为true。 列出的项可以是常量或表达式。

IN比较使用为标量表达式定义的排序规则类型,而不考虑单个项的排序规则类型。 默认情况下,字符串数据类型字段是用SQLUPPER排序规则定义的,它不区分大小写。

下面两个示例说明排序规则匹配是基于标量表达式排序规则的。 Home_State字段是用SQLUPPER(不区分大小写)排序规则定义的。 因此,下面的示例返回NH Home_State值:

SELECT Name, Home_State FROM Sample.Person
WHERE Home_State IN ('ME','nH','VT')

下面的示例不返回NH Home_State值:

SELECT Name, Home_State FROM Sample.Person
WHERE %EXACT(Home_State) IN ('ME','nH','VT')

在值列表中包含NULL没有意义。 NULL表示没有值,因此无法通过所有相等测试。 指定IN谓词(或任何其他谓词)将消除指定字段的任何NULL实例。 这在以下不正确(但可执行)的示例中显示:

SELECT FavoriteColors FROM Sample.Person
WHERE FavoriteColors IN ($LISTBUILD('Red'),$LISTBUILD('Blue'),NULL)
  /* NULL here is meaningless. No FavoriteColor NULL fields returned */

在谓词结果集中包含NULL字段的唯一方法是指定is NULL谓词,如下例所示:

SELECT FavoriteColors FROM Sample.Person
WHERE FavoriteColors IN ($LISTBUILD('Red'),$LISTBUILD('Blue')) OR FavoriteColors IS NULL

当使用日期或时间进行IN谓词相等性比较时,将自动执行适当的数据类型转换。 如果WHERE字段类型为TimeStamp,则DateTime类型的值将转换为TimeStamp。 如果WHERE字段类型为Date,则类型为TimeStampString的值将转换为Date。 如果WHERE字段为type Time,则类型为TimeStampString的值将转换为Time

下面的示例执行相同的相等比较并返回相同的数据。 DOB字段的数据类型为Date:

SELECT Name,DOB FROM Sample.Person 
WHERE DOB IN ({d '1951-02-02'},{d '1987-02-28'})

image

SELECT Name,DOB FROM Sample.Person 
WHERE DOB IN ({ts '1951-02-02 02:37:00'},{ts '1987-02-28 16:58:10'})

%SelectMode

如果%SelectMode设置为逻辑格式以外的值,那么IN谓词值必须以%SelectMode格式(ODBCDisplay)指定。 这主要适用于日期、时间和IRIS格式列表(%List)。 以逻辑格式指定谓词值通常会导致SQLCODE错误。 例如,SQLCODE -146“无法将日期输入转换为有效的逻辑日期值”。

在以下动态SQL示例中,In谓词必须以%SelectMode=1 (ODBC)格式指定日期:

/// d ##class(PHA.TEST.SQLCommand).In()
ClassMethod In()
{
	s q1 = "SELECT Name,DOB FROM Sample.Person "
	s q2 = "WHERE DOB IN('1956-03-05','1956-04-08','1956-04-18','1990-04-25')"
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}

子查询比较

可以在子查询中使用IN谓词来测试列值(或任何其他表达式)是否等于任何子查询行值。 例如:

SELECT Name,Home_State FROM Sample.Person
WHERE Name IN 
   (SELECT Name FROM Sample.Employee
    HAVING Salary < 50000)

注意,子查询在SELECT列表中必须只有一个选择项。

下面的例子使用一个IN子查询返回不是Vendor状态的`Employee状态:

SELECT Home_State
FROM Sample.Employee
WHERE Home_State NOT IN (SELECT Address_State FROM Sample.Vendor)
GROUP BY Home_State

下面的示例将排序规则函数表达式匹配到带有子查询的IN谓词:

SELECT Name,Id FROM Sample.Person
WHERE %EXACT(Spouse) NOT IN
   (SELECT Id FROM Sample.Person
    WHERE Age < 65)

IN不能同时指定子查询和逗号分隔的文字值列表。

文字替换覆盖

在编译预解析期间,可以用圆括号将每个IN谓词参数括起来,从而覆盖文字替换。 例如,WHERE Home_State IN (('ME'),('NH'),('VT'),('MA'),('RI'),('CT'))。 这可以通过改善整体选择性和/或下标边界选择性来提高查询性能。 但是,当使用不同的值多次调用同一个查询时,应该避免使用这种方法,因为这将导致为每个查询调用创建一个单独的缓存查询。

IN and %INLIST

IN%INLIST谓词都可以用于提供多个值来进行OR相等比较。 %INLIST谓词用于将值匹配到%List结构的元素。 在动态SQL中,可以将%INLIST谓词值作为单个主机变量提供。 必须将IN谓词值作为单独的主机变量提供。 因此,更改IN谓词值的数量将导致创建一个单独的缓存查询。 %INLIST接受一个谓词值,一个包含多个元素的%List; 更改%List元素的数量不会导致创建一个单独的缓存查询。 %INLIST还提供了一个数量级的SIZE参数,SQL使用它来优化性能。 由于这些原因,使用它通常是有利的

%INLIST($LISTFROMSTRING(val)) rather than IN(val1,val2,val3,..valn).

%INLIST可以执行相等比较; 它不能执行子查询比较。

0
0 101
文章 姚 鑫 · 十二月 8, 2021 5m read

第九章 SQL谓词 FOR SOME %ELEMENT

将列表元素值或列表元素的数量与谓词匹配。

大纲

FOR SOME %ELEMENT(field) [[AS] e-alias] (predicate)

参数

  • field - 将其元素与谓词进行比较的标量表达式(最常见的是数据列)。
  • AS e-alias - 可选-用于限定谓词中的%KEY%VALUE的元素别名。通常,当谓词包含嵌套的FOR某些%ELEMENT条件时,会使用此别名。别名必须是有效的标识符。
  • (predicate) - 用括号括起来的谓词条件。 在这个条件中,使用%VALUE/%KEY来确定条件匹配的是什么。 %VALUE匹配元素值(%VALUE= ' Red ')。 %KEY匹配元素的最小数目(%KEY=2)。 在此条件下,如果您指定了e-alias%VALUE%KEY可能是可选限定的。 这个谓词可以由多个带有ANDOR逻辑运算符的条件表达式组成。

描述

FOR SOME %ELEMENT谓词将字段中的列表元素与指定的谓词匹配。 SOME关键字指定字段中至少有一个元素必须满足指定的谓词子句。

谓词子句必须包含%VALUE%KEY关键字,后跟谓词条件。 这些关键字不区分大小写。

下面的例子解释了%VALUE%KEY的用法:

  • (%VALUE=’Red’) 匹配所有包含值Red作为其列表元素之一的字段值。 该字段可以只包含单个元素Red,也可以包含多个元素,其中一个元素是Red
  • (%KEY=2)匹配所有包含至少2个元素的字段值。 字段可以包含两个元素,也可以包含两个以上的元素。 %KEY值必须为正整数。 (%KEY=0)不匹配任何字段值。

FOR SOME %ELEMENT 不能用于匹配为空的字段。

谓词子句可以使用任何谓词条件,而不仅仅是相等条件。以下是谓词子句的一些示例:

(%VALUE='Red')
(%VALUE > 21)
(%VALUE %STARTSWITH 'R')
(%VALUE [ 'e')
(%VALUE IN ('Red','Blue')
(%VALUE IS NOT NULL)
(%KEY=3)
(%KEY > 1)
(%KEY IS NOT NULL)

注意:当在运行时提供谓词值时(使用? 输入参数或:var输入主机变量),结果谓词%STARTSWITH 'abc'提供了比等价的结果谓词'abc%'更好的性能。

可以使用ANDORNOT逻辑操作符指定多个谓词条件。 IRIS将组合的谓词条件应用于每个元素。 因此,使用AND测试应用两个%VALUE或两个%KEY谓词是没有意义的。

例如,使用For SOME %ELEMENT匹配包含值RedGreenRed GreenBlack RedGreen Yellow RedGreen BlackYellowBlack Yellow的字段:

  • (%VALUE='Red')匹配任何包含元素Red: RedRed GreenBlack RedRed Yellow Green的字段。
  • (%VALUE='Red' OR %VALUE='Green')匹配任何包含其中一个元素(或同时包含两个元素,按任意顺序)的字段:Red, Green, Red Green, Black Red, Green Yellow Red, Green Black。 这在功能上与(%VALUE IN('Red','Green'))相同。
  • (%VALUE='Red' AND %VALUE='Green')不匹配字段值,因为它同时匹配RedGreen的每个元素,并且没有元素可以同时拥有RedGreen的值。 此谓词不匹配双元素值Red Green
  • (%VALUE='Red' AND %KEY=2) 匹配 Red Green, Black Red, Green Yellow Red.
  • (%value=‘Red’或%key=2)匹配Red, Red Green, Black Red, Green Yellow Red, Green Black, Black Yellow.

FOR SOME %ELEMENT是一个集合谓词。 它可以用于可以指定谓词条件的大多数上下文中,如本手册的谓词概述页面所述。 受以下限制:

  • 不能在HAVING子句中使用FOR SOME %ELEMENT
  • 不能使用FOR SOME %ELEMENT作为为JOIN操作选择字段的谓词。
  • 如果两个谓词引用不同表中的字段,则不能使用OR逻辑操作符将FOR SOME %ELEMENT与另一个谓词条件关联。 例如:
WHERE FOR SOME %ELEMENT(t1.FavoriteColors) (%VALUE='purple') OR t2.Age < 65

因为此限制取决于优化器如何使用索引,所以SQL可能只在将索引添加到表时执行此限制。 强烈建议在所有查询中避免这种类型的逻辑。

  • 在查询分片表时,不能使用FOR SOME %ELEMENT

Collection Index

FOR SOME %ELEMENT的一个重要用途是使用集合索引选择元素。 如果为字段定义了适当的KEYSELEMENTS索引, IRIS将使用该索引,而不是直接引用字段值元素。

如果定义了以下集合索引:

 INDEX fcIDX1 ON FavoriteColors(ELEMENTS);

下面的查询使用了这个索引:

SELECT Name,FavoriteColors FROM Sample.Person
WHERE FOR SOME %ELEMENT(FavoriteColors) (%VALUE='Red')

如果定义了以下集合索引:

 INDEX fcIDX2 ON FavoriteColors(KEYS) [ Type = bitmap ];

下面的查询使用了这个索引:

SELECT Name,FavoriteColors FROM Sample.Person
WHERE FOR SOME %ELEMENT(FavoriteColors) (%KEY=2)

示例

下面的示例使用FOR SOME %ELEMENT返回FavoriteColors列表中包含元素'Red'的那些行:

SELECT Name,FavoriteColors
FROM Sample.Person
WHERE FOR SOME %ELEMENT(FavoriteColors) (%VALUE='Red')

image

在下面的示例中,%VALUE谓词包含一个In语句,该语句指定一个用逗号分隔的列表。 这个例子返回FavoriteColors列表中包含元素'Red'或元素'Blue'(或两者都包含)的那些行:

SELECT Name,FavoriteColors
FROM Sample.Person
WHERE FOR SOME %ELEMENT(FavoriteColors) (%VALUE IN ('Red','Blue'))

image

下面的示例使用带有两个Contains操作符([)的谓词子句。 它返回那些FavoriteColors列表中包含包含小写'l'和小写'e'的元素的行(contains操作符是大小写敏感的)。 在本例中,元素“Blue”“Yellow”“Purple”:

SELECT Name,FavoriteColors AS Preferences
FROM Sample.Person
WHERE FOR SOME %ELEMENT(FavoriteColors) AS fc (fc.%VALUE [ 'l' AND fc.%VALUE [ 'e')

image

这个示例还演示了如何使用元素别名。

下面的动态SQL示例使用%KEY根据FavoriteColors中的元素数量返回行。 第一个%Execute()设置%KEY=1,返回所有包含一个或多个FavoriteColors元素的行。 第二个%Execute()设置%KEY=2,返回所有包含两个或更多favoritecolor元素的行:

ClassMethod ForSomeElement()
{
	s q1 = "SELECT %ID,Name,FavoriteColors FROM Sample.Person "
	s q2 = "WHERE FOR SOME %ELEMENT(FavoriteColors) (%KEY=?)"
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute(1)
	d rset.%Display()
	w !,"End of data %KEY 1",!!
	s rset = tStatement.%Execute(2)
	d rset.%Display()
	w !,"End of data %KEY 2"
}
0
0 82
文章 姚 鑫 · 十二月 7, 2021 4m read

第八章 SQL谓词 FOR SOME

确定是否根据字段值的条件测试返回记录。

大纲

FOR SOME (table [AS t-alias]) (fieldcondition)

参数

  • table - Table可以是单个表,也可以是用逗号分隔的表列表。 括号是必须的。

  • AS t-alias - 可选-前一个表名的别名。 别名必须是有效的标识符; 它可以是一个分隔符。

  • fieldcondition - fieldcondition 指定一个或多个引用一个或多个字段的条件表达式。 字段条件用括号括起来。 可以使用AND(&)OR(!)逻辑操作符在字段条件中指定多个条件表达式。

描述

FOR SOME谓词允许根据表中一个或多个字段值的布尔条件测试来决定是否返回记录。 如果fieldcondition计算结果为true,则返回记录。 如果fieldcondition计算结果为false,则不返回记录。

对于表(及其可选的t-alias)参数,必须使用括号分隔。 分隔括号对于字段条件参数也是强制性的。 允许(但不是必需的)在这两组括号之间使用空格。

通常,FOR SOME用于确定是否根据另一个表中一条记录的内容从一个表返回一条记录。 FOR SOME还可用于确定是否根据同一表中记录的内容从表中返回记录。 在后一种情况下,要么返回所有记录,要么不返回任何记录。

在下面的示例中,For Some返回Sample.Person表中其Name字段值与Sample.Employee表中的Name字段值匹配的所有记录:

SELECT Name,COUNT(Name) AS NameCount
FROM Sample.Person AS p
WHERE FOR SOME (Sample.Employee AS e)(e.Name=p.Name)
ORDER BY Name

在下面的示例中,FOR根据同一表的布尔测试返回Sample.Person表中的某些记录。如果至少有一条记录的年龄值大于65,此程序将返回所有Sample.Person记录。否则,它不返回任何记录。由于Sample.Person中至少有一条记录的年龄字段值大于65,因此将返回所有Sample.Person记录:

SELECT Name,Age,COUNT(Name) AS NameCount
FROM Sample.Person
WHERE FOR SOME (Sample.Person)(Age>65)
ORDER BY Age

与大多数谓词一样,可以使用NOT逻辑运算符对某些谓词进行倒置,如下例所示:

SELECT Name,Age,COUNT(Name) AS NameCount
FROM Sample.Person
WHERE NOT FOR SOME (Sample.Person)(Age>65)
ORDER BY Age

复合条件

一个字段条件可以包含多个条件表达式。这组条件包含在圆括号中。使用逻辑运算符ANDOR指定多个条件,这些条件也可以使用

SELECT Name,COUNT(Name) AS NameCount
FROM Sample.Person AS p
WHERE FOR SOME (Sample.Employee AS e)(e.Name=p.Name AND p.Name %STARTSWITH 'A')
ORDER BY Name
SELECT Name,COUNT(Name) AS NameCount
FROM Sample.Person AS p
WHERE FOR SOME (Sample.Employee AS e)(e.Name=p.Name OR  p.Name %STARTSWITH 'A')
ORDER BY Name

在以下示例中,对于某些记录,返回Sample.Person表中其Name字段值与Sample.Employee表中的Name字段值匹配,并且其住所(Home_State)与其办公室(Office_State)处于相同状态的所有记录:

SELECT Name,Home_State,COUNT(Name) AS NameCount
FROM Sample.Person AS p
WHERE FOR SOME (Sample.Employee AS e)(p.Name=e.Name AND p.Home_State=e.Office_State)
ORDER BY Name

多个表

可以在字段条件之前以逗号分隔的列表形式指定多个表。 确定是否返回记录的条件可以引用从中选择数据的表,也可以引用另一个表中的字段值。 表别名通常需要将每个指定的字段与其表关联起来。

在下面的示例中,如果Sample.Person表中至少有一个名称也在Sample.Employee表中,则返回所有记录。由于至少有一条记录满足此条件,因此将返回所有Sample.Person记录:

SELECT Name AS PersonName,Age,COUNT(Name) AS NameCount
FROM Sample.Person
WHERE FOR SOME (Sample.Employee AS e,Sample.Person AS p) (e.Name=p.Name)
ORDER BY Name

在下面的示例中,如果Sample.Person表中至少有一个名称也在Sample.Company表中找到,则返回所有记录。由于人名和公司名(在此数据集中)从不相同,因此此条件不适用于任何记录。因此,不返回Sample.Person记录:

SELECT Name AS PersonName,Age,COUNT(Name) AS NameCount
FROM Sample.Person
WHERE FOR SOME (Sample.Company AS c,Sample.Person AS p) (c.Name=p.Name)
ORDER BY Name
0
0 136
文章 姚 鑫 · 十二月 6, 2021 2m read

第七章 SQL谓词 %FIND

使用位图块迭代将一个值匹配到一组生成的值。

大纲

scalar-expression %FIND valueset [SIZE ((nn))]

参数

  • scalar-expression - 一个标量表达式(最常见的是表的RowId字段),它的值正在与值集进行比较。
  • valueset - 对用户定义对象的对象引用(oref),该对象实现位图块迭代方法和ContainsItem()方法。 该方法接受一组数据值,并在与标量表达式中的值匹配时返回一个布尔值。
  • SIZE ((nn)) - 可选-用于查询优化的数量级整数(101001000等)。

描述

通过选择与值集中指定的值相匹配的数据值,通过迭代位图块序列中的值,%FIND谓词允许筛选结果集。 当标量表达式的值与valueset中的值匹配时,此匹配将成功。 如果值集值不匹配任何标量表达式值,%FIND返回空字符串。 无论显示模式如何,这个匹配总是在逻辑(内部存储)数据值上执行。

%FIND和其他比较条件一样,用于SELECT语句的WHERE子句或HAVING子句中。

%FIND使用抽象的、通过编程指定的匹配值集来过滤字段值。 具体来说,它使用抽象的、编程指定的位图来过滤RowId字段值,其中的值集行为类似于位图索引的下标层。

用户定义类派生自抽象类%SQL.AbstractFind。 这个抽象类定义了ContainsItem()布尔方法。 ContainsItem()方法将标量表达式值与值集值匹配。

使用以下三种方法对位图块序列中的值进行迭代:

  • GetChunk(c),返回块编号为c的位图块。
  • NextChunk(.c),它返回第一个块编号为> c的位图块。
  • PreviousChunk(.c),返回第一个块号< c的位图块。

排序类型

%FIND使用与它匹配的列相同的排序规则类型。 默认情况下,字符串数据类型字段是用SQLUPPER排序规则定义的,它不区分大小写。

SIZE子句

可选的%FIND SIZE子句提供整数nn,它指定valueset中值数量的数量级估计数。 IRIS使用这个数量级估计来确定最佳查询计划。 指定nn为以下文字之一:10100100010000,等等。 因为nn必须在编译时作为常量值可用,所以在所有SQL代码中必须将其指定为文字。 注意,必须为所有SQL指定嵌套括号,嵌入式SQL除外。

%FIND和%INSET比较

  • INSET是最简单和最通用的接口。 它支持ContainsItem()方法。
  • %FIND支持使用位图索引对位图块进行迭代。 它模拟了ObjectScript $ORDER函数的功能,支持NextChunk()PreviousChunk()GetChunk()迭代方法,以及ContainsItem()方法。
0
0 106
文章 姚 鑫 · 十二月 6, 2021 1m read

第六章 SQL谓词 EXISTS

检查表中是否至少存在一个对应行。

大纲

EXISTS select-statement

参数

  • select-statement - 一种简单的查询,通常包含一个条件表达式。

描述

EXISTS谓词测试指定的表,通常至少测试一行是否存在。 因为EXISTS后面的SELECT语句正在被检查是否包含某些内容,所以子句通常是这样的形式:

EXISTS (SELECT... FROM... WHERE...)
SELECT name
     FROM Table_A
     WHERE EXISTS
     (SELECT *
          FROM Table_B
          WHERE Table_B.Number = Table_A.Number)

在本例中,谓词测试子查询指定的一行或多行是否存在。

注意,测试必须发生在SELECT语句上(而不是在UNION上)。

NOT EXISTS子句测试表中是否有一行不存在,如下例所示:

SELECT EmployeeName,Age
     FROM Employees
     WHERE NOT EXISTS (SELECT * FROM BonusTable
     WHERE NOT (BonusTable.Result = 'Positive'
     AND Employees.EmployeeNum = BonusTable.EmployeeNum))

EXISTS可以在任何可以指定谓词条件的地方使用,如本手册的谓词概述页面所述。

在适用的情况下,系统自动对存在或不存在的子查询应用集值子查询优化(SVSO)。

0
0 119
文章 姚 鑫 · 十二月 4, 2021 4m read

第五章 SQL谓词 BETWEEN

大纲

scalar-expression BETWEEN lowval AND highval

参数

  • scalar-expression - 一种标量表达式(最常见的是数据列),将其值与低值和高值(包括高值)之间的值范围进行比较。
  • lowval - 解析为低排序规则序列值的表达式,指定与标量表达式中的每个值匹配的值范围的开始。
  • highval - 解析为高排序规则序列值的表达式,指定要与标量表达式中的每个值匹配的值范围的末尾。

描述

BETWEEN谓词允许选择lowvalhighval指定范围内的数据值。 这个范围包括低值和高值本身。 这等价于一对大于或等于操作符和一对小于或等于操作符。 下面的例子展示了这种比较:

SELECT Name,Age FROM Sample.Person
WHERE Age BETWEEN 18 AND 21
ORDER BY Age

这将返回Sample中的所有记录。 年龄值介于1821之间的人员表,包括这些值。 注意,必须按升序指定BETWEEN值; 例如BETWEEN 21 AND 18这样的谓词将返回空字符串。 如果标量表达式的值都不在指定的范围内,则BETWEEN返回空字符串。

与大多数谓词一样,BETWEEN可以使用NOT逻辑运算符进行反转。 BETWEENNOT BETWEEN都不能用于返回NULL字段。 返回NULL字段使用IS NULLNOT BETWEEN的示例如下:

SELECT Name,Age FROM Sample.Person
WHERE Age NOT BETWEEN 20 AND 55
ORDER BY Age

这将返回Sample中的所有记录。 年龄值小于20或大于55的人表,不包括这些值。

排序类型

BETWEEN通常用于按数字顺序排序的数值范围。 但是,BETWEEN可用于任何数据类型值的排序规则序列范围。

BETWEEN使用与它所匹配的列相同的排序规则类型。 默认情况下,字符串数据类型排序为SQLUPPER,这是不区分大小写的。

如果查询为列分配了不同的排序规则类型,则还必须将此排序规则类型应用于BETWEEN子字符串。 下面的例子说明了这一点:

在下面的示例中,BETWEEN使用字段的默认字母大小写排序规则SQLUPPER,它不区分大小写。 它返回Name的字母顺序比Home_State高,Home_State的字母顺序比Home_City高的记录:

SELECT Name,Home_State,Home_City
FROM Sample.Person
WHERE Home_State BETWEEN Name AND Home_City
ORDER BY Home_State

在下例中,BETWEEN字符串比较不区分大小写,因为Home_State字段被定义为SQLUPPER。 这意味着低val和高val在功能上是相同的,在任何字母中选择'MA':

SELECT Name,Home_State FROM Sample.Person
WHERE Home_State
   BETWEEN 'MA' AND 'Ma'
ORDER BY Home_State

在下面的示例中,%SQLSTRING排序函数使BETWEEN字符串比较区分大小写。 它选择那些Home_State值为'MA''MA'的记录,在这个数据集中包括'MA''MD''ME''MO''MS''MT':

SELECT Name,Home_State FROM Sample.Person
WHERE %SQLSTRING(Home_State) 
   BETWEEN %SQLSTRING('MA') AND %SQLSTRING('Ma')
ORDER BY Home_State

在以下示例中,BETWEEN字符串比较不区分大小写,并且忽略空格和标点符号:

SELECT Name FROM Sample.Person
WHERE %STRING(Name) BETWEEN %SQLSTRING('OA') AND %SQLSTRING('OZ')
ORDER BY Name

下面的示例显示了在内部连接操作ON子句中使用的BETWEEN。 它正在执行一个不区分大小写的字符串比较:

SELECT P.Name AS PersonName,E.Name AS EmpName 
FROM Sample.Person AS P INNER JOIN Sample.Employee AS E
ON P.Name BETWEEN 'an' AND 'ch' AND P.Name=E.Name

%SelectMode

如果%SelectMode设置为逻辑格式以外的值,那么BETWEEN谓词值必须以%SelectMode格式(ODBCDisplay)指定。 这主要适用于日期、时间和 IRIS格式列表(%List)。 以逻辑格式指定谓词值通常会导致SQLCODE错误。 例如,SQLCODE -146“无法将日期输入转换为有效的逻辑日期值”。

在下面的动态SQL示例中,BETWEEN谓词必须以%SelectMode=1 (ODBC)的格式指定日期:

ClassMethod Between()
{
	s q1 = "SELECT Name,DOB FROM Sample.Person "
	s q2 = "WHERE DOB BETWEEN '1950-01-01' AND '1960-01-01'"
	s myquery = q1_q2
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(myquery)
	if qStatus'=1 {
		w "%Prepare failed:" 
		d $System.Status.DisplayError(qStatus) 
		q
	}
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Between()
Name    DOB
Houseman,Martin D.      1955-09-25
Ingrahm,Yan S.  1954-06-15
Smith,Elvis Y.  1955-06-29
Gore,Alfred M.  1958-09-15
Yoders,Liza U.  1959-06-05
Ng,Liza Z.      1955-10-05
Yeats,Debby G.  1951-12-06
Zweifelhofer,Zelda J.   1954-02-19
Solomon,Emily D.        1953-01-28
Isaacs,Elvis V. 1952-04-05
Pantaleo,Robert U.      1950-03-29
Zampitello,Josephine Q. 1953-08-14
Xiang,Molly F.  1953-03-21
Nichols,Heloisa M.      1957-07-19
Hertz,Uma C.    1954-07-25
LaRocca,David X.        1956-01-11
Houseman,Alice R.       1957-12-07
Alton,Phil T.   1953-02-25
Davis,Jane E.   1953-07-28
Vanzetti,Alexandra O.   1953-12-29
Uhles,Dmitry P. 1951-08-23
Jafari,Christine Z.     1950-04-11
 
22 Rows(s) Affected
End of data
0
0 144
文章 姚 鑫 · 十二月 3, 2021 1m read

第四章 SQL谓词 ANY

将值与子查询中的至少一个匹配值匹配。

大纲

scalar-expression comparison-operator ANY (subquery)

参数

  • scalar-expression - 将其值与子查询生成的结果集进行比较的标量表达式(最常见的是数据列)。
  • comparison-operator - 以下比较操作符之一:=(等于),<>!=(不等于),<(小于),<=(小于或等于),>(大于),>=(大于或等于),[(包含),或](跟随)。
  • subquery - 一个用括号括起来的子查询,它返回一个用于与标量表达式比较的结果集。

描述

ANY关键字与比较操作符一起创建谓词(量化比较条件),如果标量表达式的值匹配子查询检索到的一个或多个对应值,则该谓词为真。 ANY谓词将单个标量表达式项与单个子查询SELECT项进行比较。 具有多个选择项的子查询将生成SQLCODE -10错误。

注意:ANYSOME关键字是同义词。

任何可以指定谓词条件的地方都可以使用ANY,如本手册的谓词概述页面所述。

在适用的情况下,系统自动对任意子查询应用集值子查询优化(SVSO)。

示例

下面的例子选择了居住在密西西比河以西任何一个州的工资超过75,000美元的员工:

SELECT Name,Salary,Home_State FROM Sample.Employee
WHERE Salary > 75000
AND Home_State = ANY
 (SELECT State FROM Sample.USZipCode
  WHERE Longitude < -93)
ORDER BY Home_State
0
0 132
文章 姚 鑫 · 十二月 2, 2021 2m read

第三章 SQL谓词 ALL

将值与子查询中的所有对应值匹配。

大纲

scalar-expression comparison-operator ALL (subquery)

参数

  • scalar-expression - 将其值与子查询生成的结果集进行比较的标量表达式(最常见的是数据列)。
  • comparison-operator - 以下比较操作符之一:=(等于),<>!=(不等于),<(小于),<=(小于或等于),>(大于),>=(大于或等于),[(包含),或](跟随)。
  • subquery - 一个用括号括起来的子查询,它从单个列返回一个结果集,用于与标量表达式进行比较。

描述

ALL关键字与比较操作符一起创建谓词(量化比较条件),如果标量表达式的值与子查询检索到的所有对应值匹配,则该谓词为真。 ALL谓词将单个标量表达式项与单个子查询SELECT项进行比较。 具有多个选择项的子查询将生成SQLCODE -10错误。

ALL可以在任何可以指定谓词条件的地方使用,如本手册的谓词概述页面所述。

在适用的情况下,系统自动对ALL子查询应用集值子查询优化(SVSO)。

示例

下面的示例选择了Person数据库中小于Employee数据库中所有年龄的年龄:

SELECT DISTINCT Age FROM Sample.Person
WHERE Age < ALL
   (SELECT Age FROM Sample.Employee)
ORDER BY Age

下面的示例选择Person数据库中比Employee数据库中所有名称更长或更短的名称:

SELECT $LENGTH(Name) AS NameLength,Name FROM Sample.Person
WHERE $LENGTH(Name) > ALL
     (SELECT $LENGTH(Name) FROM Sample.Employee)
OR $LENGTH(Name) < ALL
     (SELECT $LENGTH(Name) FROM Sample.Employee)

image

下面的示例返回密西西比河以西的州的列表,所有州都不包含拥有经理或董事头衔的员工:

SELECT DISTINCT State
FROM Sample.USZipCode
WHERE Longitude < -93
  AND State != ALL
   (SELECT Home_State FROM Sample.Employee
    WHERE Title [ 'Manager' OR Title [ 'Director')
ORDER BY State
0
0 122