0 关注者 · 478 帖子

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

文章 姚 鑫 · 二月 28, 2022 5m read

第六十八章 SQL函数 JSON_ARRAY

JSON数组形式返回数据的转换函数。

大纲

JSON_ARRAY(expression [,expression][,...] [NULL ON NULL | ABSENT ON NULL])

参数

  • expression - 表达式或逗号分隔的表达式列表。这些表达式可以包括列名、聚合函数、算术表达式、文字和文字NULL
  • ABSENT ON NULLNULL ON NULL - 可选-指定如何在返回的JSON数组中表示空值的关键字短语。NULL ON NULL(缺省值)表示带有单词NULL(未引号)的NULL(缺少)数据。在NULL上不存在将从JSON数组中省略空数据;它不会保留占位符逗号。此关键字短语对空字符串值没有影响。

描述

Json_array接受表达式或(更常见的)逗号分隔的表达式列表,并返回包含这些值的JSON数组。Json_array可以在SELECT语句中与其他类型的SELECT-Items结合使用。可以在可以使用SQL函数的其他位置指定json_array,例如在WHERE子句中。

返回的JSON数组格式如下:

[ element1 , element2 , element3 ]

Json_array以字符串(用双引号括起来)或数字形式返回每个数组元素值。数字以规范格式返回。数字字符串以文字形式返回,用双引号括起来。所有其他数据类型(例如,DATE$LIST)都作为字符串返回。

Json_array不支持将星号(*)语法作为指定表中所有字段的方式。它支持COUNT(*)聚合函数。

返回的JSON数组列被标记为表达式(默认情况下);可以为JSON_ARRAY指定列别名。

选择模式和归类

当前%SelectMode属性确定返回的JSON数组值的格式。通过更改Select Mode,所有Date%List元素都以该Select Mode格式的字符串包含在JSON数组中。

可以通过将格式转换函数(%EXTERNAL%INTERNAL%ODBCIN%ODBCOUT)应用于JSON_ARRAY内的各个字段名来覆盖当前的选择模式。将格式转换函数应用于JSON_ARRAY没有任何效果,因为JSON数组的元素是字符串。

可以将归类函数应用于JSON_ARRAY内的单个字段名或整个JSON_ARRAY

  • 应用于JSON_ARRAY的排序函数在JSON数组格式化之后应用排序规则。因此,%SQLUPPER(JSON_ARRAY(f1,f2))将所有JSON数组元素值转换为大写。%SQLUPPER(JSON_ARRAY(f1,f2))JSON数组之前插入一个空格,而不是在数组元素之前插入一个空格;因此它不会强制将数字解析为字符串。
  • 应用于JSON_ARRAY中的元素的排序规则函数将应用该排序规则。因此,JSON_ARRAY(‘abc’,%SQLUPPER(‘abc’))返回["Abc"," ABC"](注意前导空格);而JSON_ARRAY(007,%SQLSTRING(007))返回[7," 7"]。由于%SQLUPPER会在值之前插入一个空格,因此通常最好指定大小写转换函数,如LCASEUCASE。可以将排序规则应用于元素和整个数组:%SQLUPPER(JSON_ARRAY('Abc',%SQLSTRING('Abc'))) returns ["ABC"," ABC"]

ABSENT ON NULL

如果指定可选的ACESING ON NULL关键字短语,则JSON数组中不包括NULL(或NULL文字)列值。JSON数组中不包括占位符。这可能会导致JSON数组具有不同数量的元素。例如,下面的程序返回JSON数组,其中对于某些记录,第三个数组元素是Age,对于其他记录,第三个数组元素是FavoriteColors

SELECT JSON_ARRAY(%ID,Name,FavoriteColors,Age ABSENT ON NULL) FROM Sample.Person

如果未指定关键字短语,则NULL的默认值为NULL:NULL由单词NULL(未用引号分隔)表示为逗号分隔的数组元素。因此,JSON_ARRAY函数返回的所有JSON数组都将具有相同数量的数组元素。

示例

下面的示例应用JSON_ARRAY来格式化包含逗号分隔的字段值列表的JSON数组:

SELECT TOP 3 JSON_ARRAY(%ID,Name,Age,Home_State) FROM Sample.Person

image

下面的示例应用JSON_ARRAY使用包含名称字段值的单个元素格式化JSON数组:

SELECT TOP 3 JSON_ARRAY(Name) FROM Sample.Person

image

下面的示例应用JSON_ARRAY来格式化包含文字和字段值的JSON数组:

SELECT TOP 3 JSON_ARRAY('Employee from',%TABLENAME,Name,SSN) FROM Sample.Employee

下面的示例应用JSON_ARRAY来格式化包含空值和字段值的JSON数组:

SELECT JSON_ARRAY(Name,FavoriteColors) FROM Sample.Person
WHERE Name %STARTSWITH 'S'

下面的示例应用JSON_ARRAY来格式化包含联接表中的字段值的JSON数组:

SELECT TOP 3 JSON_ARRAY(E.%TABLENAME,E.Name,C.%TABLENAME,C.Name) 
FROM Sample.Employee AS E,Sample.Company AS C

下面的动态SQL示例设置ODBC %SelectMode,它确定如何表示所有字段,包括JSON数组值。该查询通过应用%EXTERNAL FORMAT-CONVERSION函数覆盖特定JSON数组元素的此选择模式:

ClassMethod JsonArray()
{
	s myquery = 3
	s myquery(1) = "SELECT TOP 8 DOB,JSON_ARRAY(Name,DOB,FavoriteColors) AS ODBCMode, "
	s myquery(2) = "JSON_ARRAY(Name,DOB,%EXTERNAL(DOB),%EXTERNAL(FavoriteColors)) AS ExternalTrans "
	s myquery(3) = "FROM Sample.Person"
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	w "SelectMode is ODBC",!
	s qStatus = tStatement.%Prepare(.myquery)

	s rset = tStatement.%Execute()
	if rset.%SQLCODE=0 { 
		w !,"Executed query",! 
	} else { 
		s badSQL=##class(%Exception.SQL).%New(,rset.%SQLCODE, , rset.%Message)
	}
	d rset.%Display()
	w !,"End of data"
}
DHC-APP> d ##class(PHA.TEST.SQLCommand).JsonArray()
SelectMode is ODBC
 
Executed query
DOB     ODBCMode        ExternalTrans
1990-04-25      ["yaoxin","1990-04-25","Red,Orange,Yellow"]     ["yaoxin","1990-04-25","04/25/1990","Red\r\nOrange\r\nYellow"]
        ["xiaoli",null,null]    ["xiaoli",null,null,null]
2014-01-02      ["姚鑫","2014-01-02",null]      ["姚鑫","2014-01-02","01/02/2014    ",null]
2014-01-02      ["姚鑫","2014-01-02",null]      ["姚鑫","2014-01-02","01/02/2014    ",null]
1978-01-28      ["姚鑫","1978-01-28",null]      ["姚鑫","1978-01-28","01/28/1978    ",null]
        ["姚鑫",null,"Red,Orange,Yellow,Green"] ["姚鑫",null,null,"Red\r\nOrange    \r\nYellow\r\nGreen"]
        ["姚鑫",null,"Red,Orange,Yellow,Green,Green"]   ["姚鑫",null,null,"Red\r    \nOrange\r\nYellow\r\nGreen\r\nGreen"]
        ["Isaacs,Roberta Z.",null,"Red,Orange,Yellow,Green,Yellow"]     ["Isaacs,Roberta Z.",null,null,"Red\r\nOrange\r\nYellow\r\nGreen\r\nYellow"]
 
8 Rows(s) Affected
End of data

下面的示例在WHERE子句中使用JSON_ARRAY在不使用OR语法的情况下对多列执行CONTAINS测试:

SELECT Name,Home_City,Home_State FROM Sample.Person
WHERE JSON_ARRAY(Name,Home_City,Home_State) [ 'X'
0
0 497
文章 姚 鑫 · 二月 27, 2022 2m read

第六十七章 SQL函数 ISNUMERIC

测试有效数字的数值函数。

大纲

ISNUMERIC(check-expression)

参数

  • check-expression - 要计算的表达式。

ISNUMERIC返回SMALLINT数据类型。

描述

ISNUMERIC计算check-expression并返回下列值之一:

  • 如果check表达式是有效数字,则返回1。有效数字可以是数字表达式,也可以是表示有效数字的字符串。
    • 数值表达式首先转换为规范形式,解析多个前导符号;因此,诸如+-+34这样的数值表达式是有效的数字。
    • 在求值之前不会转换数字字符串。数字字符串最多只能有一个前导符号才能计算为有效数字。带有尾随小数点的数字字符串的计算结果为有效数字。
  • 如果check-expression不是有效数字,则返回0。任何包含非数字字符的字符串都不是有效数字。具有多个前导符号的数字字符串(如‘+-+34’)不会被计算为有效数字。编码列表始终返回0,即使其元素是有效数字也是如此。空字符串ISNUMERIC(‘’)返回0。
  • 如果check-expressionNULL,则返回NULLISNUMERIC(NULL)返回NULL

如果科学记数法指数大于308(308-(整数数-1)),ISNUMERIC会生成SQLCODE-7,指数超出范围错误。例如,ISNUMERIC(1E309)ISNUMERIC(111E307)都会生成此错误代码。如果小于或等于“1E145”的指数数字字符串返回1,则大于“1E145”的指数数字字符串返回0。

ISNUMERIC函数与ObjectScript $ISVALIDNUM函数非常相似。但是,当输入值为NULL时,这两个函数返回不同的值。

示例

在下面的示例中,所有ISNUMERIC函数都返回1:

SELECT ISNUMERIC(99) AS MyInt,
       ISNUMERIC('-99') AS MyNegInt,
       ISNUMERIC('-0.99') AS MyNegFrac,
       ISNUMERIC('-0.00') AS MyNegZero,
       ISNUMERIC('-0.09'+7) AS MyAdd,
       ISNUMERIC('5E2') AS MyExponent
       
1	1	1	1	1	1

如果FavoriteColorsNULL,则下面的示例返回NULL;否则返回0,因为FavoriteColors不是数值字段:

SELECT Name,
ISNUMERIC(FavoriteColors) AS ColorPref
FROM Sample.Person
0
0 106
文章 姚 鑫 · 二月 26, 2022 3m read

第六十六章 SQL函数 ISNULL

测试NULL并返回相应表达式的函数。

大纲

ISNULL(check-expression,replace-expression)

参数

  • check-expression - 要计算的表达式。
  • replace-expression - Check-ExpressionNULL时返回的表达式。

ISNULL返回与Check-Expression相同的数据类型。

描述

ISNULL计算check-expression并返回以下两个值之一:

  • 如果check-expressionNULL,则返回Replace-Expression
  • 如果Check-Expression不为空,则返回Check-Expression

Replace-Expression的数据类型应该与Check-Expression的数据类型兼容。

请注意,ISNULL函数与NVL函数相同,后者是为了与Oracle兼容而提供的。

日期和时间显示转换

某些检查表达式数据类型需要从逻辑模式转换为ODBC模式或显示模式。例如日期和时间数据类型。如果替换表达式值不是相同的数据类型,则不能在ODBC模式或显示模式下转换此值,并生成SQLCODE错误:日期数据类型为-146;时间数据类型为-147。例如,ISNULL(DOB,'nodate')不能在ODBC模式或显示模式下执行;它会发出SQLCODE-146错误,并显示 %msg Error: 'nodate' is an invalid ODBC/JDBC Date value or Error: 'nodate' is an invalid DISPLAY Date value。要在ODBC模式或显示模式下执行此语句,必须将值强制转换为适当的数据类型:ISNULL(DOB,CAST('nodate' as DATE))。这将导致日期0,显示为1840-12-31

比较的NULL处理函数

下表显示了各种SQL比较函数。如果逻辑比较测试为True(A与B相同),则每个函数返回一个值;如果逻辑比较测试为False(A与B不同),则每个函数返回另一个值。这些函数允许您执行空逻辑比较。不能在实际相等(或不相等)条件比较中指定NULL

SQL FunctionComparisonTest Return Value
IFNULL(ex1,ex2) [two-argument form]ex1 = NULLTrue returns ex2 False returns NULL
IFNULL(ex1,ex2,ex3) [three-argument form]ex1 = NULLTrue returns ex2 False returns ex3
{fn IFNULL(ex1,ex2)}ex1 = NULLTrue returns ex2 False returns ex1
ISNULL(ex1,ex2)ex1 = NULLTrue returns ex2 False returns ex1
NVL(ex1,ex2)ex1 = NULLTrue returns ex2 False returns ex1
NULLIF(ex1,ex2)ex1 = ex2True returns NULL False returns ex1
COALESCE(ex1,ex2,...)ex = NULL for each argumentTrue tests next ex argument. If all ex arguments are True (NULL), returns NULL. False returns ex

示例

在下面的示例中,第一个ISNULL返回第二个表达式(99),因为第一个表达式为空。第二个ISNULL返回第一个表达式(33),因为第一个表达式不为空:

SELECT ISNULL(NULL,99) AS IsNullT,ISNULL(33,99) AS IsNullF

99	33

如果FavoriteColorsNULL,下面的动态SQL示例将返回字符串‘No Preference’;否则,它将返回FavoriteColors的值:

ClassMethod IsNull()
{
	s myquery=3
	s myquery(1)="SELECT Name,"
	s myquery(2)="ISNULL(FavoriteColors,'No Preference') AS ColorChoice "
	s myquery(3)="FROM Sample.Person"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(.myquery)
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}

DHC-APP> d ##class(PHA.TEST.SQLCommand).IsNull()
Name    ColorChoice
yaoxin  $lb("Red","Orange","Yellow")
xiaoli  No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫    $lb("Red","Orange","Yellow","Green")
姚鑫    $lb("Red","Orange","Yellow","Green","Green")

ISNULL的行为与IFNULL进行比较:

ClassMethod IsNull1()
{
	s myquery=3
	s myquery(1)="SELECT Name,"
	s myquery(2)="IFNULL(FavoriteColors,'No Preference') AS ColorChoice "
	s myquery(3)="FROM Sample.Person"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(.myquery)
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).IsNull1()
Name    ColorChoice
yaoxin
xiaoli  No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫
姚鑫
0
0 78
文章 姚 鑫 · 二月 25, 2022 3m read

第六十五章 SQL函数 %INTERNAL

返回逻辑格式表达式的格式转换函数。

大纲

%INTERNAL(expression)

%INTERNAL expression

参数

  • expression - 要转换的表达式。 字段名、包含字段名的表达式,或返回可转换数据类型(如DATE%List)中的值的函数。

描述

%INTERNAL将表达式转换为逻辑格式,与当前选择模式(显示模式)无关。逻辑格式是数据的内存格式(对其执行操作的格式)。%INTERNAL通常用于选择列表SELECT-ITEM

可以在WHERE子句中使用%INTERNAL,但强烈建议不要使用%INTERNAL,因为使用%INTERNAL会阻止在指定字段上使用索引,并且%INTERNAL会强制所有比较区分大小写,即使该字段有默认排序规则也是如此。

应用%INTERNAL会将列标题名称更改为诸如“Expression_1”之类的值;因此,通常需要指定列名别名,如下面的示例所示。

%INTERNAL将数据类型%DATE的值转换为整数数据类型值。%INTERNAL将数据类型%TIME的值转换为数字(15,9)数据类型值。之所以提供此转换,是因为ODBC或JDBC客户端不识别逻辑%DATE%TIME值。

%INTERNAL是否转换日期取决于日期字段或函数返回的数据类型。%INTERNAL转换CURDATECURRENT_DATECURTIMECURRENT_TIME值。它不转换CURRENT_TIMESTAMPGETDATEGETUTCDATENOW$HOROLOG值。

不能将流字段指定为ObjectScript一元函数(包括所有格式转换函数,%Internal除外)的参数。%INTERNAL函数允许将流字段作为表达式值,但不对该流字段执行任何操作。

%INTERNAL是InterSystems SQL扩展。

要将表达式转换为显示格式,而不考虑当前的选择模式,请使用%EXTERNAL函数。要将表达式转换为ODBC格式,而不考虑当前的SELECT模式,请使用%ODBCOUT函数。

示例

下面的动态SQL示例以当前选择模式格式返回出生日期(道布)数据值,并使用%INTERNAL函数返回相同的数据。出于演示目的,在此程序中,为每次调用随机确定%SelectMode值:

ClassMethod Internal()
{
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=$RANDOM(3)
	if tStatement.%SelectMode=0 {WRITE "Select mode LOGICAL",! }
	elseif tStatement.%SelectMode=1 {WRITE "Select mode ODBC",! }
	elseif tStatement.%SelectMode=2 {WRITE "Select mode DISPLAY",! }
	s myquery = 2
	s myquery(1) = "SELECT TOP 5 DOB,%INTERNAL(DOB) AS IntDOB "
	s myquery(2) = "FROM Sample.Person"
	s qStatus = tStatement.%Prepare(.myquery)
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).Internal()
Select mode DISPLAY
DOB     IntDOB
04/25/1990      54536
 
01/02/2014      63189
01/02/2014      63189
01/28/1978      50066
 
5 Rows(s) Affected
End of data

下面的示例显示了此函数的两种语法形式;在其他方面它们是相同的。它们指定%LIST字段的%EXTERNAL(显示格式)、%INTERNAL(逻辑格式)和%ODBCOUT(ODBC格式):

SELECT TOP 10 %EXTERNAL(FavoriteColors) AS ExtColors,
              %INTERNAL(FavoriteColors) AS IntColors,
              %ODBCOUT(FavoriteColors) AS ODBCColors
FROM Sample.Person
SELECT TOP 10 %EXTERNAL FavoriteColors AS ExtColors,
              %INTERNAL FavoriteColors AS IntColors,
              %ODBCOUT FavoriteColors AS ODBCColors
FROM Sample.Person
0
0 87
文章 姚 鑫 · 二月 24, 2022 3m read

第六十四章 SQL函数 INSTR

返回子字符串在字符串中的位置的字符串函数,具有可选的搜索起始点和出现次数。

大纲

INSTR(string,substring[,start[,occurrence]])

参数

  • string - 要在其中搜索子字符串的字符串表达式。 它可以是列的名称、字符串字面值或另一个标量函数的结果,其中基础数据类型可以表示为任何字符类型(如CHARVARCHAR2)。
  • substring - 一个子字符串,被认为出现在字符串中。
  • start - 可选-子字符串搜索的起始点,指定为正整数。 从字符串开始的字符计数,从1开始计数。 若要从字符串的开头开始搜索,请忽略此参数或指定从1开始。 起始值为0、空字符串、NULL或非数字值会导致INSTR返回0。 指定start为负数会导致INSTR返回<null>
  • occurrence - 可选-一个非零整数,指定从起始位置搜索时返回哪个子字符串。 默认情况是返回第一个出现的位置。

INSTR返回INTEGER数据类型。

描述

INSTR在字符串中查找子字符串,并返回子字符串的第一个字符的位置。 位置以整数形式返回,从字符串的开头开始计算。 如果substring没有找到,则返回0(0)。 如果传递给任何一个参数一个NULL值,INSTR将返回NULL

INSTR支持指定start作为子字符串搜索的起始点。 INSTR还支持从起始点指定子字符串出现。

INSTR是区分大小写的。 使用其中一个大小写转换函数来定位字母或字符串的大写和小写实例。

这个函数也可以通过调用INSTR()方法从ObjectScript调用:

DHC-APP> w $SYSTEM.SQL.INSTR("The broken brown briefcase","br",6,2)        18

INSTR, CHARINDEX, POSITION和$FIND

INSTR, CHARINDEX, POSITION$FIND都搜索一个字符串中指定的子字符串,并返回一个整数位置对应于第一个匹配。 CHARINDEXPOSITIONINSTR返回匹配子字符串的第一个字符的整数位置。 $FIND返回匹配子字符串结束后第一个字符的整数位置。 CHARINDEX$FINDINSTR支持指定子字符串搜索的起始点。 INSTR还支持从起始点指定子字符串出现。

下面的示例演示了这四个函数,指定了所有可选参数。 注意,在这些函数中,stringsubstring的位置不同:

SELECT POSITION('br' IN 'The broken brown briefcase') AS Position,
       CHARINDEX('br','The broken brown briefcase',6) AS Charindex,
       $FIND('The broken brown briefcase','br',6) AS Find,
       INSTR('The broken brown briefcase','br',6,2) AS Inst
       
5	12	14	18

示例

下面的例子返回11,因为“b”是字符串中的第11个字符:

SELECT INSTR('The quick brown fox','b',1) AS PosInt

11

下面的示例返回示例中每个名字的姓氏长度。 人表。 它定位用于将姓氏与name字段的其余部分分隔开的逗号,然后从该位置减去1:

SELECT Name,
INSTR(Name,',',1)-1 AS LNameLen
FROM Sample.Person

下面的示例返回样本中每个名称中字母“B”的第一个实例的位置。 人表。 因为INSTR是区分大小写的,所以在执行搜索之前使用%SQLUPPER函数将所有的名称值转换为大写。 因为%SQLUPPER在字符串的开头添加了一个空格,所以这个示例减去1以获得实际的字母位置。 没有找到指定字符串的搜索将返回0 (0); 在本例中,由于减法为1,这些搜索显示的值为-1:

SELECT Name,
INSTR(%SQLUPPER(Name),'B',1)-1 AS BPos
FROM Sample.Person
0
0 170
文章 姚 鑫 · 二月 23, 2022 8m read

第六十三章 SQL函数 IFNULL

测试NULL并返回适当表达式的函数。

大纲

IFNULL(expression-1,expression-2 [,expression-3])

{fn IFNULL(expression-1,expression-2)}

参数

  • expression-1 - 要计算以确定是否为NULL的表达式。
  • expression-2 - 如果expression-1NULL,则返回的表达式。
  • expression-3 - 可选-如果expression-1不是NULL返回的表达式。 如果没有指定expression-3,则当expression-1不是NULL时返回NULL值。

返回的数据类型描述如下。

描述

支持IFNULL作为SQL通用函数和ODBC标量函数。 请注意,虽然这两个执行非常相似的操作,但它们在功能上是不同的。 SQL通用函数支持三个参数。 ODBC标量函数支持两个参数。 SQL通用函数和ODBC标量函数的双参数形式是不一样的; 当expression-1不为空时,它们返回不同的值。

SQL通用函数计算表达式1是否为NULL。 它永远不会返回expression-1:

  • 如果expression-1NULL,则返回expression-2
  • 如果expression-1不为NULL,则返回expression-3
  • 如果expression-1不为NULL,并且没有expression-3,则返回NULL

ODBC标量函数计算expression-1是否为NULL。 它要么返回expression-1,要么返回expression-2:

  • 如果expression-1为NULL,则返回expression-2
  • 如果expression-1不为NULL,则返回expression-1

返回值数据类型

  • IFNULL(expression-1,expression-2):返回expression-2的数据类型。 如果expression-2是数值字面值,则字符串字面值或NULL返回数据类型VARCHAR
  • IFNULL(expression-1,expression-2,expression-3):如果expression-2expression-3具有不同的数据类型,则返回数据类型优先级更高(包容性更强)的数据类型。 如果expression-2expression-3是数值字面值或字符串字面值,则返回数据类型VARCHAR。 如果expression-2expression-3NULL,则返回非NULL参数的数据类型。

如果expression-2expression-3的长度、精度或比例不同,则IFNULL返回两个表达式的更大长度、精度或比例。

  • {fn IFNULL(expression-1,expression-2)}:返回expression-1的数据类型。 如果expression-1是数字字面值、字符串字面值或NULL,则返回数据类型VARCHAR

日期和时间显示转换

一些expression-1数据类型需要从逻辑模式(模式0)转换为ODBC模式(模式1)或显示模式(模式2)。例如DATE和TIME数据类型。 如果expression-2expression-3的值不是相同的数据类型,则不能在ODBC模式或Display模式下转换该值,并产生一个SQLCODE错误:DATE数据类型为-146; -147TIME数据类型。 例如,IFNULL(DOB,'nodate',DOB)不能在ODBC模式或显示模式中执行; 它会发出一个SQLCODE -146错误,其中有%msg Error: 'nodate' is an invalid ODBC/JDBC Date value or Error: 'nodate' is an invalid DISPLAY Date value. 要在ODBC模式或Display模式下执行此语句,必须将该值转换为适当的数据类型:IFNULL(DOB,CAST('nodate' as DATE),DOB)。 这将产生日期0,显示为1840-12-31

%List显示转换

%LIST字段是带编码的字符串数据类型字段。如果Expression-1%List字段,则相应的Expression-2Expression-3值取决于选择模式:

  • 在逻辑模式(模式0)或显示模式(模式2)中,%List值作为字符串数据类型返回,格式为$lb("element1","element2",…)。 因此,expression-2expression-3的值必须指定为%List,示例如下:
/// d ##class(PHA.TEST.SQLCommand).IfNull()
ClassMethod IfNull()
{
	s myquery=3
	s myquery(1)="SELECT TOP 20 Name,"
	s myquery(2)="IFNULL(FavoriteColors,$LISTBUILD('No Preference'),FavoriteColors) AS ColorChoice "
	s myquery(3)="FROM Sample.Person"
	s tStatement = ##class(%SQL.Statement).%New(2)  // 2=Display mode
	s qStatus = tStatement.%Prepare(.myquery)
	s rset = tStatement.%Execute()
	d rset.%Display()
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).IfNull()
Name    ColorChoice
yaoxin  $lb("Red","Orange","Yellow")
xiaoli  $lb("No Preference")
姚鑫    $lb("No Preference")
姚鑫    $lb("No Preference")
姚鑫    $lb("No Preference")
姚鑫    $lb("Red","Orange","Yellow","Green")
姚鑫    $lb("Red","Orange","Yellow","Green","Green")
Isaacs,Roberta Z.       $lb("Red","Orange","Yellow","Green","Yellow")
Chadwick,Zelda S.Chadwick,Zelda S.Chadwick,Zelda S.Chadwick,Zelda S.Chadwick,Zelda S.   $lb("White")
Fives,James D.  $lb("Black")
Vonnegut,Jose P.        $lb("Green","White")
Chadbourne,Barb B.      $lb("Purple")
Quigley,Barb A. $lb("Yellow")
O'Rielly,Chris H.       $lb("Red","Red")
Willeke,Alvin L.        $lb("Black","Black")
Orwell,John V.  $lb("No Preference")
Umansky,Susan C.        $lb("Blue")
Kratzmann,Kirsten C.    $lb("No Preference")
Ng,Josephine Z. $lb("White")
Zevon,Heloisa O.        $lb("Orange")
 
20 Rows(s) Affected
  • 在ODBC模式(模式1)中,%List值作为逗号分隔的元素字符串返回:element1element2、.... 因此,expression-2expression-3的值可以指定为字符串,示例如下:
/// d ##class(PHA.TEST.SQLCommand).IfNull1()
ClassMethod IfNull1()
{
	s myquery=3
	s myquery(1)="SELECT TOP 20 Name,"
	s myquery(2)="IFNULL(FavoriteColors,'No Preference',FavoriteColors) AS ColorChoice "
	s myquery(3)="FROM Sample.Person"
	s tStatement = ##class(%SQL.Statement).%New(1)  // 1=ODBC mode
	s qStatus = tStatement.%Prepare(.myquery)
	s rset = tStatement.%Execute()
	d rset.%Display()
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).IfNull1()
Name    ColorChoice
yaoxin  $lb("Red","Orange","Yellow")
xiaoli  No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫    $lb("Red","Orange","Yellow","Green")
姚鑫    $lb("Red","Orange","Yellow","Green","Green")
Isaacs,Roberta Z.       $lb("Red","Orange","Yellow","Green","Yellow")
Chadwick,Zelda S.Chadwick,Zelda S.Chadwick,Zelda S.Chadwick,Zelda S.Chadwick,Zelda S.   $lb("White")
Fives,James D.  $lb("Black")
Vonnegut,Jose P.        $lb("Green","White")
Chadbourne,Barb B.      $lb("Purple")
Quigley,Barb A. $lb("Yellow")

NULL处理函数比较

下表显示了各种SQL比较函数。 如果逻辑比较测试为True (A与B相同),则每个函数返回一个值;如果逻辑比较测试为False (A与B不同),则返回另一个值。这些函数允许执行NULL逻辑比较。 不能在实际相等(或不相等)条件比较中指定NULL

SQL FunctionComparisonTest Return Value
IFNULL(ex1,ex2) [two-argument form]ex1 = NULLTrue returns ex2 False returns NULL
IFNULL(ex1,ex2,ex3) [three-argument form]ex1 = NULLTrue returns ex2 False returns ex3
{fn IFNULL(ex1,ex2)}ex1 = NULLTrue returns ex2 False returns ex1
ISNULL(ex1,ex2)ex1 = NULLTrue returns ex2 False returns ex1
NVL(ex1,ex2)ex1 = NULLTrue returns ex2 False returns ex1
NULLIF(ex1,ex2)ex1 = ex2True returns NULL False returns ex1
COALESCE(ex1,ex2,...)ex = NULL for each argumentTrue tests next ex argument. If all ex arguments are True (NULL), returns NULL. False returns ex

示例

在下面的例子中,通用函数和ODBC标量函数都返回第二个表达式(99),因为第一个表达式是NULL:

SELECT IFNULL(NULL,99) AS NullGen,{fn IFNULL(NULL,99)} AS NullODBC

99	99

在下面的示例中,通用函数和ODBC标量函数示例返回不同的值。 通用函数返回<null>,因为第一个表达式不是nullODBC示例返回第一个表达式(33),因为第一个表达式不是NULL:

SELECT IFNULL(33,99) AS NullGen,{fn IFNULL(33,99)} AS NullODBC

NUll	33

下面的动态SQL示例返回字符串'No Preference',如果FavoriteColorsNULL; 否则,返回NULL:

/// d ##class(PHA.TEST.SQLCommand).IfNull2()
ClassMethod IfNull2()
{
	s myquery=3
	s myquery(1)="SELECT Name,"
	s myquery(2)="IFNULL(FavoriteColors,'No Preference') AS ColorChoice "
	s myquery(3)="FROM Sample.Person"
	s tStatement = ##class(%SQL.Statement).%New()
	s qStatus = tStatement.%Prepare(.myquery)
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).IfNull2()
Name    ColorChoice
yaoxin
xiaoli  No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫
姚鑫
Isaacs,Roberta Z.

下面的动态SQL示例返回字符串'No Preference',如果FavoriteColorsNULL; 否则,它返回FavoriteColors的值:

ClassMethod IfNull3()
{
	s myquery=3
	s myquery(1)="SELECT Name,"
	s myquery(2)="IFNULL(FavoriteColors,'No Preference',FavoriteColors) AS ColorChoice "
	s myquery(3)="FROM Sample.Person"
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=2
	s qStatus = tStatement.%Prepare(.myquery)
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).IfNull3()
Name    ColorChoice
yaoxin  $lb("Red","Orange","Yellow")
xiaoli  No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫    $lb("Red","Orange","Yellow","Green")
姚鑫    $lb("Red","Orange","Yellow","Green","Green")

下面的例子返回字符串'No Preference'如果FavoriteColorsNULL; 否则,返回字符串'Preference':

SELECT sqlName,
IFNULL(FavoriteColors,'No Preference','Preference') AS ColorPref
FROM Sample.Person

下面的ODBC语法示例如果FavoriteColors为NULL,则返回字符串'No Preference',否则返回FavoriteColors数据值:

SELECT Name,
       {fn IFNULL(FavoriteColors,$LISTBUILD('No Preference'))} AS ColorPref
FROM Sample.Person
/// d ##class(PHA.TEST.SQLCommand).IfNull4()
ClassMethod IfNull4()
{
	s myquery=3
	s myquery(1)="SELECT Name,"
	s myquery(2)="{fn IFNULL(FavoriteColors,'No Preference')} AS ColorChoice "
	s myquery(3)="FROM Sample.Person"
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode=1
	s qStatus = tStatement.%Prepare(.myquery)
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).IfNull4()
Name    ColorChoice
yaoxin  Red,Orange,Yellow
xiaoli  No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫    No Preference
姚鑫    Red,Orange,Yellow,Green
姚鑫    Red,Orange,Yellow,Green,Green
Isaacs,Roberta Z.       Red,Orange,Yellow,Green,Yellow

下面的例子在WHERE子句中使用了IFNULL。 它挑选了21岁以下没有最喜欢的颜色偏好的人。 如果FavoriteColorsNULL, IFNULL返回Age字段值,用于条件测试:

SELECT Name,FavoriteColors,Age
FROM Sample.Person
WHERE 21 > IFNULL(FavoriteColors,Age)
ORDER BY Age

类似的功能可以参考NULL谓词(IS NULL, IS NOT NULL)。

0
0 133
文章 Michael Lei · 二月 23, 2022 2m read

开发者们大家好!

你可能已经注意到了在IRIS 2021 Global的名字是随机的。

如果你用DDL来创建类而且想给Global一个确定的名字,实际上是可以做的。

在CREATE Table  里使用 WITH %CLASSPARAMETER DEFAULTGLOBAL='^GLobalName' ,如文档。参考以下例子:

0
0 162
文章 姚 鑫 · 二月 22, 2022 3m read

第六十二章 SQL函数 HOUR

Time函数,它返回DateTime表达式的小时数。

大纲

{fn HOUR(time-expression)}
  • time-expression - 作为列名、另一个标量函数的结果或字符串或数字文字的表达式。它必须解析为日期时间字符串或时间整数,其中基础数据类型可以表示为%Time%Timestamp%PosiTime

描述

Hour返回一个整数,指定给定时间或日期时间值的小时。小时是根据$HOROLOG$ZTIMESTAMP值、ODBC格式的日期字符串或时间戳计算的。

时间表达式时间戳可以是数据类型%Library.PosiTime(编码的64位有符号整数),也可以是数据类型%Library.TimeStamp(yyyy-mm-dd hh:mm:ss.fff)

要更改此默认时间格式,请使用SET OPTION命令。

请注意,可以提供时间整数(已用秒数),但不能提供时间字符串(hh:mm:ss)。必须提供日期时间字符串(yyyy-mm-dd hh:mm:ss)。可以省略日期时间字符串的秒(:ss)或分钟和秒(mm:ss)部分,但仍返回小时部分。日期时间字符串的时间部分必须是有效的时间值。未验证日期时间字符串的日期部分。

小时以24小时表示。小时数(HH)部分应该是介于0到23之间的整数。输入上的前导零是可选的;输出上不显示前导零。

当小时部分为“0”“00”时,小时返回0小时的值。如果没有提供时间表达式,或者如果省略了时间表达式的小时部分(':mm:ss''::ss'),也会返回零小时。

同时可以使用DATEPARTDATENAME返回信息。

也可以使用 HOUR()方法调用从ObjectScript调用此函数:

$SYSTEM.SQL.Functions.HOUR(time-expression)

示例

以下示例均返回数字18,因为时间表达式值为18:45:38

SELECT {fn HOUR('2017-02-16 18:45:38')} AS ODBCHour

18
SELECT {fn HOUR(67538)} AS HorologHour

18

下面的示例也返回18。时间值的秒(或分和秒)部分可以省略。

SELECT {fn HOUR('2017-02-16 18:45')} AS Hour_Given

18

下面的示例返回0小时,因为日期时间字符串的时间部分已被省略:

SELECT {fn HOUR('2017-02-16')} AS Hour_Given

0

以下示例均返回当前时间的小时部分:

SELECT {fn HOUR(CURRENT_TIME)} AS H_CurrentT,
       {fn HOUR({fn CURTIME()})} AS H_CurT,
       {fn HOUR({fn NOW()})} AS H_Now,
       {fn HOUR($HOROLOG)} AS H_Horolog,
       {fn HOUR($ZTIMESTAMP)} AS H_ZTS


16	16	16	16	8

请注意,$ZTIMESTAMP返回协调世界时(UTC)。其他时间表达式值返回本地时间。

下面的示例显示前导零被抑制。 第一个HOUR函数返回长度为2,其他函数返回长度为1。 忽略的时间设为0小时,其长度为1:

SELECT LENGTH({fn HOUR('2018-02-15 11:45')}),
       LENGTH({fn HOUR('2018-02-15 03:45')}),
       LENGTH({fn HOUR('2018-02-15 3:45')}),
       LENGTH({fn HOUR('2018-02-15')})
       
2	1	1	1

下面的嵌入式SQL示例显示了HOUR函数识别为区域设置指定的timeseseparator字符:

ClassMethod Hour()
{
  d ##class(%SYS.NLS.Format).SetFormatItem("TimeSeparator",".")
  &sql(SELECT {fn HOUR('2018-02-16 18.45.38')} INTO :a)
  w "hour=",a
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Hour()
hour=18
0
0 146
文章 姚 鑫 · 二月 21, 2022 3m read

第六十一章 SQL函数 GREATEST

从一系列表达式中返回最大值的函数。

大纲

GREATEST(expression,expression[,...])

参数

  • expression - 解析为数字或字符串的表达式。 对这些表达式的值进行比较。 表达式可以是字段名、文字、算术表达式、主机变量或对象引用。 最多可以列出140个逗号分隔的表达式。

描述

GREATEST返回逗号分隔的一系列表达式中的最大值。 表达式按从左到右的顺序求值。 如果只提供一个表达式,则GREATEST返回该值。 如果任何表达式为NULL,则GREATEST返回NULL

如果所有表达式值都解析为规范数,则按数值顺序对它们进行比较。 如果引用的字符串包含规范格式的数字,则按数字顺序对其进行比较。 但是,如果引用的字符串包含非规范格式的数字(例如,'00''0.4''+4'),则将其作为字符串进行比较。 字符串比较按排序顺序逐字符执行。 任何字符串值都大于任何数字值。

空字符串大于任何数字值,但小于任何其他字符串值。

如果返回值是一个数字,则GREATEST将以规范格式返回它(删除前导和末尾的零,等等)。 如果返回值是一个字符串,则GREATEST将不改变返回值,包括任何前导或末尾空格。

GREATEST返回逗号分隔的一系列表达式中的最大值。 LEAST返回逗号分隔的一系列表达式中的最小值。 COALESCE返回逗号分隔的一系列表达式中的第一个非null值。

返回值数据类型

如果表达式值的数据类型不同,则返回的数据类型是与所有可能的返回值最兼容的类型,具有最高数据类型优先级的数据类型。 例如,如果一个表达式是整数,而另一个表达式是小数,则GREATEST返回数据类型NUMERIC的值。 这是因为NUMERIC是具有最高优先级的数据类型,并且与两者兼容。 但是,如果表达式是文字数字或字符串,则GREATEST将返回数据类型VARCHAR

示例

在下面的例子中,每个GREATEST比较了三个正则数:

SELECT GREATEST(22,2.2,-21) AS HighNum,
       GREATEST('2.2','22','-21') AS HighNumStr
       
22	22

在下面的例子中,每个GREATEST比较三个数字字符串。 但是,每个GREATEST包含一个非规范字符串; 这些非规范值将作为字符串进行比较。 字符串总是大于数字:

SELECT GREATEST('22','+2.2','-21'),
       GREATEST('0.2','22','-21')
       
+2.2	0.2

在下面的例子中,每个GREATEST都会比较三个字符串,并返回排序序列最高的值:

SELECT GREATEST('A','a',''),
       GREATEST('a','ab','abc'),
       GREATEST('#','0','7'),
       GREATEST('##','00','77')
       
       
a	abc	#	00

下面的示例将两个日期作为规范数字进行比较:出生日期作为$HOROLOG整数,整数58073转换为日期。它返回21世纪出生的每个人的出生日期。任何在2000年1月1日之前出生的人都会显示默认的出生日期1999年12月31日

SELECT Name,GREATEST(DOB,TO_DATE(58073)) AS NewMillenium
FROM Sample.Person
0
0 108
文章 姚 鑫 · 二月 20, 2022 4m read

第六十章 SQL函数 GETUTCDATE

日期/时间函数,返回当前UTC日期和时间。

大纲

GETUTCDATE([precision])

参数

  • precision - 可选-一个正整数,指定时间精度为小数秒的位数。 默认值是0(没有小数秒); 这个默认值是可配置的。

描述

GETUTCDATE返回通用时间常数(UTC)日期和时间作为时间戳。由于UTC时间在地球上的任何地方都是相同的,不依赖于当地时区,也不受当地时差(如夏令时)的影响,因此当不同时区的用户访问同一数据库时,此函数对于应用一致的时间戳非常有用。

GETUTCDATE可以返回%TIMESTAMP数据类型格式(yyyy-mm-dd hh:mm:ss.ffff)或%PosiTime数据类型格式(编码的64位有符号整数)的时间戳。以下规则确定返回哪种时间戳格式:

  1. 如果当前UTC时间戳被提供给数据类型为%PosiTime的字段,则此时间戳值将以POSIXTIME数据类型格式返回。例如,WHERE PosixField=GETUTCDATE() or INSERT INTO MyTable (PosixField) VALUES (GETUTCDATE())
  2. 如果当前UTC时间戳被提供给数据类型为%TIMESTAMP的字段,则此时间戳值以TIMESTAMP数据类型格式返回。其ODBC类型为TIMESTAMP,长度为16,精度为19。例如, WHERE TSField=GETUTCDATE() or INSERT INTO MyTable (TSField) VALUES (GETUTCDATE())
  3. 如果当前UTC时间戳是在没有上下文的情况下提供的,则此时间戳值以TIMESTAMP数据类型格式返回。例如,SELECT GETUTCDATE()

要更改默认日期时间字符串格式,请使用带有各种日期和时间选项的set option命令。

GETUTCDATE的典型用法是在SELECT语句SELECT列表或查询的WHERE子句中。在设计报表时,可以使用GETUTCDATE在每次生成报表时打印当前日期和时间。GETUTCDATE对于跟踪活动也很有用,比如记录事务发生的时间。

GETUTCDATE可用于创建表中以指定字段的默认值。

Other SQL Functions

GETUTCDATE以时间戳或POSIXTIME格式将当前UTC日期和时间作为时间戳返回。

所有其他TIMESTAMP函数都返回本地日期和时间:GETDATECURRENT_TIMESTAMPNOWSYSDATETIMESTAMPPOSIXTIME格式将当前本地日期和时间作为时间戳返回。

GETDATECURRENT_TIMESTAMP提供精度参数。

NOW,无参数CURRENT_TIMESTAMPSYSDATE不提供精度参数;它们采用系统范围的默认时间精度。

CURDATECURRENT_DATE返回当前本地日期。CURTIMECURRENT_TIME返回当前本地时间。这些函数使用日期或时间数据类型。这些函数都不支持精度。

TIMESTAMP数据类型以相同的格式存储和显示其值。POSIXTIME数据类型将其值存储为编码的64位有符号整数。时间和日期数据类型将它们的值存储为$HOROLOG格式的整数,并可以多种格式显示。

请注意,除GETUTCDATE外,所有 SQL时间戳函数都特定于本地时区设置。要获得通用的当前时间戳(独立于时区),还可以使用ObjectScript $ZTIMESTAMP特殊变量。请注意,可以设置GETUTCDATE的精度;$ZTIMESTAMP始终返回精度3。

小数秒精度

GETUTCDATE最多可以返回9位精度。返回的精度位数是使用Precision参数设置的。可以使用以下内容配置精度参数的默认值:

  • 使用TIME_PRECISION选项设置选项。
  • 系统范围的$SYSTEM.SQL.Util.SetOption()方法配置选项DefaultTimePrecision。要确定当前设置,请调用$SYSTEM.SQL.CurrentSettings(),它显示默认的时间精度;默认值为0。
  • 转到管理门户,依次选择系统管理、配置、SQL和对象设置、SQL。查看和编辑GETDATE()CURRENT_TIMECURRENT_TIMESTAMP的默认时间精度的当前设置。

为要返回的默认精度小数位数指定一个从09(包括09)的整数。默认值为0。返回的实际精度取决于平台;超出系统可用精度的精度位数将作为零返回。

小数秒始终被截断,而不是舍入到指定的精度。

示例

以下示例将当前日期和时间作为UTC时间戳和本地时间戳返回,两者均采用时间戳格式:

SELECT GETUTCDATE() AS UTCDateTime,
       GETDATE() AS LocalDateTime
       
       
2022/2/12 7:49:53	2022/2/12 15:49:53

下面的示例返回当前的UTC日期和时间,其中小数秒具有两位精度:

SELECT GETUTCDATE(2) AS DateTime

2022/2/12 7:50:19

下面的嵌入式SQL示例比较本地(特定于时区)和通用(独立于时区)时间戳:

ClassMethod GetDate()
{
	&sql(SELECT GETDATE(),GETUTCDATE() INTO :a,:b)
	if SQLCODE'=0 {
		w !,"Error code ",SQLCODE }
	else {
		w !,"Local timestamp is:  ",a
		w !,"UTC timestamp is:    ",b
		w !,"$ZTIMESTAMP is:      ",$ZDATETIME($ZTIMESTAMP,3,,3)
	}
}
DHC-APP> d ##class(PHA.TEST.SQLCommand).GetDate()
 
Local timestamp is:  2022-02-12 15:40:34
UTC timestamp is:    2022-02-12 07:40:34
$ZTIMESTAMP is:      2022-02-12 07:40:34.978

下面的示例将Orders表的选定行中的LastUpdate字段设置为当前UTC日期和时间。如果LastUpdate是数据类型%TIMESTAMP,则GETUTCDATE将当前UTC日期和时间作为ODBC时间戳返回;如果LastUpdate是数据类型%PosiTime,则GETUTCDATE将当前UTC日期和时间作为编码的64位有符号整数返回:

UPDATE Orders SET LastUpdate = GETUTCDATE()
  WHERE Orders.OrderNumber=:ord

在以下示例中,CREATE TABLE语句使用GETUTCDATEOrderRcvd字段设置默认值:

CREATE TABLE Orders(
     OrderId     INT NOT NULL,
     ItemName    CHAR(40) NOT NULL,
     Quantity    INT NOT NULL,
     OrderRcvd   TIMESTAMP DEFAULT GETUTCDATE())
0
0 124
文章 姚 鑫 · 二月 19, 2022 4m read

第五十九章 SQL函数 GETDATE

日期/时间函数,返回当前本地日期和时间。

大纲

GETDATE([precision])

参数

  • precision - 可选-一个正整数,指定时间精度为小数秒的位数。 默认值是0(没有小数秒); 这个默认值是可配置的。 精度值是可选的,括号是必选的。

描述

GETDATE将此时区的当前本地日期和时间作为时间戳返回;它根据本地时间变量(如夏令时)进行调整。

GETDATE可以返回%TIMESTAMP数据类型格式(yyyy-mm-dd hh:mm:ss.ffff)或%PosiTime数据类型格式(编码的64位有符号整数)的时间戳。以下规则确定返回哪种时间戳格式:

  1. 如果当前时间戳被提供给数据类型为%PosiTime的字段,则当前时间戳值将以POSIXTIME数据类型格式返回。例如, WHERE PosixField=GETDATE() or INSERT INTO MyTable (PosixField) VALUES (GETDATE())

  2. 如果当前时间戳被提供给数据类型为%TIMESTAMP的字段,则当前时间戳值将以TIMESTAMP数据类型格式返回。其ODBC类型为TIMESTAMP,长度为16,精度为19,例如 WHERE TSField=GETDATE() or INSERT INTO MyTable (TSField) VALUES (GETDATE())

  3. 如果当前时间戳是在没有上下文的情况下提供的,则当前时间戳值以TIMESTAMP数据类型格式返回。例如,选择GETDATE()

要更改默认日期时间字符串格式,请使用带有各种日期和时间选项的set option命令。

GETDATE可以在SELECT语句SELECT LIST或查询的WHERE子句中使用。在设计报表时,可以使用GETDATE在每次生成报表时打印当前日期和时间。GETDATE对于跟踪活动也很有用,比如记录事务发生的时间。

可以在CREATE TABLE中使用GETDATE指定字段的默认值。GETDATECURRENT_TIMESTAMP的同义词,提供GETDATE是为了与Sybase和Microsoft SQL Server兼容。

CURRENT_TIMESTAMPNOW函数还可以用于以时间戳或POSIXTIME格式将当前本地日期和时间作为时间戳返回。CURRENT_TIMESTAMP支持精度,现在不支持精度。

要仅返回当前日期,请使用CURDATECURRENT_DATE。要仅返回当前时间,请使用CURRENT_TIMECURTIME。这些函数使用日期或时间数据类型。这些函数都不支持精度。

TIMESTAMP数据类型以相同的格式存储和显示其值。POSIXTIME数据类型将其值存储为编码的64位有符号整数。时间和日期数据类型将它们的值存储为$HOROLOG格式的整数。它们可以以显示格式或逻辑(存储)格式显示。可以使用CASTCONVERT函数更改日期和时间的数据类型。

世界时(UTC)

GETDATE返回当前本地日期和时间。除GETUTCDATE之外,所有SQL时间戳、日期和时间函数都特定于本地时区设置。GETUTCDATE将当前UTC(通用)日期和时间作为时间戳值或POSIXTIME值返回。还可以使用ObjectScript $ZTIMESTAMP特殊变量来获取通用的当前时间戳(独立于时区)。

精确到小数部分的秒

GETDATE可以返回多达9位的精度。 使用precision参数设置返回的精度的位数。 precision参数的默认值可以通过以下方式配置:

  • 使用TIME_PRECISION选项设置OPTION
  • 系统范围的$SYSTEM.SQL.Util.SetOption()方法配置选项DefaultTimePrecision。 要确定当前设置,调用$SYSTEM.SQL.CurrentSettings(),它显示默认的时间精度; 默认值为0。
  • 进入管理门户,选择“系统管理”、“配置”、“SQL和对象设置”、“SQL”。 查看和编辑GETDATE()CURRENT_TIMECURRENT_TIMESTAMP的默认时间精度的当前设置。

指定从0到9(包括9)的整数,作为返回的十进制精度的默认位数。 默认值为0。 实际返回的精度取决于平台; 超过系统中可用精度的精度数字将作为零返回。

分数秒总是被截断,而不是四舍五入到指定的精度。

示例

下面的示例以TIMESTAMP格式返回当前日期和时间:

SELECT GETDATE() AS DateTime

2022/2/12 15:39:00

下面的示例以两位精度返回当前日期和时间:

SELECT GETDATE(2) AS DateTime

2022/2/12 15:39:21

下面的嵌入式SQL示例比较了本地(特定于时区)和通用(独立于时区)的时间戳:

ClassMethod GetDate()
{
	&sql(SELECT GETDATE(),GETUTCDATE() INTO :a,:b)
	if SQLCODE'=0 {
		w !,"Error code ",SQLCODE }
	else {
		w !,"Local timestamp is:  ",a
		w !,"UTC timestamp is:    ",b
		w !,"$ZTIMESTAMP is:      ",$ZDATETIME($ZTIMESTAMP,3,,3)
	}
}
DHC-APP> d ##class(PHA.TEST.SQLCommand).GetDate()
 
Local timestamp is:  2022-02-12 15:40:34
UTC timestamp is:    2022-02-12 07:40:34
$ZTIMESTAMP is:      2022-02-12 07:40:34.978

下面的示例将Orders表中所选行中的LastUpdate字段设置为当前系统日期和时间。 如果LastUpdate是数据类型%TimeStamp, GETDATE返回当前日期和时间作为ODBC时间戳; 如果LastUpdate是数据类型%PosixTime, GETDATE返回当前日期和时间为编码的64位带符号整数:

UPDATE Orders SET LastUpdate = GETDATE()
  WHERE Orders.OrderNumber=:ord

在下面的例子中,CREATE TABLE语句使用GETDATEStartDate字段设置一个默认值:

CREATE TABLE Employees(
     EmpId       INT NOT NULL,
     LastName    CHAR(40) NOT NULL,
     FirstName   CHAR(20) NOT NULL,
     StartDate   TIMESTAMP DEFAULT GETDATE())
0
0 175
文章 姚 鑫 · 二月 18, 2022 2m read

第五十八章 SQL函数 FLOOR

数值函数,返回小于或等于给定数值表达式的最大整数。

大纲

FLOOR(numeric-expression)

{fn FLOOR(numeric-expression)}

参数

  • numeric-expression - 下限要计算的数字。

FLOOR返回与NUMERIC-EXPRESSION相同的数据类型。

描述

FLOOR返回小于或等于NUMERIC-EXPRESSION的最接近的整数值。返回值的小数位数为0。当numeric-expression为空值、空字符串(‘’)或非数字字符串时,FLOOR返回NULL

请注意,Floor可以作为ODBC标量函数(使用花括号语法)调用,也可以作为SQL常规函数调用。

也可以使用Floor()方法调用从ObjectScript调用此函数:

$SYSTEM.SQL.Functions.FLOOR(numeric-expression)

示例

以下示例显示Floor如何将分数转换为其Floor整数:

SELECT FLOOR(167.111) AS FloorNum1,
       FLOOR(167.456) AS FloorNum2,
       FLOOR(167.999) AS FloorNum3

167	167	167
SELECT {fn FLOOR(167.00)} AS FloorNum1,
       {fn FLOOR(167)} AS FloorNum2
       
167	167
SELECT FLOOR(-167.111) AS FloorNum1,
       FLOOR(-167.456) AS FloorNum2,
       FLOOR(-167.999) AS FloorNum3
       
-168	-168	-168
SELECT FLOOR(-167.00) AS FloorNum 

-167

下面的示例使用子查询将一个包含美国邮政编码(postal Codes)的大表简化为每个楼层Latitude整数的一个代表城市:

SELECT City,State,FLOOR(Latitude) AS FloorLatitude 
FROM (SELECT City,State,Latitude,FLOOR(Latitude) AS FloorNum
      FROM Sample.USZipCode)
GROUP BY FloorNum
ORDER BY FloorNum DESC
0
0 106
文章 Qiao Peng · 二月 18, 2022 6m read

在InterSystems IRIS和InterSystems Caché 里,是否您遇到过执行一个SQL Insert/Update语句,明明给的是正确的日期值,但被告知“值‘2022-01-01’ 校验失败”的类似情况,并感到困惑?

如果有,那么您需要了解一下InterSystems IRIS和InterSystems Caché保存和显示数据的模式。


一 数据模式

InterSystems IRIS和InterSystems Caché里,数据有3种模式,称之为SELECT MODE:
逻辑模式:这是数据被保存到InterSystems IRIS和InterSystems Cache'时的格式。例如,%Date类型的数据,在数据库里被保存为一个整数,即从1840年12月31号到这个日期的天数,而不是YYYY-MM-DD的格式。

ODBC模式:这是ODBC对数据定义的格式。在这个模式下,%Date类型的数据就会显示为YYYY-MM-DD的格式。

显示模式:这是数据在InterSystems IRIS和InterSystems Caché里默认的显示格式。例如在美国语言环境下,%Date的默认显示格式是DD/MM/YYYY格式。

InterSystems IRIS和InterSystems Caché只会使用逻辑模式保存数据,但可以以任何模式显示数据。

二 数据类型与数据模式

0
0 311
文章 姚 鑫 · 二月 17, 2022 4m read

第五十七章 SQL函数 $FIND

字符串函数,返回字符串中子字符串的结束位置,可选的搜索起始点。

大纲

$FIND(string,substring[,start])

参数

  • string - 要搜索的目标字符串。 它可以是变量名、数值、字符串字面值或任何有效表达式。
  • substring - 要搜索的子字符串。 它可以是变量名、数值、字符串字面值或任何有效表达式。
  • start - 可选-子字符串搜索的起始点,指定为正整数。 从字符串开始的字符计数,从1开始计数。 若要从字符串的开头开始搜索,请忽略此参数或指定从01开始。 负数、空字符串或非数字值将被视为0。 指定startNULL会导致$FIND返回< NULL >

$FIND返回SMALLINT数据类型。

描述

$FIND返回一个整数,指定子字符串在字符串中的结束位置。 $FIND搜索字符串的子字符串。 如果找到子字符串,$FIND返回子字符串后面第一个字符的整数位置。 如果substring未找到,$FIND返回0值。

可以包含start选项来指定搜索的起始位置。 如果start大于字符串中的字符数,$FIND返回一个值为0。 如果省略start,则默认为字符串位置1。 如果起始值为0、负数或非数字字符串,则位置1是默认值。

$FIND是区分大小写的。 使用其中一个大小写转换函数来定位字母或字符串的大写和小写实例。

$FIND, POSITION, CHARINDEX, INSTR

$FIND, POSITION, CHARINDEXINSTR都在字符串中搜索指定的子字符串,并返回与第一个匹配项对应的整数位置。 $FIND返回匹配子字符串结束后第一个字符的整数位置。 CHARINDEXPOSITIONINSTR返回匹配子字符串的第一个字符的整数位置。 CHARINDEX$FINDINSTR支持指定子字符串搜索的起始点。 INSTR还支持从起始点指定子字符串出现。

下面的示例演示了这四个函数,指定了所有可选参数。 注意,在这些函数中,stringsubstring的位置不同:

SELECT POSITION('br' IN 'The broken brown briefcase') AS Position,
       CHARINDEX('br','The broken brown briefcase',6) AS Charindex,
       $FIND('The broken brown briefcase','br',6) AS Find,
       INSTR('The broken brown briefcase','br',6,2) AS Inst
       
       
5	12	14	18

示例

在下面的例子中,字符串包含字符串“ABCDEFG”,子字符串包含字符串“BCD”$FIND函数返回值5,表示字符(“E”)在“BCD”后面的位置:

SELECT $FIND('ABCDEG','BCD') AS SubPoint

5

在示例中,通过数字“987654321”查找数字“7”。 它返回4,子字符串后面的位置:

SELECT $FIND(987654321,7) AS SubPoint

4

下面的例子返回3,即子字符串“AA”的第一个实例后面的字符位置:

SELECT $FIND('AAAAAA','AA') AS SubPoint

3

在下面的例子中,$FIND搜索不在字符串中的子字符串。 它返回0 (0):

SELECT $FIND('AABBCCDD','AC') AS SubPoint

0

在下面的例子中,$FIND从第7个字符开始搜索。 下面的例子返回14,也就是下一个出现“R”的字符的位置:

SELECT $FIND('EVERGREEN FOREST','R',7) AS SubPoint

14

在下面的例子中,$FIND在字符串的最后一个字符之后开始搜索。 它返回0 (0):

SELECT $FIND('ABCDEFG','G',10) AS SubPoint

0

下面的嵌入式SQL示例显示,小于1的开始将被视为1:

ClassMethod Find()
{
	s a="ABCDEFG"
	s b="F"
	&sql(SELECT 
	$FIND(:a,:b),
	$FIND(:a,:b,1),
	$FIND(:a,:b,0),
	$FIND(:a,:b,-35)
	INTO :a1,:a2,:a3,:a4)
	if SQLCODE'=0 {
		w !,"Error code ",SQLCODE }
	else {
		w !,"The input string: ",a
		w !,"Two-arg: ",a1
		w !,"3rd arg 1: ",a2
		w !,"3rd arg 0: ",a3
		w !,"3rd arg negative: ",a4 }
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Find()
 
The input string: ABCDEFG
Two-arg: 7
3rd arg 1: 7
3rd arg 0: 7
3rd arg negative: 7

下面的嵌入式SQL示例使用$FIND来搜索包含pi$CHAR(960)Unicode字符的字符串。 第一个$FIND返回pi后面的字符5。 第二个$FIND也返回5; 它从字符4开始搜索,也就是圆周率,也就是搜索的字符。 第三个$FIND从字符5开始搜索; 它返回13,这是pi下一个出现的位置。 注意,返回位置13,即使位置12是字符串中的最后一个字符:

ClassMethod Find1()
{
	s a="QT "_$CHAR(960)_" HONEY "_$CHAR(960)
	s b=$CHAR(960)
	&sql(SELECT 
	$FIND(:a,:b),
	$FIND(:a,:b,4),
	$FIND(:a,:b,5)
	INTO :a1,:a2,:a3)
	if SQLCODE'=0 {
		w !,"Error code ",SQLCODE }
	else {
		w !,"The input string: ",a
		w !,"From beginning: ",a1
		w !,"From position 4: ",a2
		w !,"From position 5: ",a3 
	}
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Find1()
 
The input string: QT π HONEY π
From beginning: 5
From position 4: 5
From position 5: 13
0
0 107
文章 姚 鑫 · 二月 16, 2022 5m read

第五十六章 SQL函数 $EXTRACT

按位置从字符串中提取字符的字符串函数。

大纲

$EXTRACT(string[,from[,to]])

参数

  • string - 要从中提取子字符串的目标字符串。
  • from - 可选-单个字符在目标字符串中的位置,或要提取的字符范围(包括)的开头。 指定为从1开始计数的正整数。
  • to - 可选-要提取的字符范围的结束位置(包括)。 指定为从1开始计数的正整数。

描述

$EXTRACT返回字符串中指定位置的子字符串。 返回的子字符串的性质取决于所使用的参数。

  • $EXTRACT(string)提取字符串中的第一个字符。
  • $EXTRACT(string,from)from指定的位置提取字符。 例如,如果变量var1包含字符串“ABCD”,下面的命令提取“B”(第二个字符):
SELECT $EXTRACT('ABCD',2) AS Extracted

2
  • $EXTRACT(string,from,to)提取以from位置开始,以to位置结束的字符范围。 例如,下面的命令从字符串“1234Alabama567”中提取字符串“Alabama”(即从位置5到位置11的所有字符,包括在内):
SELECT $EXTRACT('1234Alabama567',5,11) AS Extracted

Alabama

这个函数返回VARCHAR类型的数据。

参数

string

字符串值可以是变量名、数字值、字符串字面值或任何有效表达式。

from

from值必须是正整数(但是,请参见注释)。 如果是小数,则截断该小数部分,只使用整数部分。

如果from值大于字符串中的字符数,$EXTRACT返回一个空字符串。

如果指定了from而没有指定to参数,则提取指定的单个字符。

如果与to参数一起使用,它标识要提取的范围的开始,并且必须小于to的值。 如果from = to$EXTRACT返回指定位置的单个字符。 如果from于to$EXTRACT返回一个空字符串。

to

to参数必须与from参数一起使用。 它必须是一个正整数。 如果是小数,则截断该小数部分,只使用整数部分。

如果to的值大于或等于from的值,$EXTRACT返回指定的子字符串。 如果to大于字符串的长度,$EXTRACT返回从位置到字符串末尾的子字符串。 如果to小于from$EXTRACT返回一个空字符串。

示例

下面的示例返回字符串中的第四个字符" S ":

SELECT $EXTRACT('THIS IS A TEST',4) AS Extracted

S

下面的示例返回由第一个到第7个字符组成的子字符串“THIS IS”

SELECT $EXTRACT('THIS IS A TEST',1,7) AS Extracted

THIS IS

下面的嵌入式SQL示例从a中提取第二个字符(“B”),并将这个值赋给变量y

ClassMethod Extract()
{
	s a="ABCD"
	&sql(SELECT $EXTRACT(:a,2) INTO :y)
	if SQLCODE '= 0 {
		w !,"Error code ",SQLCODE }
	else {
		w !,"The extract returns ",y }
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).Extract()
 
The extract returns B

下面的嵌入式SQL示例显示,当from值为“1”时,单参数格式等价于双参数格式。 两个$EXTRACT函数都返回" H "

/// d ##class(PHA.TEST.SQLCommand).Extract1()
ClassMethod Extract1()
{
	s a="HELLO"
	&sql(SELECT $EXTRACT(:a),$EXTRACT(:a,1) INTO :b,:c)
	if SQLCODE'=0 {
		w !,"Error code ",SQLCODE }
	else {
		w !,"The one-arg form returns ",b
		w !,"The two-arg form returns ",c }
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Extract1()
 
The one-arg form returns H
The two-arg form returns H

注意

$EXTRACT与$PIECE和$LIST比较

$EXTRACT从字符串中按整数位置返回一个子字符串。 $PIECE$LIST都适用于特殊格式的字符串。

$PIECE从标准字符串中使用分隔符返回子字符串。

$LIST通过元素的整数位置(不是字符)返回编码列表中的元素的子列表。 $LIST不能用于普通字符串,而$EXTRACT不能用于编码列表。

$EXTRACT$FIND$LENGTH$PIECE函数对标准字符串进行操作。 各种$LIST函数对编码的字符串进行操作,这些字符串与标准字符串不兼容。 唯一的例外是$LISTGET函数和$LIST的单参数和双参数形式,它们接受已编码的字符串作为输入,但将单个元素值作为标准字符串输出。

$EXTRACT 与 Unicode

$EXTRACT函数对字符而不是字节进行操作。 因此,Unicode字符串的处理方式与ASCII字符串相同,如下所示的嵌入式SQL示例使用Unicode字符"pi" ($CHAR(960)):

ClassMethod Extract2()
{
	s a="QT PIE"
	s b=("QT "_$CHAR(960))
	&sql(SELECT 
	$EXTRACT(:a,-33,4),
	$EXTRACT(:a,4,4),
	$EXTRACT(:a,4,99),
	$EXTRACT(:b,-33,4),
	$EXTRACT(:b,4,4),
	$EXTRACT(:b,4,99)
	INTO :a1,:a2,:a3,:b1,:b2,:b3)
	if SQLCODE'=0 {
		w !,"Error code ",SQLCODE }
	else {
		w !,"ASCII form returns ",!,a1,!,a2,!,a3
		w !,"Unicode form returns ",!,b1,!,b2,!,b3 }
}
DHC-APP> d ##class(PHA.TEST.SQLCommand).Extract2()
 
ASCII form returns
QT P
P
PIE
Unicode form returns
QT π
π
π

Null和无效参数

  • stringnull字符串时,返回一个null字符串。
  • from是一个大于字符串长度的数字时,将返回一个空字符串。
  • from为零或负数,并且指定了no to时,将返回一个空字符串。
  • to为零、负数或比from小的数字时,将返回一个空字符串。
  • to为有效值时,from可以为零或负数。 $EXTRACT将这些值视为1

无效的参数值不会产生SQLCODE错误。

在下面的例子中,from值的负数被计算为1; $EXTRACT返回由第一个到第7个字符组成的子字符串“THIS IS”

SELECT $EXTRACT('THIS IS A TEST',-7,7)

THIS IS

在下面的嵌入式SQL示例中,所有的$EXTRACT函数调用都返回空字符串:

ClassMethod Extract3()
{
	s a="THIS IS A TEST"
	s b=""
	&sql(SELECT 
	$EXTRACT(:a,33),
	$EXTRACT(:a,-7),
	$EXTRACT(:a,3,2),
	$EXTRACT(:a,-7,0),
	$EXTRACT(:a,-7,-10),
	$EXTRACT(:b,-33,4),
	$EXTRACT(:b,4,4),
	$EXTRACT(:b,4,99),
	$EXTRACT(NULL,-33,4),
	$EXTRACT(NULL,4,4),
	$EXTRACT(NULL,4,99)
	INTO :a1,:a2,:a3,:a4,:a5,:b1,:b2,:b3,:c1,:c2,:c3)
	if SQLCODE'=0 {
		w !,"Error code ",SQLCODE }
	else {
		w !,"FROM too big: ",a1
		w !,"FROM negative, no TO: ",a2
		w !,"TO smaller than FROM: ",a3
		w !,"TO not a positive integer: ",a4,a5
		w !,"LIST is null string: ",b1,b2,b3,c1,c2,c3 }
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Extract3()
 
FROM too big:
FROM negative, no TO:
TO smaller than FROM:
TO not a positive integer:
LIST is null string:
0
0 173
文章 姚 鑫 · 二月 15, 2022 3m read

第五十五章 SQL函数 %EXTERNAL

以显示格式返回表达式的格式转换函数。

大纲

%EXTERNAL(expression)

%EXTERNAL expression

参数

  • expression - 要转换的表达式。字段名、包含字段名的表达式或返回值为可转换数据类型(如DATE%LIST)的函数。不能是流字段。

描述

%EXTERNAL将表达式转换为显示格式,与当前选择模式(显示模式)无关。显示格式表示VARCHAR数据类型的数据,无论字段或数据类型LogicalToDisplay方法执行什么数据转换。

%EXTERNAL通常用于选择列表SELECT-ITEM。它可以在WHERE子句中使用,但不建议这样使用,因为使用%EXTERNAL会阻止在指定字段上使用索引。

应用%EXTERNAL会将列标题名称更改为诸如“Expression_1”之类的值;因此,通常需要指定列名别名,如以下示例所示。

%EXTERNAL是否转换日期取决于日期字段或函数返回的数据类型。%EXTERNAL转换CURDATECURRENT_DATECURTIMECURRENT_TIME值。它不转换CURRENT_TIMESTAMPGETDATEGETUTCDATENOW$HOROLOG值。

%EXTERNAL%List结构转换为显示格式时,显示的列表元素似乎由空格分隔。这个“空格”实际上是两个非显示字符CHAR(13)CHAR(10)

%EXTERNAL是一个SQL扩展。

无论当前选择模式是什么,要将表达式转换为LOGICAL格式,请使用%INTERNAL函数。 无论当前选择模式是什么,要将表达式转换为ODBC格式,请使用%ODBCOUT函数。

示例

下面的动态SQL示例以当前选择模式格式返回Date of Birth (DOB)数据值,并使用%EXTERNAL函数返回相同的数据。 为了演示的目的,在这个程序中,%SelectMode值在每次调用时都是随机确定的:

ClassMethod External()
{
	s tStatement = ##class(%SQL.Statement).%New()
	s tStatement.%SelectMode = $RANDOM(3)
	if tStatement.%SelectMode = 0 {w "Select mode LOGICAL",! }
	elseif tStatement.%SelectMode=1 {w "Select mode ODBC",! }
	elseif tStatement.%SelectMode=2 {w "Select mode DISPLAY",! }
	s myquery = 2
	s myquery(1) = "SELECT TOP 5 DOB,%EXTERNAL(DOB) AS ExtDOB "
	s myquery(2) = "FROM Sample.Person"
	s qStatus = tStatement.%Prepare(.myquery)
	s rset = tStatement.%Execute()
	d rset.%Display()
	w !,"End of data"
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).External()
Select mode DISPLAY
DOB     ExtDOB
04/25/1990      04/25/1990
 
01/02/2014      01/02/2014
01/02/2014      01/02/2014
01/28/1978      01/28/1978
 
5 Rows(s) Affected
End of data

DHC-APP>d ##class(PHA.TEST.SQLCommand).External()
Select mode LOGICAL
DOB     ExtDOB
54536   04/25/1990
 
63189   01/02/2014
63189   01/02/2014
50066   01/28/1978
 
5 Rows(s) Affected
End of data
DHC-APP>d ##class(PHA.TEST.SQLCommand).External()
Select mode ODBC
DOB     ExtDOB
1990-04-25      04/25/1990
 
2014-01-02      01/02/2014
2014-01-02      01/02/2014
1978-01-28      01/28/1978
 
5 Rows(s) Affected
End of data

下面的例子展示了这个函数的两种语法形式; 它们在其他方面是相同的。 它们指定了%List字段的%EXTERNAL(显示格式)、%INTERNAL(逻辑格式)和%ODBCOUT (ODBC格式):

SELECT TOP 10 %EXTERNAL(FavoriteColors) AS ExtColors,
              %INTERNAL(FavoriteColors) AS IntColors,
              %ODBCOUT(FavoriteColors) AS ODBCColors
FROM Sample.Person

image

以下示例将出生日期(DOB)和四舍五入出生日期(DOB)值转换为%EXTERNAL (DISPLAY格式):

SELECT %EXTERNAL(DOB) AS DOB,
       %INTERNAL(ROUND(DOB,-3)) AS DOBGroup,
       %EXTERNAL(ROUND(DOB,-3)) AS RoundedDOB
FROM Sample.Person
GROUP BY (ROUND(DOB,-3))
ORDER BY DOBGroup

image

0
0 113
文章 姚 鑫 · 二月 14, 2022 3m read

第五十四章 SQL函数 EXP

返回数字的指数(自然对数的倒数)的标量数值函数。

大纲

{fn EXP(expression)}

参数

  • expression - 对数指数,数值表达式。

EXP返回NUMERICDOUBLE数据类型。如果表达式的数据类型为DOUBLE,则EXP返回DOUBLE;否则返回NUMERIC

描述

Exp是指数函数e n,其中e是常数2.718281828。因此,要返回e的值,可以指定{fn exp(1)}Exp是自然对数函数log的逆函数。

EXP返回一个精度为36、小数位数为18的值。如果传递的值为NULL,则EXP返回NULL

EXP只能用作ODBC标量函数(使用花括号语法)。

示例

下面的示例返回常量e:

SELECT {fn EXP(1)} AS e_constant

2.718281828459045235

下面的嵌入式SQL示例返回整数010的指数值:

ClassMethod Exp()
{
	s a = 0
	while a < 11 {
	&sql(SELECT {fn EXP(:a)} INTO :b)
	if SQLCODE'=0 {
		w !,"错误代码 ",SQLCODE
		q 
	} else {
		w !,"指数 ",a," = ",b
		s a=a+1 }
	}
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Exp()
 
指数 0 = 1
指数 1 = 2.718281828459045235
指数 2 = 7.389056098930650228
指数 3 = 20.08553692318766774
指数 4 = 54.59815003314423907
指数 5 = 148.4131591025766034
指数 6 = 403.4287934927351225
指数 7 = 1096.633158428458599
指数 8 = 2980.957987041728276
指数 9 = 8103.083927575384008
指数 10 = 22026.46579480671652

下面的嵌入式SQL示例演示了explog相反:

ClassMethod Exp1()
{
	s x=7
	&sql(SELECT {fn EXP(:x)} AS Exp,
			{fn LOG(:x)} AS Log,
			{fn EXP({fn LOG(:x)})} AS ExpOfLog
		INTO :a,:b,:c)
	if SQLCODE'=0 {
		w !,"Error code ",SQLCODE
		q 
	} else {
		w "Exponential of ",x," = ",a,!
		w "Natural log of ",x," = ",b,!
		w "Exp of Log of  ",x," = ",c
	}
}
DHC-APP> d ##class(PHA.TEST.SQLCommand).Exp1()
Exponential of 7 = 1096.633158428458599
Natural log of 7 = 1.945910149055313306
Exp of Log of  7 = 7.000000000000000004

注意,在第三个函数中,调用数字输入和计算的返回值之间的小差异。下一个示例显示如何处理这种计算差异。

下面的嵌入式SQL示例显示了整数1到10的logexp函数之间的关系:

ClassMethod Exp2()
{
	s a = 1
	while a < 11 {
	&sql(SELECT {fn LOG(:a)} INTO :b)
	if SQLCODE '= 0 {
		w !,"Error code ",SQLCODE
		q 
	} else {
		w !,"Logarithm of ",a," = ",b }
		&sql(SELECT ROUND({fn EXP(:b)},12) INTO :c)
		if SQLCODE '= 0 {
			w !,"Error code ",SQLCODE 
		} else {
			w !,"Exponential of log ",b," = ",c 
			s a = a + 1 
		}
	}
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).Exp2()
 
Logarithm of 1 = 0
Exponential of log 0 = 1
Logarithm of 2 = .6931471805599453089
Exponential of log .6931471805599453089 = 2
Logarithm of 3 = 1.098612288668109691
Exponential of log 1.098612288668109691 = 3
Logarithm of 4 = 1.386294361119890618
Exponential of log 1.386294361119890618 = 4
Logarithm of 5 = 1.609437912434100375
Exponential of log 1.609437912434100375 = 5
Logarithm of 6 = 1.791759469228055002
Exponential of log 1.791759469228055002 = 6
Logarithm of 7 = 1.945910149055313306
Exponential of log 1.945910149055313306 = 7
Logarithm of 8 = 2.079441541679835929
Exponential of log 2.079441541679835929 = 8
Logarithm of 9 = 2.197224577336219384
Exponential of log 2.197224577336219384 = 9
Logarithm of 10 = 2.302585092994045684
Exponential of log 2.302585092994045684 = 10

请注意,这里需要ROUND函数来校正系统计算限制导致的非常小的差异。在上面的示例中,为此目的将舍入任意设置为12位十进制数字。

0
0 94
文章 姚 鑫 · 二月 13, 2022 3m read

第五十三章 SQL函数 %EXACT

排序规则函数,可将字符转换为精确的排序规则格式。

大纲

%EXACT(expression)

%EXACT expression

参数

  • expression - 字符串表达式,可以是列名、字符串文字、数字或另一个函数的结果,其中底层数据类型可以表示为任何字符类型(如CHARVARCHAR2)。

描述

%Exact返回精确排序规则序列中的表达式。此归类序列按如下方式对值进行排序:

  1. NULL排序在所有实际值之前。%Exact对空值没有影响。这与默认排序规则相同。
  2. 规范数值(无论输入为数字还是字符串)在字符串值之前按数字顺序排序。
  3. 字符串值按区分大小写的字符串顺序排序。字符串的精确排序顺序与ANSI标准的ASCII排序顺序相同:数字在大写字母字符之前排序,大写字母字符在小写字母字符之前排序。标点符号出现在序列中的多个位置。

这将导致如下所示的序列:

NULL
-2        /* 规范数排序 */
0
1
2
10
22
88
''         /* 空字符串 */
#          /* 逐个字符的字符串排序 */
-00        /* 非规范数字排序为字符串 */
0 Elm St.  /* 逐个字符的字符串排序 */
022        /* 非规范数字排序为字符串 */
1 Elm St.  
19 Elm St.
19 elm St. /* 字符串排序规则区分大小写 */
19Elm St.
2 Elm St.
201 Elm St.
21 Elm St.
Elm St.

%Exact通常用于按区分大小写的顺序排序包含字母的字符串值。SQL的默认设置是将所有字母转换为大写,以便进行排序。

%Exact是扩展,用于SQL查找查询。

可以在ObjectScript中使用%SYSTEM.Util类的COLLATION()方法执行相同的排序规则转换。

%Exact将输入字符串作为完全数字(规范)或混合字符字符串进行排序,在混合字符串中,数字与任何其他字符的处理方式相同。与%MVR排序规则相比,%MVR排序规则根据字符串中的数字子字符串对字符串进行排序。

DISTINCT 和 GROUP BY

DISTINCT子句和GROUP BY子句根据它们的大写默认排序规则对值进行分组,并返回全部大写字母的值,即使实际数据值都不是全部大写字母也是如此。

  • 可以使用%EXACT按大小写敏感值对值进行分组:按%EXACTmytable group中选择Name(Name)
  • 可以使用%Exact返回每个组的实际区分大小写的值:从MyTable GROUP BY NAME中选择%Exact(Name)

注:默认情况下,SQL索引以大写默认排序规则表示字符串数据。因此,指定精确排序规则可能会阻止使用可能会对性能产生重大影响的索引。

示例

以下示例按照%Exact排序规则对所有街道地址进行排序:

SELECT Name,Street 
FROM Sample.Person
ORDER BY %EXACT Street

下面的示例使用%Exact返回排序序列中高于‘Smith’的所有Name值。第一个示例使用圆括号语法,第二个示例省略圆括号。

SELECT Name 
FROM Sample.Person
WHERE %EXACT(Name) > 'Smith'
0
0 193
文章 姚 鑫 · 二月 12, 2022 1m read

第五十二章 SQL函数 DEGREES

将弧度转换为角度的数值函数。

大纲

DEGREES(numeric-expression)

{fn DEGREES(numeric-expression)}

参数

  • numeric-expression - 以弧度表示的角度的量度。解析为数值的表达式。

度返回NUMERICDOUBLE数据类型。如果NUMERIC-EXPRESSION的数据类型为DOUBLE,则度返回DOUBLE;否则返回NUMERIC

度数可以指定为标准标量函数,也可以指定为使用大括号语法的ODBC标量函数。

描述

DEGREES以弧度为单位进行角度测量,并以度为单位返回相应的角度测量值。如果传递空值,度将返回空。

返回值的默认精度为36,默认小数位数为18

可以使用弧度函数将度数转换为弧度。

示例

下面的嵌入式SQL示例返回与弧度值0到6对应的等价度:

ClassMethod Degrees()
{
	s a = 0
	while a < 7 {
		&sql(SELECT DEGREES(:a) INTO :b)
		if SQLCODE '= 0 {
			w !,"Error code ",SQLCODE
			q 
		} else {
			w !,"radians ",a," = degrees ",b
			s a=a+1 }
		}
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).Degrees()
 
radians 0 = degrees 0
radians 1 = degrees 57.29577951308232089
radians 2 = degrees 114.5915590261646418
radians 3 = degrees 171.8873385392469627
radians 4 = degrees 229.1831180523292836
radians 5 = degrees 286.4788975654116045
radians 6 = degrees 343.7746770784939253
0
0 152
文章 姚 鑫 · 二月 11, 2022 4m read

第五十一章 SQL函数 DECODE

计算给定表达式并返回指定值的函数。

大纲

DECODE(expr {,search,result}[,default])

参数

  • expr - 要解码的表达式。
  • search - 要与Expr进行比较的值。
  • result - Expr匹配搜索时返回的值。
  • default - 可选-如果expr与任何搜索都不匹配,则返回默认值。

描述

可以指定多个搜索和结果对,以逗号分隔。您可以指定一个默认值。DECODE表达式(包括EXPRSEARCHRESULTDEFAULT)中的最大参数数约为100。搜索、结果和默认值可以从表达式派生。

为了计算DECODE表达式,会逐个将expr与每个搜索值进行比较:

  • 如果expr等于search ,则返回相应的结果。
  • 如果expr不等于search ,则返回默认值,如果省略默认值,则返回NULL

仅在将searchExpr进行比较之前计算每个search,而不是在将所有searchExpr进行比较之前评估所有search。因此,如果上一次搜索等于EXPR,不会对搜索求值。

DECODE表达式中,将两个NULL视为等效。如果exprNULL,则将返回同样为NULL的第一次搜索结果。

请注意,为了与Oracle兼容,支持解码。

返回值的数据类型

DECODE返回第一个结果参数的数据类型。如果无法确定第一个结果参数的数据类型,则DECODE返回VARCHAR。对于数值,DECODE从所有可能的结果参数值返回最大长度、精度和小数位数。

如果结果和默认值的数据类型不同,则返回的数据类型是与所有可能的返回值最兼容的类型,即具有最高数据类型优先级的数据类型。例如,如果结果是整数,默认值是小数,则DECODE返回一个带有数据类型数字的值。这是因为数字是与两者兼容的最高优先级的数据类型。

示例

下面的例子将1319岁的年龄“decodes”“Teen”; 默认为“Adult”:

SELECT Name,Age,DECODE(Age,
       13,'Teen',14,'Teen',15,'Teen',16,'Teen',
       17,'Teen',18,'Teen',19,'Teen',
       'Adult') AS AgeBracket
FROM Sample.Person
WHERE Age > 12

下面的示例对空值进行解码。 如果FavoriteColors没有值,DECODE将它替换为字符串' no Preference '; 否则,它返回FavoriteColors值:

SELECT Name,DECODE(FavoriteColors,
                   NULL,'No Preference',
                   $LISTTOSTRING(FavoriteColors,'^')) AS ColorPreference
FROM Sample.Person
ORDER BY Name

下面的示例解码颜色首选参数。如果此人只有一种最喜欢的颜色,则该颜色名称将被字母缩写替换。如果用户有多个最喜欢的颜色,则DECODE返回FavoriteColors值:

SELECT Name,DECODE(FavoriteColors,
                   $LISTBUILD('Red'),'R',
                   $LISTBUILD('Orange'),'O',
                   $LISTBUILD('Yellow'),'Y',
                   $LISTBUILD('Green'),'G',
                   $LISTBUILD('Blue'),'B',
                   $LISTBUILD('Purple'),'V',
                   $LISTBUILD('White'),'W',
                   $LISTBUILD('Black'),'K',
                   $LISTTOSTRING(FavoriteColors,'^')) 
FROM Sample.Person
WHERE FavoriteColors IS NOT NULL
ORDER BY FavoriteColors

请注意,ORDER BY子句按原始字段值排序。以下示例按解码值排序:

SELECT Name,DECODE(FavoriteColors,
                   $LISTBUILD('Red'),'R',
                   $LISTBUILD('Orange'),'O',
                   $LISTBUILD('Yellow'),'Y',
                   $LISTBUILD('Green'),'G',
                   $LISTBUILD('Blue'),'B',
                   $LISTBUILD('Purple'),'V',
                   $LISTBUILD('White'),'W',
                   $LISTBUILD('Black'),'K',
                   $LISTTOSTRING(FavoriteColors,'^')) AS ColorCode
FROM Sample.Person
WHERE FavoriteColors IS NOT NULL
ORDER BY ColorCode

下面的示例将“Employee”记录中的“Company code”字段中的数字代码进行解码,并返回相应的部门名称。 如果员工的公司代码不是110,DECODE返回默认的“Admin(non-tech)”:

SELECT Name,
DECODE (Company,
   1, 'TECH MARKETING', 2, 'TECH SALES', 3, 'DOCUMENTATION', 
   4, 'BASIC RESEARCH', 5, 'SOFTWARE DEVELOPMENT', 6, 'HARDWARE DEVELOPMENT',
   7, 'QUALITY TESTING', 8, 'FIELD SUPPORT', 9, 'PHONE SUPPORT',
   10, 'TECH TRAINING',
       'Admin (non-tech)') AS TechJobs
FROM Sample.Employee WHERE Company<10

该表达式使用Company作为expr参数,并使用10对搜索和结果参数。 默认参数为“Admin(non-tech)”

0
0 104
文章 姚 鑫 · 二月 10, 2022 2m read

第五十章 SQL函数 DAYOFWEEK

Date函数,它返回日期表达式的整型日期。

参数

  • date-expression - 日期表达式,它是列名、另一个标量函数的结果或日期或时间戳文字。

描述

DAYOFYEAR返回一个介于1到366之间的整数,该整数对应于给定日期表达式的一年中的第几天。DAYOFYAR计算闰年日期。

根据日期整数、$HOROLOG$ZTIMESTAMP值、ODBC格式日期字符串或时间戳计算一年中的日期。

日期表达式时间戳可以是数据类型%Library.PosiTime(编码的64位有符号整数)或数据类型%Library.TimeStamp(yyyy-mm-dd hh:mm:ss.fff)

时间戳的时间部分不计算,可以省略。

在计算$HOROLOG值的月份日期时,DAYOFYAR会计算闰年差异,包括世纪日调整:2000年是闰年,1900和2100不是闰年。

DAYOFYEAR可以将1840年12月31日之前的日期表达式值处理为负整数。下面的示例显示了这一点:

SELECT {fn DAYOFYEAR(-306)} AS LastDayFeb, 
       {fn DAYOFYEAR(-305)} AS FirstDayMar  
       
       
60	61

最早有效日期表达式为-672045(0001-01)

可以使用DATEPARTDATENAME函数返回当天计数。DATEPARTDATENAME对日期表达式执行值和范围检查。

也可以使用DAYOFYEAR()方法调用从ObjectScript调用此函数:

$SYSTEM.SQL.Functions.DAYOFYEAR(date-expression)

示例

以下示例都返回数字64,因为日期表达式(2016年3月4日)中的日期是一年中的第64天(自动计算闰年日期):

SELECT {fn DAYOFYEAR('2016-03-04 12:45:37')} AS DayCount

64
SELECT {fn DAYOFYEAR(63981)} AS DayCount

64

以下示例均返回当天的计数:

SELECT {fn DAYOFYEAR({fn NOW()})} AS DNumNow,
       {fn DAYOFYEAR(CURRENT_DATE)} AS DNumCurrD,
       {fn DAYOFYEAR(CURRENT_TIMESTAMP)} AS DNumCurrTS,
       {fn DAYOFYEAR($HOROLOG)} AS DNumHorolog,
       {fn DAYOFYEAR($ZTIMESTAMP)} AS DNumZTS
       
42	42	42	42	42

请注意,$ZTIMESTAMP返回协调世界时(UTC)。其他时间表达式值返回本地时间。这可能会影响DAYOFYAR值。

下面的示例使用子查询返回按每个人的生日日期排序的员工记录:

SELECT Name,DOB
FROM (SELECT Name,DOB,{fn DAYOFYEAR(DOB)} AS BDay FROM Sample.Employee)
ORDER BY BDay

image

0
0 117
文章 姚 鑫 · 二月 9, 2022 6m read

第四十九章 SQL函数 DAYOFWEEK

Date函数,它返回日期表达式的整型星期几。

大纲

{fn DAYOFWEEK(date-expression)}

参数

  • date-expression - 有效的ODBC格式日期或$HOROLOG格式日期,带或不带时间组件。作为列名、另一个标量函数的结果或日期或时间戳文字的表达式。

描述

DAYOFWEEK接受日期表达式,并返回与该日期的星期几对应的整数。一周的天数从一周的第一天开始计算;的默认设置是星期天是一周的第一天。因此,默认情况下,返回值表示这些天:

  • 1 — Sunday
  • 2 — Monday
  • 3 — Tuesday
  • 4 — Wednesday
  • 5 — Thursday
  • 6 — Friday
  • 7 — Saturday

请注意,ObjectScript $ZDATE$ZDATETIME函数计算一周中的天数从06(而不是17)。

日期表达式可以是日期整数、$HOROLOG$ZTIMESTAMP值、ODBC格式的日期字符串或时间戳。

日期表达式时间戳可以是数据类型%Library.PosiTime(编码的64位有符号整数)或数据类型%Library.TimeStamp(yyyy-mm-dd hh:mm:ss.fff)

时间戳的时间部分不被评估,可以省略。

可以使用DATEPARTTO_DATE函数返回星期几的信息。要返回星期几的名称,请使用DAYNAMEDATENAMETO_DATE

也可以使用DAYOFWEEK()方法调用从ObjectScript调用此函数:

$SYSTEM.SQL.Functions.DAYOFWEEK(date-expression)

日期验证

DAYOFWEEK对输入值执行以下检查。如果值未通过检查,则返回空字符串。

  • 有效的日期表达式可以由日期字符串(yyyy-mm-dd)、日期和时间字符串(yyyy-mm-dd hh:mm:ss)、日期整数或$HOROLOG值组成。DAYOFWEEK仅计算日期表达式的日期部分。
  • 日期字符串必须完整且格式正确,包含适当数量的元素和每个元素的数字,以及适当的分隔符。年份必须指定为四位数。
  • 日期值必须在有效范围内。年份:00019999。月份:112天:131
  • 一个月中的天数必须与月和年匹配。例如,日期‘02-29’只有在指定年份是闰年时才有效。
  • 小于10的日期值可以包含或省略前导零。不允许其他非规范整数值。因此,“日期”值“07”“7”有效,但“007”“7.0”“7a”无效。

设置每周的第一天

默认情况下,一周的第一天是周日。 你可以通过指定SET ^%SYS("sql","sys","day of week")=n来覆盖这个默认的系统范围,其中n个值是1=周一到7=周日。 SET ^%SYS("sql","sys","day of week")=1设置星期一为一周的第一天。 如果Monday是一周的第一天,周三日期表达式返回3,而不是如果Sunday是一周的第一天将返回的4。 如果要重置的默认值(周日为一周的第一天),请指定^%SYS("sql","sys","day of week")=7

通过设置SET ^%SYS("sql","sys","day of week",namespace)=n,其中n个值为1=周一到7=周日。 使用SET ^%SYS("sql","sys","day of week","USER")=1设置USER命名空间的周一为每周的第一天。 一旦在命名空间级别设置一周的第一天,通过指定^%SYS("sql","sys","day of week")=n更改系统范围的设置,对该命名空间没有影响。 为了恢复更改命名空间的默认第一天,kill ^%SYS("sql","sys","day of week",namespace)

还支持用于确定星期、星期和其他日期设置的ISO 8601标准。 这一标准主要在欧洲国家使用。 ISO 8601标准从星期一开始计算一周的天数。 SET ^%SYS("sql","sys","week ISO8601")=1 若要禁用,请将其设置为0。 如果ISO8601周被激活,而周的天数未定义或设置为默认值(7=周日),则ISO8601标准将覆默认值。 如果 day of week设置为任何其他值,则DAYOFWEEK将覆盖周ISO8601。

示例

在下面的例子中,两个select项都返回数字5(如果周日被设置为一周的第一天),因为指定的date-expression (64701 = February 22, 2018)是一个星期四:

SELECT {fn DAYOFWEEK('2018-02-22')}||' '||DATENAME('dw','2018-02-22') AS ODBCDoW,
       {fn DAYOFWEEK(64701)}||' '||DATENAME('dw','64701') AS HorologDoW
       

5 Thursday	5 Thursday

在下面的例子中,所有的select-item返回的都是对应于当前日期的整数:

SELECT {fn DAYOFWEEK({fn NOW()})} AS DoW_Now,
       {fn DAYOFWEEK(CURRENT_DATE)} AS DoW_CurrDate,
       {fn DAYOFWEEK(CURRENT_TIMESTAMP)} AS DoW_CurrTstamp,
       {fn DAYOFWEEK($ZTIMESTAMP)} AS DoW_ZTstamp,
       {fn DAYOFWEEK($HOROLOG)} AS DoW_Horolog
       
       
3	3	3	3	3

注意$ZTIMESTAMP返回协调世界时(UTC)。 其他时间表达式值返回本地时间。 这可能会影响DAYOFWEEK值。

下面的嵌入式SQL示例演示如何更改命名空间的一周的第一天。它最初设置系统范围的每周第一天(设置为7),然后设置命名空间的每周第一天(设置为3)。在程序终止特定于命名空间的设置之前,后续的系统范围内的每周第一天更改(更改为2)对命名空间第一天没有影响。取消特定于命名空间的设置会立即将该命名空间每周的第一天重置为当前系统范围的值。最后,程序恢复系统范围的初始设置。

注:以下程序测试是否具有%SYSuser命名空间的特定于命名空间的每周第一天设置。如果这样做,此程序将中止以阻止更改这些设置。

SetUp
  SET TestNsp="USER"
  SET ControlNsp="%SYS"
InitialDoWValues
  WRITE "Systemwide default DoW initial values",!
  DO TestDayofWeek()
  IF a=b {WRITE "No namespace-specific DoW defaults",!!}
  ELSE {WRITE "DoW initial settings are namespace-specific",!
        WRITE "Stopping this program"
        QUIT }
  SET initialDoW=^%SYS("sql","sys","day of week")
SetSystemwideDoW
  KILL ^%SYS("sql","sys","day of week",TestNsp)
  KILL ^%SYS("sql","sys","day of week",ControlNsp)
  SET ^%SYS("sql","sys","day of week")=7
  WRITE "Systemwide DoW set",!
  DO TestDayofWeek()
SetNamespaceDoW
  SET ^%SYS("sql","sys","day of week",TestNsp)=3
  WRITE TestNsp," namespace DoW set",!
  &sql(SELECT {fn DAYOFWEEK($HOROLOG)} INTO :a)
  DO TestDayofWeek()
ResetSystemwideDoW
  SET ^%SYS("sql","sys","day of week")=2
  WRITE "Systemwide DoW set with ",TestNsp," DoW set",!
  DO TestDayofWeek
KillNamespaceDoW
  KILL ^%SYS("sql","sys","day of week",TestNsp)
  WRITE "Namespace ",TestNsp," DoW killed",!
  DO TestDayofWeek
ResetSystemwideDoWDefault
  SET ^%SYS("sql","sys","day of week")=initialDoW
  WRITE "Systemwide DoW reset after ",TestNsp," DoW killed",!
  DO TestDayofWeek
TestDayofWeek()
  SET $NAMESPACE=TestNsp
  &sql(SELECT {fn DAYOFWEEK($HOROLOG)} INTO :a)
  WRITE "Today is the ",a," day of week in ",$NAMESPACE,!
  SET $NAMESPACE=ControlNsp
  &sql(SELECT {fn DAYOFWEEK($HOROLOG)} INTO :b)
  WRITE "Today is the ",b," day of week in ",$NAMESPACE,!!
  RETURN

下面的嵌入式SQL示例显示了应用了ISO 8601标准的默认星期几和星期几。它假定星期几未定义或设置为默认值:

TestISO
  SET def=$DATA(^%SYS("sql","sys","week ISO8601"))
  IF def=0 {SET ^%SYS("sql","sys","week ISO8601")=0}
  ELSE {SET isoval=^%SYS("sql","sys","week ISO8601")}
     IF isoval=1 {GOTO UnsetISO }
     ELSE {SET isoval=0 GOTO DayofWeek }
UnsetISO
  SET ^%SYS("sql","sys","week ISO8601")=0
DayofWeek
  &sql(SELECT {fn DAYOFWEEK($HOROLOG)} INTO :a)
  WRITE "Today:",!
  WRITE "default day of week is ",a,!
  SET ^%SYS("sql","sys","week ISO8601")=1
  &sql(SELECT {fn DAYOFWEEK($HOROLOG)} INTO :b)
  WRITE "ISO8601 day of week is ",b,!
ResetISO
  SET ^%SYS("sql","sys","week ISO8601")=isoval
0
0 394
文章 姚 鑫 · 二月 8, 2022 3m read

第四十八章 SQL函数 DAYOFMONTH

返回日期表达式的月份日期的日期函数。

大纲

{fn DAYOFMONTH(date-expression)}

参数

  • date-expression - 要从中返回月值日期的日期或时间戳表达式。作为列名、另一个标量函数的结果或日期或时间戳文字的表达式。

描述

DAYOFMONTH131之间的整数形式返回每月的第几天。日期表达式可以是日期整数、$HOROLOG$ZTIMESTAMP值、ODBC格式的日期字符串或时间戳。

日期表达式时间戳可以是数据类型%Library.PosiTime(编码的64位有符号整数)或数据类型%Library.TimeStamp(yyyy-mm-dd hh:mm:ss.fff)

TIMESTAMP$HOROLOG字符串的时间部分不计算,可以省略。

DAYOFMONTHDAY函数在功能上是相同的。

也可以使用DAYOFMONTH()方法调用从ObjectScript调用此函数:

DHC-APP>  w $SYSTEM.SQL.DAYOFMONTH("2018-02-25")
25

Timestamp date-expression

时间戳字符串的日(Dd)部分应该是介于131之间的整数。但是,不会对用户提供的值进行范围检查。按照指定的方式返回大于31的数字和分数。由于(-)用作分隔符,因此不支持负数。输入上的前导零是可选的;输出上不显示前导零。

当日期部分为‘0’‘00’或非数字值时,DAYOFMONTH返回NULL。如果完全省略日期字符串的日期部分(‘yyyy-mm hh:mm:ss’),或者如果没有提供日期表达式,也会返回NULL

可以使用以下SQL标量函数返回日期时间字符串的元素:年、月、DAYOFMONTH(或日)、小时、分钟、秒。使用DATEPARTDATENAME函数可以返回相同的元素。DATEPARTDATENAME对日期值执行值和范围检查。

$HOROLOG日期表达式

在计算$HOROLOG值的月份日期时,DAYOFMONTH会计算闰年差异,包括世纪日调整:2000年是闰年,19002100不是闰年。

DAYOFMONTH可以将1840年12月31日之前的日期表达式值处理为负整数。下面的示例显示了这一点:

SELECT {fn DAYOFMONTH(-306)} AS DayOfMonthFeb,    /* February 29, 1840 */
       {fn DAYOFMONTH(-305)} AS DayOfMonthMar,    /* March 1, 1840     */
       {fn DAYOFMONTH(-127410)} AS DayOfMonthFeb  /* February 29, 1492 */
       
29	1	29

LAST_DAY函数返回指定日期的月份最后一天的日期(以$HOROLOG格式表示)。

示例

以下示例返回数字25,因为指定的日期是该月的第25天:

SELECT {fn DAYOFMONTH('2018-02-25')} AS DayNumTS,
       {fn DAYOFMONTH(64704)} AS DayNumH

25	25

下面的示例还返回数字25,表示该月中的某一天。省略年份,但分隔符(-)用作占位符:

SELECT {fn DAYOFMONTH('-02-25 11:45:32')} AS DayNum

25

以下示例返回<null>

SELECT{fn DAYOFMONTH('2018-02-00 11:45:32')} AS DayNum
SELECT {fn DAYOFMONTH('2018-02 11:45:32')} AS DayNum
SELECT {fn DAYOFMONTH('11:45:32')} AS DayNum

以下DAYOFMONTH示例均返回当月的当前日期:

SELECT {fn DAYOFMONTH({fn NOW()})} AS DoM_Now,
       {fn DAYOFMONTH(CURRENT_DATE)} AS DoM_CurrD,
       {fn DAYOFMONTH(CURRENT_TIMESTAMP)} AS DoM_CurrTS,
       {fn DAYOFMONTH($HOROLOG)} AS DoM_Horolog,
       {fn DAYOFMONTH($ZTIMESTAMP)} AS DoM_ZTS
       
8	8	8	8	8

请注意,$ZTIMESTAMP返回协调世界时(UTC)。其他时间表达式值返回本地时间。这可能会影响DAYOFMONTH值。

下面的示例显示了前导零被取消。它返回长度为1或2的值,具体取决于月值的日期:


SELECT LENGTH({fn DAYOFMONTH('2018-02-05')}),
       LENGTH({fn DAYOFMONTH('2018-02-15')})


1	2
0
0 119
文章 姚 鑫 · 二月 7, 2022 2m read

第四十七章 SQL函数 DAYNAME

Date函数,它返回日期表达式的星期几的名称。

大纲

{fn DAYNAME(date-expression)}

参数

  • date-expression - 计算结果为日期整数、ODBC日期或时间戳的表达式。该表达式可以是列名、另一个标量函数的结果或日期或时间戳文字。

描述

DAYNAME返回与指定日期对应的日期的名称。返回值为字符串,最大长度为15。默认返回的日期名称为:Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday

要更改这些默认日期名称值,请使用带有WEEKDAY_NAME选项的SET OPTION命令。

日期名称是针对日期整数、$HOROLOG$ZTIMESTAMP值、ODBC格式日期字符串或时间戳计算的。

日期表达式时间戳可以是数据类型%Library.PosiTime(编码的64位有符号整数)或数据类型%Library.TimeStamp(yyyy-mm-dd hh:mm:ss.fff)

时间戳的时间部分不计算,可以省略。

DAYNAME检查提供的日期是否为有效日期。年份必须介于00019999之间(包括00019999)、月01到12和适合该月的日期(例如,02/29仅在闰年有效)。如果日期无效,DAYNAME将发出SQLCODE-400错误(发生致命错误)。

可以使用DATENAME函数返回星期几的信息。可以使用TO_DATE检索带有其他日期元素的日期名称或日期名称缩写。要返回与星期几对应的整数,请使用DAYOFWEEK DATEPARTTO_DATE

也可以使用DAYNAME()方法调用从ObjectScript调用此函数:

$SYSTEM.SQL.Functions.DAYNAME(date-expression)

示例

以下示例都返回字符串星期三,因为日期的日期(2018年2月21日)是星期三。第一个示例采用时间戳字符串:

SELECT {fn DAYNAME('2018-02-21 12:35:46')} AS Weekday

Wednesday

第二个示例采用日期整数:

SELECT {fn DAYNAME(64700)} AS Weekday

Wednesday

以下示例均返回一周中当前日期的名称:

SELECT {fn DAYNAME({fn NOW()})} AS Wd_Now,
       {fn DAYNAME(CURRENT_DATE)} AS Wd_CurrDate,
       {fn DAYNAME(CURRENT_TIMESTAMP)} AS Wd_CurrTstamp,
       {fn DAYNAME($ZTIMESTAMP)} AS Wd_ZTstamp,
       {fn DAYNAME($HOROLOG)} AS Wd_Horolog
       
Saturday	Saturday	Saturday	Saturday	Saturday

请注意,$ZTIMESTAMP返回协调世界时(UTC)。其他时间表达式值返回本地时间。这可能会影响DAYNAME值。

以下嵌入式SQL示例显示DAYNAME如何响应无效日期(2017年不是闰年):

ClassMethod DayName()
{
	s testdate = "2017-02-29"
	&sql(
		SELECT {fn DAYNAME(:testdate)}
		INTO :a)
	if SQLCODE '= 0 {
		w !,"Error code ",SQLCODE 
	} else {
		w !,"returns: ",a 
	}
	QUIT
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).DayName()
 
Error code -400
0
0 62
文章 姚 鑫 · 二月 6, 2022 1m read

第四十六章 SQL函数 DAY

返回日期表达式的月份日期的日期函数。

大纲

DAY(date-expression)

{fn DAY(date-expression)}

参数

  • date-expression - 作为列名、另一个标量函数的结果或日期或时间戳文字的表达式。

描述

注意:DAY函数是DAYOFMONTH函数的别名。提供DAY是为了与TSQL兼容。

SELECT day("2022-02-28") AS day

28
SELECT day(+$h) AS day

5
0
0 96
文章 姚 鑫 · 二月 5, 2022 7m read

第四十五章 SQL函数 DATEPART

日期/时间函数,返回表示日期/时间表达式指定部分的值的整数。

大纲

DATEPART(datepart,date-expression)

参数

  • datepart - 要返回的日期/时间信息的类型。日期或时间部分的名称(或缩写)。这个名称可以用大写或小写来指定,有或没有引号。datepart可以指定为文字或主机变量。
  • date-expression - 从中返回datepart值的日期、时间或时间戳表达式。日期表达式必须包含datepart类型的值。

描述

DATEPORT函数以整数数据类型返回关于指定日期/时间表达式的DATEPORT信息。唯一的例外是sqltimestamp (sts),它以数据类型%Library.Timestamp返回。要以字符串形式返回日期部分信息,请使用DATENAME

DATEPART只返回日期表达式中一个元素的值;要返回包含多个日期部分的字符串,请使用TO_DATE

也可以使用DATEPART()方法调用从ObjectScript调用此函数:

$SYSTEM.SQL.Functions.DATEPART(datepart,date-expression)

提供DATEPART是为了与Sybase和Microsoft SQL Server兼容。

Datepart 参数

日期部分参数可以是下列日期/时间组件之一,可以是全名(日期部分列)或其缩写(缩写列)。这些datepart组件名称和缩写不区分大小写。

Date PartAbbreviationsReturn Values
yearyyyy, yy0001-9999
quarterqq, q1-4
monthmm, m1-12
weekwk, ww1-53
weekdaydw1-7 (Sunday,...,Saturday)
dayofyeardy, y1-366
daydd, d1-31
hourhh0-23
minutemi, n0-59
secondss, s0-59
millisecondms0-999 (with precision of 3)
microsecondmcs0–999999 (with precision of 6)
nanosecondns0–999999999 (with precision of 9)
sqltimestampstsSQL_TIMESTAMP: yyyy-mm-dd hh:mm:ss

上表显示了不同日期部分的默认返回值。可以使用带有各种时间和日期选项的“设置选项”命令来修改其中几个日期部分的返回值。

week:可以配置为使用默认算法或ISO 8601标准算法来确定给定日期的一年中的星期。

weekday:对weekday的默认设置是将星期日指定为一周的第一天(weekday=1)。但是,可以将一周的第一天配置为另一个值,或者可以应用ISO 8601标准,将星期一指定为一周的第一天。请注意,ObjectScript $ZDATE$ZDATETIME函数计算的周天数是从0到6(而不是从1到7)。

second:如果日期表达式包含小数秒,将秒作为十进制数返回,整数秒作为整数部分,小数秒作为小数部分。精度不会被截断。

millisecond:返回三个小数位数的精度,去掉尾随零。如果日期表达式的精度超过三位数会将其截断为三位数。

sqltimestamp: 将输入数据转换为时间戳格式,并在必要时为时间元素提供零值。sqltimestamp(缩写为sts) datepart值仅用于datepart。不要试图在其他上下文中使用此值。

datepart可以指定为带引号的字符串,不带引号,或者在带引号的字符串周围加上括号。无论如何指定,都不会对datepart执行文字替换;对日期表达式执行文字替换。所有datepart值都返回一个数据类型INTEGER值,但sqltimestamp(或sts)除外,它以数据类型timestamp的字符串形式返回其值。

日期输入格式

日期表达式参数可以采用以下任何格式:

  • %Date logical value (+$H)

  • %PosixTime (%Library.PosixTime) logical value (an encoded 64-bit signed integer)

  • %TimeStamp (%Library.TimeStamp) logical value (YYYY-MM-DD HH:MM:SS.FFF), also known as ODBC format.

  • IRIS %String (or compatible) value

%String(或兼容)值可以是以下任何格式:

  • 99999,99999 ($H format)

  • Sybase/SQL-Server-date Sybase/SQL-Server-time

  • Sybase/SQL-Server-time Sybase/SQL-Server-date

  • Sybase/SQL-Server-date (default time is 00:00:00)

  • Sybase/SQL-Server-time (default date is 01/01/1900)

Sybase/SQL-Server-date是这五种格式之一:

mmdelimiterdddelimiter[yy]yy dd Mmm[mm][,][yy]yy dd [yy]yy Mmm[mm] yyyy Mmm[mm] dd yyyy [dd] Mmm[mm]

其中分隔符是斜杠(/)、连字符(-)或句点(.)).

Sybase/SQL服务器时间代表这三种格式之一:

HH:MM[:SS:SSS][{AM|PM}] HH:MM[:SS.S] HH['']{AM|PM}

如果日期表达式指定了时间格式,但没有指定日期格式,则DATENAME默认为日期1900–01–01,该日期的工作日值为2(星期一)。

对于sqltimestamp,时间以24小时制返回。分数秒被截断。

无效的参数错误代码

如果指定无效的datepart选项,DATEPART将生成一个SQLCODE -8错误代码,并且以下%msg: 'badopt' is not a recognized DATEPART option.

如果指定了无效的日期表达式值(例如,字母文本字符串),DATEPART将生成SQLCODE -400错误代码和以下 %msg: Invalid input to DATEPART() function: DATEPART('year','badval')。如果指定的日期表达式未通过验证(如下所述),datepart将生成一个SQLCODE -400错误代码,并显示以下%msg: Unexpected error occurred: <ILLEGAL VALUE>datepart.

范围和值检查

DATEPART对日期表达式值执行以下检查。如果值未通过检查,则返回空字符串。

  • 有效的日期表达式可以由日期字符串(yyyy-mm-dd)、时间字符串(hh:mm:ss)或日期和时间字符串(yyy-mm-dd hh:mm:ss)组成。如果同时指定了日期和时间,则两者都必须有效。例如,如果未指定时间字符串,则可以返回年份值,但是如果指定了无效的时间字符串,则不能返回年份值。
  • 日期字符串必须完整且格式正确,每个元素都有适当数量的元素和数字,以及适当的分隔符。例如,如果省略了“日”值,则不能返回“年”值。年份必须指定为四位数。
  • 时间字符串必须用适当的分隔符正确格式化。因为时间值可以为零,所以可以省略一个或多个时间元素(保留或省略分隔符),这些元素将以零值返回。因此,' hh:mm:ss '' hh:mm '' hh:mm '' hh:ss '' hh:',和':::'都是有效的。要省略Hour元素,日期表达式不能包含字符串的日期部分,并且必须至少保留一个分隔符(:)。
  • 日期和时间值必须在有效范围内。年份:00019999。月份:112。天数:131天。小时:023。分钟:059。秒:059
  • 一个月中的天数必须与月和年相匹配。例如,日期“02–29”仅在指定年份为闰年时有效。
  • 大多数小于10的日期和时间值可能包含或省略前导零。但是,如果小时值是日期时间字符串的一部分,则小于10的小时值必须包含前导零。不允许其他非规范整数值。因此,“07”“7”的“日”值有效,但“007”“7.0”“7a”无效。
  • 如果日期表达式指定了时间格式,但没有指定日期格式,则DATEPART不会对时间分量值执行范围验证。

示例

在下面的示例中,每个DATEPART将日期时间字符串的年份部分(在本例中为2018年)作为整数返回。请注意,日期表达式可以有多种格式,datepart可以指定为datepart名称或datepart缩写,带引号或不带引号:

SELECT DATEPART('yy','2018-02-22 12:00:00') AS YearDTS,
       DATEPART('year','2018-02-22') AS YearDS,
       DATEPART(YYYY,'02/22/2018') AS YearD,
       DATEPART(YEAR,64701) AS YearHD,
       DATEPART('Year','64701,23456') AS YearHDT
       
2018	2018	2018	2018	2018

以下示例基于$HOROLOG值返回当前年份和季度:

SELECT DATEPART('yyyy',$HOROLOG) AS Year,DATEPART('q',$HOROLOG) AS Quarter


2022	1

下面的嵌入式SQL示例使用主机变量来提供DATEPART参数值:

  SET x="year"
  SET datein="2018-02-22"
  &sql(SELECT DATEPART(:x,:datein)
       INTO :partout)
  WRITE "the ",x," is ",partout

下面的示例返回Sample.Person表的出生日期(按星期几排序):

SELECT Name,DOB,DATEPART('weekday',DOB) AS bday
FROM Sample.Person
ORDER BY bday,DOB

在以下示例中,每个DATEPART返回20作为日期表达式字符串的分钟部分:

SELECT DATEPART('mi','2018-2-20 12:20:07') AS Minutes,
       DATEPART('n','2018-02-20 10:20:') AS Minutes,
       DATEPART(MINUTE,'2018-02-20 10:20') AS Minutes
       
       
20	20	20

在下面的示例中,每个DATEPART返回0作为日期表达式字符串的秒部分:

SELECT DATEPART('ss','2018-02-20 03:20:') AS Seconds,
       DATEPART('S','2018-02-20 03:20') AS Seconds,
       DATEPART('Second','2018-02-20') AS Seconds

0	0	0

以下示例以TIMESTAMP数据类型返回完整的SQL TIMESTAMPDATEPART填充缺失的时间信息以返回时间戳‘2018-02-25 00:00:00’

SELECT DATEPART(sqltimestamp,'2/25/2018') AS DTStamp


2018/2/25 0:00:00

以下示例以$HOROLOG格式提供日期和时间,并返回时间戳‘2018-02-22 06:30:56’

SELECT DATEPART(sqltimestamp,'64701,23456') AS DTStamp

2018/2/22 6:30:56

下面的示例使用带有DATEPART的子查询来返回生日为闰年日(2月29日)的那些人:

SELECT Name,DOB
FROM (SELECT Name,DOB,DATEPART('dd',DOB) AS DayNum,DATEPART('mm',DOB) AS Month FROM Sample.Person)
WHERE Month=2 AND DayNum=29 
0
0 244
文章 姚 鑫 · 二月 4, 2022 6m read

第四十四章 SQL函数 DATENAME

日期/时间函数,它返回一个字符串,表示日期/时间表达式中指定部分的值。

参数

  • datepart - 要返回的日期/时间信息类型。 日期或时间部分的名称(或缩写)。 可以用大写或小写指定该名称,也可以不加引号。 可以将datepart指定为文字或主机变量。
  • date-expression - 要返回datepart值的日期、时间或时间戳表达式。 日期表达式必须包含datepart类型的值。

描述

DATENAME函数返回日期/时间值中指定部分的名称(例如“June”)。 结果作为数据类型VARCHAR(20)返回。 如果结果是数字(例如“23”表示当天),它仍然作为VARCHAR(20)字符串返回。 要以整数形式返回此信息,请使用DATEPART。 要返回包含多个日期部分的字符串,请使用TO_DATE

请注意,DATENAME是为Sybase和Microsoft SQL Server兼容性而提供的。

这个函数也可以通过调用DATENAME()方法从ObjectScript调用:

$SYSTEM.SQL.Functions.DATENAME(datepart,date-expression)

Datepart 参数

datepart参数可以是包含一个(且仅包含一个)以下日期/时间组件的字符串,可以是全名(date Part列),也可以是缩写(缩写列)。 这些datepart组件名称和缩写不区分大小写。

Date PartAbbreviationsReturn Values
yearyyyy, yy0001-9999
quarterqq, q1-4
monthmmJanuary,...December
weekwk, ww1-53
weekdaydwSunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
dayofyeardy, y1-366
daydd, d1-31
hourhh0-23
minutemi, n0-59
secondss, s0-59
millisecondms0-999 (with precision of 3)
microsecondmcs0–999999 (with precision of 6)
nanosecondns0–999999999 (with precision of 9)

如果将无效的datepart值指定为文字,则会发出SQLCODE -8错误码。 但是,如果提供一个无效的datepart值作为主机变量,则不会发出SQLCODE错误,并且DATENAME函数返回一个NULL值。

上表显示了不同日期部分的默认返回值。 通过使用带有不同时间和日期选项的SET OPTION命令,可以修改其中几个日期部分的返回值。

week:可以配置为使默认算法或ISO 8601标准算法确定给定日期的年度星期。

weekday:对于weekday的默认设置是将周日指定为一周的第一天(工作日=1)。 但是,可以将一周的第一天配置为另一个值,或者可以应用指定星期一为一周的第一天的ISO 8601标准。

millisecond:返回一个包含毫秒数(千分之一秒)的字符串。 如果日期表达式的精度超过3个小数位数,将其截断为3个数字,并将该数字作为字符串返回。 如果日期表达式具有指定的精度,但精度小于3个小数位数,则 0将其填充为3个数字,并将该数字作为字符串返回。 微秒和纳秒执行类似的截断和填充零。

可以将datepart指定为带引号的字符串或不带引号的字符串。 这些语法变体执行的操作略有不同:

  • 引号:DATENAME('month','2018-02-25'):在创建缓存查询时,datepart被视为一个字面值。 SQL执行文字替换。 这将产生一个更普遍的可重用的缓存查询。
  • 没有引号:DATENAME(month,'2018-02-25'):在创建缓存查询时,datepart被视为关键字。 没有文字替换。 这将产生一个更具体的缓存查询。

日期表达格式

date-expression参数可以是以下任何一种格式:

  • %Date logical value (+$H)

  • %PosixTime (%Library.PosixTime) logical value (an encoded 64-bit signed integer)

  • %TimeStamp (%Library.TimeStamp) logical value (YYYY-MM-DD HH:MM:SS.FFF), also known as ODBC format.

  • %String (or compatible) value %String(或compatible)值可以是以下任何格式:

  • 99999,99999 ($H format)

  • Sybase/SQL-Server-date Sybase/SQL-Server-time

  • Sybase/SQL-Server-time Sybase/SQL-Server-date

  • Sybase/SQL-Server-date (default time is 00:00:00)

  • Sybase/SQL-Server-time (default date is 01/01/1900)

Sybase/SQL-Server-date是以下五种格式之一:

mmdelimiterdddelimiter[yy]yy dd Mmm[mm][,][yy]yy dd [yy]yy Mmm[mm] yyyy Mmm[mm] dd yyyy [dd] Mmm[mm]

其中分隔符是斜杠(/)、连字符(-)或句号(.)。

Sybase/SQL-Server-time表示以下三种格式之一:

HH:MM[:SS:SSS][{AM|PM}] HH:MM[:SS.S] HH['']{AM|PM}

如果date-expression指定了时间格式但没有指定日期格式,则DATENAME的默认值为1900-01-01,其中weekday的值为Monday

范围和值检查

DATENAME对输入值执行以下检查。 如果一个值检查失败,则返回null字符串。

  • 有效的日期表达式可以由日期字符串(yyyy-mm-dd)、时间字符串(hh:mm:ss)或日期和时间字符串(yyyy-mm-dd hh:mm:ss)组成。 如果同时指定日期和时间,则日期和时间都必须有效。 例如,如果没有指定时间字符串,则可以返回Year值,但如果指定了无效的时间字符串,则无法返回Year值。
  • 日期字符串必须完整,格式正确,包含适当数量的元素和每个元素的数字,以及适当的分隔符。 例如,如果省略了Day值,则不能返回Year值。 年必须指定为四位数字。
  • 时间字符串必须使用适当的分隔符进行适当的格式化。 因为时间值可以为零,所以可以省略一个或多个时间元素(保留或省略分隔符),这些元素将返回值为零。 因此,“hh: mm: ss”,“hh: mm:”“hh: mm”,“hh:: ss”,“hh::”“hh”,和“::”都是有效的。 若要省略Hour元素,date-expression必须没有字符串的日期部分,并且必须保留至少一个分隔符(:)。
  • 日期和时间值必须在有效范围内。 年龄:0001到9999。 月份:1 - 12个月。 天数:1 - 31天。 小时:0到23。 分钟:0到59分钟。 秒:0 ~ 59。
  • 一个月中的天数必须与月和年相匹配。 例如,日期“02-29”仅在指定的年份为闰年时有效。
  • 大多数小于10的日期和时间值可能包括或省略前导零。 但是,小于10的Hour值必须包括前导0,如果它是datetime字符串的一部分。 不允许使用其他非规范整数值。 因此,Day值为“07”“7”是有效的,但“007”“7.0”“7a”无效。
  • 如果date-expression指定了时间格式但没有指定日期格式,则DATENAME不会对时间组件值执行范围验证。

示例

在下面的例子中,每个DATENAME返回'Wednesday',因为它是指定日期的星期几('dw'):


SELECT DATENAME('dw','2018-02-21') AS DayName,
       DATENAME(dw,'02/21/2018') AS DayName,
       DATENAME('DW',64700) AS DayName
       
Wednesday	Wednesday	Wednesday

下面的例子返回'December',因为它是指定日期的月份名称('mm'):

SELECT DATENAME('mm','2018-12-20 12:00:00') AS MonthName

December

下面的示例返回'2018'(字符串形式),因为它是指定日期的年份('yy'):

SELECT DATENAME('yy','2018-12-20 12:00:00') AS Year

2018

注意,上面的例子使用了日期部分的缩写。 但是,你可以指定全名,如下例所示:

SELECT DATENAME('Q',$HOROLOG) AS Q,
       DATENAME('WK',$HOROLOG) AS WkCnt,
       DATENAME('DY',$HOROLOG) AS DayCnt
       
       
1	6	35

下面的嵌入式SQL示例将datepartdate-expression作为宿主变量传入:

ClassMethod DateName()
{
	s a="year"
	s b=$HOROLOG
	&sql(SELECT DATENAME(:a,:b) INTO :c)
	w "this year is: ",c
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).DateName()
this year is: 2022

下面的示例使用子查询从出生日期为星期三的Sample.Person返回记录:

SELECT Name AS WednesdaysChild,DOB
FROM (SELECT Name,DOB,DATENAME('dw',DOB) AS Wkday FROM Sample.Person)
WHERE Wkday='Wednesday'
ORDER BY DOB
0
0 107
文章 姚 鑫 · 二月 3, 2022 7m read

[toc]

第四十三章 SQL函数 DATEDIFF

日期/时间函数,返回两个日期之间指定日期部分的整数差。

大纲

DATEDIFF(datepart,startdate,enddate)

参数

  • datepart - 日期或时间部分的名称(或缩写)。这个名称可以用大写或小写来指定,有或没有引号。datepart可以指定为文字或主机变量。
  • startdate - 间隔的开始日期/时间。可以是各种标准格式的日期、时间或日期时间。
  • enddate - 间隔的结束日期/时间。可以是各种标准格式的日期、时间或日期时间。从enddate中减去startdate,以确定两个日期之间的日期部分间隔。

描述

DATEDIFF函数返回两个指定日期之间指定日期部分差的整数。日期范围从开始日期开始,到结束日期结束。(如果enddate早于startdateDATEDIFF将返回一个负整数值。)

DATEDIFF返回startdateenddate之间指定单位的总数。例如,两个日期时间值之间的分钟数计算日期部分和时间部分,并为每一天的差异增加1440分钟。DATEDIFF返回开始日期和结束日期之间跨越的指定日期部分边界的计数。例如,指定连续年份的任意两个日期(例如2018-09-232019-01-01)返回的年份DATEDIFF为1,而不管这两个日期之间的实际持续时间是大于还是小于365天。同样,12:23:5912:24:05之间的分钟数是1,尽管实际上只有6秒将两个值分开。

请注意,DATEDIFF是为Sybase和Microsoft SQL Server兼容性而提供的。使用TIMESTAMPDIFF ODBC标量函数可以执行类似的时间/日期比较操作。

也可以使用DATEDIFF()方法调用从ObjectScript调用此函数:

$SYSTEM.SQL.Functions.DATEDIFF(datepart,startdate,enddate)

DATEDIFF()方法指定无效的datepartstartdateenddate会生成< ZDDIF >错误。

Datepart 参数

日期部分参数可以是下列日期/时间组件之一,可以是全名(日期部分列)或其缩写(缩写列)。这些datepart组件名称和缩写不区分大小写。

Date PartAbbreviations
yearyyyy, yy
monthmm, m
weekwk, ww
weekdaydw
daydd, d
dayofyeardy
hourhh
minutemi, n
secondss, s
millisecondms
microsecondmcs
nanosecondns

weekdaydayofyear datepart值在功能上与day datepart值相同。

DATEDIFFTIMESTAMPDIFF不处理季度(间隔3个月)。

如果指定包含分数秒的开始日期和结束日期,DATEDIFF将以分数秒的整数形式返回差值,如下例所示:

SELECT DATEDIFF('ms','64701,56670.10','64701,56670.27'),     /* returns 170 */
       DATEDIFF('ms','64701,56670.1111','64701,56670.27222') /* returns 161 */

datepart可以指定为带引号的字符串或不带引号的字符串。这些语法变体执行略有不同的操作:

  • Quotes: DATEDIFF('month','2018-02-25',$HOROLOG):在创建缓存查询时,datepart被视为文字。SQL执行文字替换。这将产生一个更容易重用的缓存查询。
  • 无引号: DATEDIFF(month,'2018-02-25',$HOROLOG):创建缓存查询时,datepart被视为关键字。没有文字替换。这将生成更具体的缓存查询。

日期表达式格式

startdateenddate参数可以采用不同的数据类型格式。

startdateenddate参数可以采用以下任何格式:

  • %Date逻辑值(+$H),也称为$HOROLOG格式。
  • %PosixTime(%Library.PosixTime。逻辑值(编码的64位有符号整数)
  • %TimeStamp(%Library.TimeStamp)逻辑值(YYYY-MM-DD HH:MM:SS。FFF),也称为ODBC格式。
  • %String(或兼容)值。

%String(或compatible)值可以是以下任何一种格式,可以包含或省略小数秒:

  • 99999、99999 ($HOROLOG格式)。 $HOROLOG特殊变量不返回小数秒。 但是,可以使用$HOROLOG格式指定一个包含分数秒的值:99999,99999.999

  • Sybase/SQL-Server-date Sybase/SQL-Server-time

  • Sybase/SQL-Server-time Sybase/SQL-Server-date

  • Sybase/SQL-Server-date (default time is 00:00:00)

  • Sybase/SQL-Server-time (default date is 01/01/1900)

Sybase/SQL-Server-date是以下五种格式之一:

mm/dd/[yy]yy dd Mmm[mm][,][yy]yy dd [yy]yy Mmm[mm] yyyy Mmm[mm] dd yyyy [dd] Mmm[mm]

在第一种语法格式中,分隔符可以是斜杠(/)、连字符(-)或句点(.)。

Sybase/SQL-Server-time表示以下三种格式之一:

HH:MM[:SS[:FFF]][{AM|PM}] HH:MM[:SS[.FFF]] HH['']{AM|PM}

Years

如果年份以两位数字表示,或者日期被完全省略, IRIS会检查滑动窗口来解释日期。 系统范围内滑动窗口的默认值是1900; 因此,在默认情况下,两位数的年份被认为是在20世纪。 如下示例所示:

SELECT DATEDIFF('year','10/11/14','02/22/2018'),
       DATEDIFF('year','12:00:00','2018-02-22 12:00:00')

分数秒

DATEDIFF返回以毫秒(3位整数)、微秒(6位整数)或纳秒(9位整数)表示的小数秒,而不管startdateenddate中的小数位数精度是多少。 如下示例所示:

SELECT DATEDIFF('ms','12:00:00.1','12:00:00.2'),
       DATEDIFF('ms','12:00:00.10009','12:00:00.20007')

一些NLS区域设置将分数分隔符指定为逗号(欧洲的用法),而不是句号。 如果当前区域设置是这些区域设置之一,DATEDIFF接受句号或逗号作为本地日期格式的秒分隔符。 对于$HOROLOG格式的日期或ODBC格式的日期,不能使用逗号作为小数秒分隔符。 尝试这样做会生成一个SQLCODE -8。 无论当前的NLS语言环境是什么,这两种格式都需要一段时间。

时间差异与时间格式无关

DATEDIFF返回以秒和毫秒为单位的时间差,即使当前进程的TimeFormat被设置为不返回秒。 如下示例所示:

ClassMethod DateDiff()
{
	s tfmt = ##class(%SYS.NLS.Format).GetFormatItem("TimeFormat")
	d ##class(%SYS.NLS.Format).SetFormatItem("TimeFormat",1)
	w "datetime values (with seconds) are: ",!,
	$ZDATETIME("64701,56670.10",1,-1),"  ",$ZDATETIME("64701,56673.27",1,-1),!
	&sql(SELECT DATEDIFF('ss','64701,56670.10','62871,56673.27') INTO :x)
	w "DATEDIFF number of seconds is: ",x,!!
	d ##class(%SYS.NLS.Format).SetFormatItem("TimeFormat",2)
	w "datetime values (without seconds) are: ",!,
	$ZDATETIME("64701,56670.10",1,-1),"  ",$ZDATETIME("64701,56673.27",1,-1),!
	&sql(SELECT DATEDIFF('ss','64701,56670.10','64701,56673.27') INTO :x)
	w "DATEDIFF number of seconds is: ",x,!
	d ##class(%SYS.NLS.Format).SetFormatItem("TimeFormat",tfmt)
}

DHC-APP>d ##class(PHA.TEST.SQLCommand).DateDiff()
datetime values (with seconds) are:
02/22/2018 15:44:30  02/22/2018 15:44:33
DATEDIFF number of seconds is: -158111996.83
 
datetime values (without seconds) are:
02/22/2018 15:44  02/22/2018 15:44
DATEDIFF number of seconds is: 3.17
 

范围和值检查

DATEDIFF对输入值执行以下检查:

  • 在执行任何DATEDIFF操作之前,开始日期和结束日期的所有指定部分必须是有效的。
  • 日期字符串必须完整,格式正确,包含适当数量的元素和每个元素的数字,以及适当的分隔符。 年必须指定为四位数字。 如果省略输入值的日期部分,DATEDIFF默认为' 1900-01-01 '。 无效的日期值将导致SQLCODE -8错误。
  • 日期和时间值必须在有效范围内。 年龄:00019999。 月份:1 - 12个月。 天数:1 - 31天。 营业时间:0023。 分钟:059分钟。 秒:0 ~ 59。 一个月中的天数必须与月和年相匹配。 例如,日期“02-29”仅在指定的年份为闰年时有效。 无效的日期值将导致SQLCODE -8错误。
  • 小于10(月和日)的日期值可以包括或省略前导零。 不允许使用其他非规范整数值。 因此,Day值为“07”“7”是有效的,但“007”“7.0”“7a”无效。
  • 时间值可以全部或部分省略。 如果startdateenddate指定了一个不完整的时间,则为未指定的部分提供0
  • 小于10的小时值必须包含前导零。 省略前导零将导致SQLCODE -8错误。

错误处理

  • Embedded SQL中,如果指定无效的datepart作为输入变量,则会发出SQLCODE -8错误码。 如果将无效的日期部分指定为文字,则会发生<SYNTAX>错误。 如果将无效的开始日期或结束日期指定为输入变量或文字,则会发出SQLCODE -8错误码。
  • 在动态SQL中,如果您提供了无效的日期部分、开始日期或结束日期,则DATEDIFF函数将返回一个NULL值。 没有发出SQLCODE错误。

示例

下面的例子返回353,因为两个时间戳之间有353天(D):

SELECT DATEDIFF(D,'2018-01-01 00:00:00','2018-12-20 12:00:00')

353

在下面的示例中,每个DATEDIFF返回1,因为日期的年份部分相差1。 日期之间的实际持续时间不被考虑:

SELECT DATEDIFF('yyyy','1910-08-21','1911-08-21') AS ExactYear,
       DATEDIFF('yyyy','1910-06-30','1911-01-01') AS HalfYear,
       DATEDIFF('yyyy','1910-01-01','1911-12-31') AS Nearly2Years,
       DATEDIFF('yyyy','1910-12-31 11:59:59','1911-01-01 00:00:00') AS NewYearSecond
       
       
1	1	1	1

注意,上面的例子使用了日期部分的缩写。 但是,你可以指定全名,如下例所示:

SELECT DATEDIFF('year','2017-09-10 13:19:00','2018-12-20 00:00:00')

1

下面的嵌入式SQL示例使用主机变量执行与前面示例相同的DATEDIFF操作:

ClassMethod DateDiff1()
{
	s x="year"
	s date1="2017-09-10 13:19:00"
	s date2="2018-12-20 00:00:00"
	&sql(SELECT DATEDIFF(:x,:date1,:date2)
		INTO :diff)
	w diff
}
1

下面的例子使用WHERE子句中的DATEDIFF来选择上周入院的患者:

SELECT Name,DateOfAdmission FROM Sample.Patients WHERE DATEDIFF(D,DateOfAdmission,$HOROLOG) <= 7

下面的例子使用了一个子查询来返回那些个人的出生日期距当前日期不超过1500天的记录:

SELECT Name,Age,DOB
FROM (SELECT Name,Age,DOB, DATEDIFF('dy',DOB,$HOROLOG) AS DaysTo FROM Sample.Person)
WHERE DaysTo <= 1500
ORDER BY Age
0
0 786
文章 姚 鑫 · 二月 2, 2022 6m read

第四十二章 SQL函数 DATEADD

一个日期/时间函数,它返回一个时间戳,计算方法是在一个日期或时间戳中添加或减去若干日期部件单位(如小时或天)。

大纲

DATEADD(datepart,integer-exp,date-exp)

参数

  • datepart - 日期或时间部分的名称(或缩写)。 可以用大写或小写指定该名称,也可以不加引号。 可以将datepart指定为文字或主机变量。
  • integer-exp - 任意数字类型的数字表达式。 该值被截断为整数(正或负)。 该值指示将添加到(或从)date-exp中减去的datepart单元的数量。
  • date-exp - 要修改的日期/时间表达式。它可以是日期字符串,也可以是时间戳字符串(%PosiTime%Timestamp数据类型),也可以是CURRENT_DATE之类的函数。返回的值始终是时间戳,数据类型格式为%PosiTime%Timestamp

描述

DATEADD函数通过将指定的日期部分递增指定的单元数来修改日期/时间表达式。 例如,如果datepart“month”且整数-exp5,则DATEADDdate-exp递增5个月。 还可以通过为integer-exp指定一个负整数来减少日期部分。

计算出的日期将作为完整的日期/时间表达式(时间戳)返回。返回的数据类型取决于Date-EXP的数据类型。如果Date-EXP%Library.PosiTime(编码的64位有符号整数),则DATEADD返回数据类型%Library.PosiTime。否则,DATEADD返回数据类型%Library.TimeStamp(yyyy-mm-dd hh:mm:ss.fff)

DATEADD始终返回有效日期,并考虑一个月的天数,并计算闰年。例如,将1月31日递增一个月将返回2月28日(该月中的最高有效日期),除非指定的年份是闰年,在这种情况下将返回2月29日。将闰年日期2月29日递增一年将返回2月28日。将闰年日期2月29日递增四年返回2月29日。

如果指定包含小数秒的date-exp,则返回值也包括小数秒。如果省略date-exp的时间部分,DATEADD将返回默认时间00:00:00。如果省略date-exp的日期部分,DATEADD将返回默认日期1900-01-01

DATEADDTIMESTAMPADD处理季度(3个月间隔);DATEDIFFTIMESTAMPDIFF不处理季度。

可以使用TIMESTAMPADD ODBC标量函数执行类似的时间/日期修改操作。

也可以使用DATEADD()方法调用从ObjectScript调用此函数:

$SYSTEM.SQL.Functions.DATEADD(datepart,integer-exp,date-exp)

Datepart Argument

日期部分参数可以是以下日期/时间组件之一:全名(日期部分列)或其缩写(缩写列)。这些日期部分组件名称和缩写不区分大小写。

Date PartAbbreviationsinteger-exp = 1
yearyyyy, yyIncrements year by 1.
quarterqq, qIncrements month by 3.
monthmm, mIncrements month by 1.
weekwk, wwIncrements day by 7.
weekdaydwIncrements day by 1.
daydd, dIncrements day by 1.
dayofyeardy, yIncrements day by 1.
hourhhIncrements hour by 1.
minutemi, nIncrements minute by 1.
secondss, sIncrements second by 1.
millisecondmsIncrements by .001 of a second.
microsecondmcs0–999999 (with precision of 6)
nanosecondns0–999999999 (with precision of 9)

递增或递减日期部分会导致适当修改其他日期部分。例如,午夜过后的小时递增会自动递增日期,这又可能会递增月份,依此类推。

日期部分可以指定为带引号的字符串或不带引号。这些语法变体执行的操作略有不同:

  • QUOTESDATEADD('month',12,$HOROLOG):在创建缓存查询时,日期部分被视为文字。 SQL执行文字替换。这会产生更普遍可重用的缓存查询。
  • 无引号:DATEADD(MONTH,12,$HOROLOG):在创建缓存查询时,日期部分被视为关键字。没有文字替换。这会产生更具体的缓存查询。

如果将无效的日期部分值指定为文字,则会发出SQLCODE-8错误代码。但是,如果提供无效的日期部件值作为主机变量,则不会发出SQLCODE错误,并且DATEPART函数返回值为NULL

日期表达式格式

Date-exp参数可以采用以下任何格式,并且可以包括或省略小数秒:

  • %Date logical value (+$H)

  • %PosiTime(%Library.PosiTime)逻辑值(编码的64位有符号整数)

  • (%Library.TimeStamp)逻辑值(YYYY-MM-DD HH:MM:SS)

  • %String(或兼容)值

%STRING(或COMPATIBLE)值可以采用以下任何格式:

  • 99999,99999 ($H format)

  • /SQL-Server-date Sybase/SQL-Server-time

  • Sybase/SQL-Server-time Sybase/SQL-Server-date

  • Sybase/SQL-Server-date (default time is 00:00:00)

  • Sybase/SQL-Server-time (default date is 01/01/1900)

Sybase/SQL-Server-Date是以下五种格式之一:

mmdelimiterdddelimiter[yy]yy dd Mmm[mm][,][yy]yy dd [yy]yy Mmm[mm] yyyy Mmm[mm] dd yyyy [dd] Mmm[mm]

其中,分隔符是斜杠(/)、连字符(-)或句点(.)。

Sybase/SQL-Server-Time表示以下三种格式之一:

HH:MM[:SS:SSS][{AM|PM}] HH:MM[:SS.S] HH['']{AM|PM}

请注意,提供DATEADD是为了与SybaseMicrosoft SQL Server兼容。

范围和值检查

DATEADD对输入值执行以下检查。如果值未通过检查,则返回空字符串。

  • 日期字符串必须完整且格式正确,包含适当数量的元素和每个元素的数字,以及适当的分隔符。年份必须指定为四位数。
  • 日期值必须在有效范围内。年份:00019999。月份:1到12天1到31。时间:0点到23点。分钟:0到59分钟。秒:0到59
  • 返回的递增的year值必须在00019999之间。 超出此范围将返回<null>
  • 一个月中的天数必须与月和年相匹配。 例如,日期“02-29”仅在指定的年份为闰年时有效。
  • 小于10的日期值可以包括或省略前导零。 不允许使用其他非规范整数值。 因此,Day值为“07”“7”是有效的,但“007”“7.0”“7a”无效。

下面的例子为指定的日期添加了1周:

SELECT DATEADD('week',1,'2018-02-26') AS NewDate

2018/3/5 0:00:00

它返回2018-03-05 00:00:00,因为增加1周会增加7天。 注意,DATEADD提供了省略的时间部分。

下面的例子为时间戳添加了5个月:

SELECT DATEADD(MM,5,'2017-11-26 12:00:00') AS NewDate

2018/4/26 12:00:00

它返回2018-04-26 12:00:00,因为增加5个月也会增加一年。

下面的例子也在时间戳上增加了5个月:

SELECT DATEADD('mm',5,'2018-01-31 12:00:00') AS NewDate

2018/6/30 12:00:00

它返回2018-06-30 12:00:00。 这里DATEADD修改了日值和月值,因为简单地增加月值将导致6月31日,这是一个无效的日期。

下面的例子为时间戳添加了45分钟:

SELECT DATEADD(MI,45,'2018-02-26 12:00:00') AS NewTime

2018/2/26 12:45:00

下面的示例还为时间戳添加了45分钟,但在本例中,添加的内容增加了日,从而增加了月:

SELECT DATEADD('mi',45,'2018-02-28 23:30:00') AS NewTime

2018/3/1 0:15:00

下面的例子将原始时间戳减去45分钟:

SELECT DATEADD(N,-45,'2018-01-01 00:10:00') AS NewTime

2017/12/31 23:25:00

下面的例子为当前日期添加了60天,并根据月份的不同长度进行调整:

SELECT DATEADD(D,60,CURRENT_DATE) AS NewDate

2022/4/4 0:00:00

在下面的例子中,第一个DATEADD为指定的日期添加了92天,第二个DATEADD为指定的日期添加了1 / 4天:

SELECT DATEADD('dd',92,'2018-12-20') AS NewDateD,
       DATEADD('qq',1,'2018-12-20') AS NewDateQ

image

第一季将于2019-03-22 00:00:00回归; 第二季将于2019-03-20 00:00:00回归。 每增加1 / 4,month字段就会增加3,如果需要,还会增加year字段。 它还校正给定月份的最大天数。

上面的例子都使用日期部分的缩写。 但是,也可以用它的全名来指定日期部分,就像下面的例子一样:

SELECT DATEADD('day',92,'2018-12-20') AS NewDate

2019/3/22 0:00:00

下面的嵌入式SQL示例使用主机变量来执行与前面示例相同的DATEADD操作:

ClassMethod DateAdd()
{
	s x="day"
	s datein="2019-12-20"
	&sql(SELECT DATEADD(:x,92,:datein)
	   INTO :dateout)
	w "in:  ",datein,!,"out: ",dateout
}
DHC-APP>d ##class(PHA.TEST.SQLCommand).DateAdd()
in:  2019-12-20
out: 2020-03-21 00:00:00
DHC-APP>
0
0 176