SYSNAME ชนิดข้อมูลใดใน SQL Server


131

SQL Server SYSNAME เป็นชนิดข้อมูลอะไร BOLพูดว่า:

ชนิดข้อมูล sysname ใช้สำหรับคอลัมน์ตารางตัวแปรและพารามิเตอร์ขั้นตอนการจัดเก็บที่เก็บชื่อวัตถุ

แต่ฉันไม่เข้าใจจริงๆ มีกรณีการใช้งานที่คุณสามารถให้ได้หรือไม่?


1
นอกจากคำตอบที่ดีเหล่านี้ด้านล่างแล้วยังใช้เพื่อทำให้เกิดความเสียหายสำหรับผู้ที่พยายามรับข้อมูลเมตาของคอลัมน์โดยใช้ sys.types เนื่องจากมีการแชร์ system_type_id เดียวกันกับ nvarchar
StingyJack

คำตอบ:


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ไม่ใช่ NULL ใน SQL Server เวอร์ชันก่อนหน้าsysnameถูกกำหนดเป็น varchar (30)

ข้อมูลเพิ่มเติมเกี่ยวกับการsysnameอนุญาตหรือไม่อนุญาตNULLสามารถดูได้ที่นี่https://stackoverflow.com/a/52290792/300863

เพียงเพราะมันเป็นค่าเริ่มต้น (เป็นไม่เป็นโมฆะ) ไม่รับประกันว่ามันจะเป็น!


1
"มีกรณีใช้งานที่คุณสามารถให้ได้หรือไม่" ฉันไม่คิดว่าคุณจะพบเหตุผลทางธุรกิจที่ใช้งานได้จริง ส่วนใหญ่จะถูกใช้ภายในใน MS SQL เป็นมันอาจจะใช้ไม่น้อยในตาราง ฯลฯ
จิม

9
คุณจะใช้sysnameสำหรับความเข้ากันได้ (และถอยหลัง) ในสคริปต์ของคุณ
Martin Smith

เพียงแค่ใส่ 2 เซ็นต์ที่นี่: คอลัมน์ที่นำฉันมาที่นี่จะประกาศว่าnvarchar(max)ไม่เป็นโมฆะใน SP แต่พวกเขากำลังแสดงเป็นsysnameในตาราง sys
gloomy.penguin

3
@Barry จริง ... ตามที่มันเป็นsys.types nvarchar(256) not nullโปรดทราบว่าระบบประเภท ID = 231 (nvarchar) มันทำงานเป็นนามแฝงประเภทใน TDS ทุกวันนี้; รหัสแรกของนามแฝงเป็น 256 sysnameซึ่งสอดคล้องกับ สำหรับการใช้งาน: sysnameใช้ในสคีมาข้อมูล
atlaste

2
@atlaste ความยาว max_length ใน sys.tables เป็นไบต์ nvarchar ใช้สองไบต์ต่อตัวอักษรซึ่งเป็นเหตุผลที่กำหนดให้เป็น nvarchar (128)
David Rushton

60

มีกรณีการใช้งานที่คุณสามารถให้ได้หรือไม่?

หากคุณมีความต้องการในการสร้างsql แบบไดนามิกมันเหมาะที่จะใช้sysnameเป็นชนิดข้อมูลสำหรับตัวแปรที่เก็บชื่อตารางชื่อคอลัมน์และชื่อเซิร์ฟเวอร์


6

เช่นเดียวกับ FYI ....

select * from sys.types where system_type_id = 231 ให้สองแถว

(ฉันไม่แน่ใจว่าสิ่งนี้หมายความว่ายัง แต่ฉัน 100% แน่ใจว่ามันสับสนรหัสของฉันตอนนี้)

แก้ไข:ฉันเดาว่ามันหมายความว่าคุณควรเข้าร่วมโดย user_type_id ในสถานการณ์นี้ (สถานการณ์ของฉัน) หรืออาจเป็นทั้ง user_type_id และ th 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 ซึ่งเป็นประเภทของระบบสำหรับลำดับชั้นid, เรขาคณิตและภูมิศาสตร์
Mikael Eriksson

ฉันลืมเรื่องนั้นไปโดยสิ้นเชิง ดังนั้น ... อะไรคือวิธีที่ดีที่สุดในการค้นหาสิ่งนี้ด้วย sysname ในนั้น เนื่องจากมันเป็น 'นามแฝง' ฉันสามารถทำได้where typ.name<>'sysname'หรือจะมีผลลัพธ์แบบอื่นที่ฉันไม่รู้?
gloomy.penguin

3
เข้าร่วมกับ sys.types ทั้ง system_type_id และ user_type_id SQL Fiddle
Mikael Eriksson

โอ้นั่นคือสิ่งที่ฉันพูดที่ด้านบนสุด ฉันคิดว่าคุณกำลังพูดว่ามันผิด ...
gloomy.penguin

ขออภัยเกี่ยวกับสิ่งนั้นไม่ใช่ความหมายของฉัน แค่ต้องการชี้ให้เห็นสิ่งอื่น ๆ ที่อาจทำให้ข้อความค้นหาของคุณยุ่งเหยิงไม่เพียง แต่ sysname อาจทำให้คุณเศร้าโศกโดยไม่ต้องเข้าร่วมทั้งสองคอลัมน์
Mikael Eriksson

3

ให้ฉันแสดงรายการกรณีการใช้งานด้านล่าง หวังว่ามันจะช่วย ที่นี่ฉันพยายามค้นหาเจ้าของโต๊ะของตาราง 'Stud_dtls' จากฐานข้อมูล 'นักเรียน' ดังที่ Mikael ได้กล่าวไว้ 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

คำสั่งด้านล่างจะกลับวันที่แปลงเป็น GMT

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)))

ดังนั้นตัวแปรนั้นจำเป็นต้องเป็นประเภทsysname(การประกาศว่าvarcharจะทำให้เกิดข้อผิดพลาด)


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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.