SQL Server中的SYSNAME数据类型是什么?


131

SQL Server SYSNAME数据类型是什么?BOL说:

sysname数据类型用于存储对象名称的表列,变量和存储过程参数。

但我真的不明白。您可以提供一个用例吗?


1
除了下面的这些很好的答案之外,它还会对试图使用sys.types获取列元数据的人造成破坏,因为它与nvarchar共享相同的system_type_id。
StingyJack

Answers:


150

sysname是一种内置数据类型,仅限于128个Unicode字符,即IIRC,主要用于在创建脚本时存储对象名称。它的值不能是NULL

与使用基本相同 nvarchar(128) NOT NULL

编辑

就像@Jim在评论中提到的那样,我认为您真的不会有一个sysname诚实的商业案例。它主要由Microsoft sys在SQL Server中构建内部表和存储过程等时使用。

例如,通过执行,Exec sp_help 'sys.tables'您将看到name定义该列的原因是因为sysname此列的值实际上是其本身的对象(表)

我对此太担心了。

还值得注意的是,对于那些仍在使用SQL Server 6.5及更低版本的人(是否仍在使用它?),内置类型sysname的等效于varchar(30)

文献资料

sysname定义与文档nchar,并nvarchar在备注部分:

sysname 是系统提供的用户定义的数据类型,在功能上等效于nvarchar(128),但它不能为空。sysname用于引用数据库对象名称。

为了澄清以上说明,默认情况下 定义了sysname,因为NOT NULL可以将其定义为可为空。同样重要的是要注意,确切的定义在SQL Server实例之间可能有所不同。

使用特殊数据类型

数据类型为sysname数据类型用于表的列,变量和存储过程参数存储对象名称。sysname的确切定义 与标识符规则有关。因此,它在SQL Server实例之间可能会有所不同。sysname在功能上与nvarchar(128)相同,除了默认情况下sysname为NOT NULL。在早期版本的SQL Server中,sysname定义为varchar(30)。

有关sysname允许或不允许NULL值的一些其他信息,请参见https://stackoverflow.com/a/52290792/300863

仅仅因为它是默认值(不能为NULL)不能保证它会是默认值!


1
“您可以提供用例吗?” 我认为您不会找到使用的实际业务理由。通常,它在MS SQL内部使用,因为它可能在表中使用了很多,等等
Jim

9
您将sysname在脚本中使用前向(和向后)兼容性。
马丁·史密斯

只需在此处输入2美分即可:带我到这里的列nvarchar(max)在SP 中声明为非null,但sysname在sys表中显示为a 。
gloomy.penguin 2013年

3
@Barry实际上...根据sys.typesnvarchar(256) not null。请注意,系统类型ID = 231(nvarchar)。如今,它已用作TDS中的类型别名。别名的第一个ID为256,对应于sysname。至于用法:sysname用于信息模式。
atlaste 2014年

2
@atlaste sys.tables中的max_length长度以字节为单位。nvarchar每个字符使用两个字节,因此将其定义为nvarchar(128)。
David Rushton


6

就像是仅供参考。

select * from sys.types where system_type_id = 231 给你两行。

(我不确定这是什么意思,但我100%肯定它现在正在弄乱我的代码)

编辑:我想这意味着在这种情况下(我的情况),您应该由user_type_id加入,或者可能是user_type_id和esystem_type_id

name        system_type_id   user_type_id   schema_id   principal_id    max_length  precision   scale   collation_name                  is_nullable     is_user_defined     is_assembly_type    default_object_id   rule_object_id
nvarchar    231              231            4           NULL            8000        0           0       SQL_Latin1_General_CP1_CI_AS    1               0                   0                   0                   0
sysname     231              256            4           NULL            256         0           0       SQL_Latin1_General_CP1_CI_AS    0               0                   0                   0                   0

create procedure dbo.yyy_test (
    @col_one    nvarchar(max),
    @col_two    nvarchar(max)  = 'default',
    @col_three  nvarchar(1),
    @col_four   nvarchar(1)    = 'default',
    @col_five   nvarchar(128),
    @col_six    nvarchar(128)  = 'default',
    @col_seven  sysname  
)
as begin 

    select 1
end 

该查询:

select  parm.name AS Parameter,    
        parm.max_length, 
        parm.parameter_id 

from    sys.procedures sp

        join sys.parameters parm ON sp.object_id = parm.object_id 

where   sp.name = 'yyy_test'

order   by parm.parameter_id

产量:

parameter           max_length  parameter_id
@col_one            -1          1
@col_two            -1          2
@col_three           2          3
@col_four            2          4
@col_five            256        5
@col_six             256        6
@col_seven           256        7

还有这个:

select  parm.name as parameter,    
        parm.max_length, 
        parm.parameter_id,
        typ.name as data_type, 
        typ.system_type_id, 
        typ.user_type_id,
        typ.collation_name,
        typ.is_nullable 
from    sys.procedures sp

        join sys.parameters parm ON sp.object_id = parm.object_id

        join sys.types typ ON parm.system_type_id = typ.system_type_id

where   sp.name = 'yyy_test'

order   by parm.parameter_id

给你这个:

parameter   max_length  parameter_id    data_type   system_type_id  user_type_id    collation_name                  is_nullable
@col_one    -1          1               nvarchar    231             231             SQL_Latin1_General_CP1_CI_AS    1
@col_one    -1          1               sysname     231             256             SQL_Latin1_General_CP1_CI_AS    0
@col_two    -1          2               nvarchar    231             231             SQL_Latin1_General_CP1_CI_AS    1
@col_two    -1          2               sysname     231             256             SQL_Latin1_General_CP1_CI_AS    0
@col_three   2          3               nvarchar    231             231             SQL_Latin1_General_CP1_CI_AS    1
@col_three   2          3               sysname     231             256             SQL_Latin1_General_CP1_CI_AS    0
@col_four    2          4               nvarchar    231             231             SQL_Latin1_General_CP1_CI_AS    1
@col_four    2          4               sysname     231             256             SQL_Latin1_General_CP1_CI_AS    0
@col_five    256        5               nvarchar    231             231             SQL_Latin1_General_CP1_CI_AS    1
@col_five    256        5               sysname     231             256             SQL_Latin1_General_CP1_CI_AS    0
@col_six     256        6               nvarchar    231             231             SQL_Latin1_General_CP1_CI_AS    1
@col_six     256        6               sysname     231             256             SQL_Latin1_General_CP1_CI_AS    0
@col_seven   256        7               nvarchar    231             231             SQL_Latin1_General_CP1_CI_AS    1
@col_seven   256        7               sysname     231             256             SQL_Latin1_General_CP1_CI_AS    0

sys.types也包含您创建的用户定义类型。如果这样做,create type MyInt from int您将有两行system_type_id = 56。默认情况下重复的另一个是240,它是architectureid,geometry和geography的系统类型。
Mikael Eriksson

我完全忘记了。那么...用sysname查询那里的东西的理想方法是什么?因为这是“别名”,我能做where typ.name<>'sysname'还是会产生我不知道的其他后果?
gloomy.penguin 2013年

3
加入system_type_id和user_type_id上​​的sys.types。SQL小提琴
Mikael Eriksson

哦,这就是我最高层所说的。我以为你是在说错了……
gloomy.penguin 2013年

抱歉,不是我的意思。只是想指出其他一些可能使查询混乱的事情,不仅sysname可能会导致您感到悲痛,而无需同时参加这两个专栏。
Mikael Eriksson

3

让我在下面列出一个用例。希望能帮助到你。在这里,我试图从数据库“学生”中查找表“ Stud_dtls”的表所有者。正如Mikael所提到的,当需要创建一些动态sql时,可以使用sysname,该sql需要包含表名,列名和服务器名的变量。只是想提供一个简单的例子来补充他的观点。

USE Students

DECLARE @TABLE_NAME sysname

SELECT @TABLE_NAME = 'Stud_dtls'

SELECT TABLE_SCHEMA 
  FROM INFORMATION_SCHEMA.Tables
 WHERE TABLE_NAME = @TABLE_NAME

2

sysname由使用sp_send_dbmail,该存储过程位于msdb数据库中,该存储过程“向指定的收件人发送电子邮件”。

根据微软的说法,

[ @profile_name = ] 'profile_name'  

是从中发送消息的配置文件的名称。profile_name的类型为sysname,默认值为NULL。profile_name必须是现有数据库邮件配置文件的名称。如果未指定profile_name,则sp_send_dbmail使用当前用户的默认专用配置文件。如果用户没有默认的专用配置文件,则sp_send_dbmail使用msdb数据库的默认的公共配置文件。如果用户没有默认的私有配置文件,并且数据库没有默认的公共配置文件,则必须指定@profile_name。


1

FWIW,如果您希望以这种方式浏览数据库,则可以将表名传递给有用的系统SP,例如:

DECLARE @Table sysname; SET @Table = 'TableName';
EXEC sp_fkeys @Table;
EXEC sp_help @Table;

0

另一个用例是使用SQL Server 2016+功能时 AT TIME ZONE

以下语句将返回转换为格林尼治标准时间的日期

SELECT 
CONVERT(DATETIME, SWITCHOFFSET([ColumnA], DATEPART(TZOFFSET, [ColumnA] AT TIME ZONE 'GMT Standard Time')))

如果要将时区作为变量传递,请说:

SELECT 
CONVERT(DATETIME, SWITCHOFFSET([ColumnA], DATEPART(TZOFFSET, [ColumnA] AT TIME ZONE @TimeZone)))

那么该变量必须是类型sysnamevarchar将其声明为会导致错误)。


0

您可以提供用例吗?

您想要存储对象名称以供数据库维护脚本使用的任何位置。例如,脚本从具有日期列的某些表中清除旧行。它配置有一个表,该表提供表名,要过滤的列名以及要保留的历史天数。另一个脚本将某些表转储为CSV文件,并再次配置了一个表,该表列出了要转储的表。这些配置表可以使用该sysname类型来存储表名和列名。


您根本不需要。只需使用一nvarchar(128) not null列。名字就是那个名字。不必sysname使用它
Panagiotis Kanavos

当然,实际上它甚至不必一定是这种类型,nvarchar(300)即使varchar在表名中不使用Unicode时,它也可以工作(因为我敢肯定,几乎没有人这样做)。的优势sysname部分在于,它使意图更清晰:此列包含一个对象名称;并且部分原因是,即使您迁移到另一版本的MSSQL,该版本更改了用于对象名称的数据类型(如前所述),它仍将是正确的类型。
Ed Avis

不,不是。这只是映射到的另一种用户类型(本质上是别名)nvarchar(128) NOT NULL。实际上,这就是查找类型的方法-通过检查user_type_id列的值。通过使用该类型,您所获得的无非是创建自己的用户类型
Panagiotis Kanavos

您的意思是,如果sysname在较新的MSSQL版本中更改的定义,并且数据库已备份并还原到该较新的实例中,则以前所有的列sysname现在都将具有错误的类型,并且不再与使用的类型匹配在系统表中?
Ed Avis

如果发生这种情况,那是不可能的,甚至更糟的是,您的色谱柱已经被软管堵住了。sysname是具有usert_type_id256 的用户定义类型。没有,ALTER TYPE因此无法更改它。您必须创建一种新类型,并将所有使用旧类型的列更改为新类型。如果MS决定更改此设置,必须将现有的系统表数据迁移到新类型。您可以期望他们为他们已经知道的系统表执行此操作,但是任何用户表都必须由用户迁移
Panagiotis Kanavos
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.