Co to jest typ danych SYSNAME w programie SQL Server?

135

Do czego służy typ danych SYSNAME programu SQL Server? BOL mówi:

Typ danych sysname jest używany dla kolumn tabeli, zmiennych i parametrów procedur składowanych, które przechowują nazwy obiektów.

ale tak naprawdę tego nie rozumiem. Czy możesz podać przykład użycia?

jrara
źródło
1
Oprócz tych dobrych odpowiedzi poniżej, jest również używany do powodowania spustoszenia u kogoś, kto próbuje pobrać metadane kolumny za pomocą sys.types, ponieważ ma ten sam system_type_id co nvarchar.
StingyJack

Odpowiedzi:

151

sysnameto wbudowany typ danych ograniczony do 128 znaków Unicode, który, IIRC, jest używany głównie do przechowywania nazw obiektów podczas tworzenia skryptów. Jego wartość nie może byćNULL

Zasadniczo jest to to samo, co używanie nvarchar(128) NOT NULL

EDYTOWAĆ

Jak wspomniał @Jim w komentarzach, nie sądzę, aby istniał przypadek biznesowy, w którym chciałbyś sysnamebyć szczery. Jest używany głównie przez firmę Microsoft podczas tworzenia wewnętrznych systabel i procedur składowanych itp. W programie SQL Server.

Na przykład, wykonując polecenie Exec sp_help 'sys.tables', zobaczysz, że kolumna namejest zdefiniowana w sysnameten sposób, ponieważ wartość this jest w rzeczywistości obiektem samym w sobie (tabelą)

Za bardzo bym się tym martwił.

Warto również zauważyć, że dla tych osób, które nadal używają SQL Server 6.5 i niższych (czy nadal są ludzie używający?), Typ wbudowany sysnamejest odpowiednikiemvarchar(30)

Dokumentacja

sysnamejest zdefiniowany w dokumentacji dla ncharinvarchar , w sekcji uwag:

sysname jest typem danych zdefiniowanym przez użytkownika, który jest funkcjonalnie równoważny z nvarchar (128) , z tą różnicą, że nie dopuszcza wartości null. sysname służy do odwoływania się do nazw obiektów bazy danych.

Aby wyjaśnić powyższe uwagi, domyślnie zdefiniowano nazwę sysname, ponieważ z NOT NULLpewnością można zdefiniować ją jako dopuszczającą wartość null. Należy również zauważyć, że dokładna definicja może się różnić w zależności od wystąpienia programu SQL Server.

Korzystanie ze specjalnych typów danych

Sysname typ danych jest używany dla kolumn tabeli, zmienne i parametry przechowywane procedury, która przechowywanie nazw obiektów. Dokładna definicja sysname jest związana z regułami dotyczącymi identyfikatorów. Dlatego może się różnić między wystąpieniami programu SQL Server. sysname jest funkcjonalnie takie samo jak nvarchar (128), z tym wyjątkiem, że domyślnie sysname NIE ma wartości NULL. We wcześniejszych wersjach SQL Server nazwa sys jest definiowana jako varchar (30).

Dodatkowe informacje na temat sysnamedopuszczania lub blokowania NULLwartości można znaleźć tutaj https://stackoverflow.com/a/52290792/300863

Tylko dlatego, że jest to wartość domyślna (NIE NULL), nie gwarantuje, że tak będzie!

codingbadger
źródło
1
„Czy jest jakiś przypadek użycia, który możesz podać?” Myślę, że nie znajdziesz praktycznego biznesowego powodu do korzystania. Przeważnie jest używany wewnętrznie w MS SQL, ponieważ jest prawdopodobnie używany dość często w tabelach itp.
Jim
11
Należałoby użyć sysnamedo przodu (i do tyłu) zgodności w skryptach.
Martin Smith
po prostu wstawiam tutaj 2 centy: kolumny, które mnie tu przyniosły, są zadeklarowane jako nvarchar(max)niezerowe w SP, ale są wyświetlane jako a sysnamew tabelach sys.
ponury pingwin
3
@Barry Właściwie ... zgodnie z sys.typestym nvarchar(256) not null. Zwróć uwagę, że identyfikator typu systemu = 231 (nvarchar). Obecnie działa jako alias typu w TDS; pierwszy identyfikator aliasu to 256, co odpowiada sysname. Co do użycia: sysnamejest używany w schematach informacyjnych.
atlaste
2
@atlaste Długość max_length w sys.tables jest w bajtach. nvarchar używa dwóch bajtów na znak, dlatego jest zdefiniowany jako nvarchar (128).
David Rushton
62

Czy możesz podać przypadek użycia?

Jeśli kiedykolwiek zajdzie potrzeba utworzenia jakiegoś dynamicznego sql , należy użyć go sysnamejako typu danych dla zmiennych przechowujących nazwy tabel, nazw kolumn i nazw serwerów.

Mikael Eriksson
źródło
8

Tak jak FYI ....

select * from sys.types where system_type_id = 231 daje dwa rzędy.

(Nie jestem jeszcze pewien, co to oznacza, ale jestem w 100% pewien, że teraz psuje mój kod)

edit: domyślam się, że oznacza to, że w tej sytuacji powinieneś dołączyć za pomocą user_type_id (moja sytuacja) lub prawdopodobnie zarówno user_type_id, jak i system_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 

To zapytanie:

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

Plony:

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

I to:

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

Daje ci to:

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
ponury.pingwin
źródło
sys.typeszawiera również utworzone przez użytkownika typy . Jeśli to zrobisz create type MyInt from int, będziesz mieć dwa rzędy z system_type_id = 56. Innym, który jest domyślnie zduplikowany, jest 240, czyli typ systemu dla hierarchii, geometrii i geografii.
Mikael Eriksson
Zupełnie o tym zapomniałem. Więc ... jaki jest idealny sposób wyszukiwania tych rzeczy z nazwą sysname w tym miejscu? skoro jest to „alias”, czy mogę po prostu zrobić, where typ.name<>'sysname'czy miałoby to jakieś inne konsekwencje, o których nie wiem?
ponury pingwin
3
Dołącz do sys.types zarówno na system_type_id, jak i user_type_id. SQL Fiddle
Mikael Eriksson
och, to właśnie powiedziałem na samej górze. Myślałem, że mówisz źle ...
ponury.pingwin
Przepraszam za to, nie o to chodzi. Chciałem tylko wskazać kilka innych rzeczy, które mogą zepsuć twoje zapytanie, nie tylko nazwa sysname może spowodować żal bez łączenia się w obu kolumnach.
Mikael Eriksson
3

Poniżej wymienię przypadek użycia. Mam nadzieję, że to pomoże. Tutaj próbuję znaleźć właściciela tabeli „Stud_dtls” z DB „Students”. Jak wspomniał Mikael, nazwa sysname może być używana, gdy istnieje potrzeba stworzenia jakiegoś dynamicznego sql, który wymaga zmiennych przechowujących nazwy tabel, nazw kolumn i nazw serwerów. Pomyślałem o podaniu prostego przykładu, który uzupełni jego punkt widzenia.

USE Students

DECLARE @TABLE_NAME sysname

SELECT @TABLE_NAME = 'Stud_dtls'

SELECT TABLE_SCHEMA 
  FROM INFORMATION_SCHEMA.Tables
 WHERE TABLE_NAME = @TABLE_NAME
dobra
źródło
2

sysnamejest używany przez sp_send_dbmailprocedurę składowaną, która „Wysyła wiadomość e-mail do określonych odbiorców” i znajduje się w bazie danych msdb.

Według Microsoftu ,

[ @profile_name = ] 'profile_name'  

To nazwa profilu, z którego chcesz wysłać wiadomość. Nazwa_profilu jest typu nazwa_systemu, z domyślną wartością NULL. Nazwa_profilu musi być nazwą istniejącego profilu poczty bazy danych. Jeśli nazwa_profilu nie jest określona, ​​sp_send_dbmail używa domyślnego profilu prywatnego dla bieżącego użytkownika. Jeśli użytkownik nie ma domyślnego profilu prywatnego, sp_send_dbmail używa domyślnego profilu publicznego dla bazy danych msdb. Jeśli użytkownik nie ma domyślnego profilu prywatnego i nie ma domyślnego profilu publicznego dla bazy danych, należy określić @profile_name.

przydatne
źródło
1

FWIW, możesz przekazać nazwę tabeli do przydatnych SP systemowych w ten sposób, jeśli chcesz eksplorować bazę danych w ten sposób:

DECLARE @Table sysname; SET @Table = 'TableName';
EXEC sp_fkeys @Table;
EXEC sp_help @Table;
AjV Jsy
źródło
0

Innym przypadkiem użycia jest korzystanie z funkcji programu SQL Server 2016+ AT TIME ZONE

Poniższa instrukcja zwróci datę przekonwertowaną na GMT

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

Jeśli chcesz przekazać strefę czasową jako zmienną, powiedz:

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

wtedy ta zmienna musi być tego typu sysname(zadeklarowanie jej jako varcharspowoduje błąd).

d219
źródło
0

Czy możesz podać przypadek użycia?

Wszędzie tam, gdzie chcesz przechowywać nazwę obiektu do użytku przez skrypty konserwacji bazy danych. Na przykład skrypt usuwa stare wiersze z niektórych tabel, które mają kolumnę daty. Jest skonfigurowany z tabelą, która zawiera nazwę tabeli, nazwę kolumny do filtrowania i liczbę dni historii do zachowania. Inny skrypt zrzuca określone tabele do plików CSV i ponownie jest skonfigurowany z tabelą zawierającą tabele do zrzucenia. Te tabele konfiguracji mogą używać sysnametypu do przechowywania nazw tabel i kolumn.

Ed Avis
źródło
W ogóle tego nie potrzebujesz. Po prostu użyj nvarchar(128) not nullkolumny. To tylko nazwa, imię. Nie trzeba sysnamego używać
Panagiotis Kanavos
Jasne, i faktycznie nie musi to być nawet tego typu, nvarchar(300)działałoby też lub nawet varchargdybyś nie używał Unicode w nazwach tabel (jestem pewien, że prawie nikt tego nie robi). Zaletą programu sysnamejest częściowo to, że wyjaśnia intencję: ta kolumna zawiera nazwę obiektu; a częściowo, że nawet jeśli dokonasz migracji do innej wersji MSSQL, która zmienia typ danych używany w nazwach obiektów (jak to miało miejsce wcześniej), nadal będzie to właściwy typ.
Ed Avis
Nie, nie ma. To po prostu inny typ użytkownika (zasadniczo alias), na który jest mapowany nvarchar(128) NOT NULL. W rzeczywistości w ten sposób można znaleźć typ - sprawdzając wartość user_type_idkolumny. Zyskasz nic więcej przy użyciu tego typu, niż byłoby, tworząc swój własny typ użytkownika
Panagiotis Kanavos
Czy masz na myśli, że jeśli definicja sysnamezostała zmieniona w nowszej wersji MSSQL, a baza danych została zarchiwizowana i przywrócona do nowszej instancji, wszystkie kolumny, które wcześniej były, sysnamebyłyby teraz niewłaściwego typu i nie pasowałyby już do używanego typu w tabelach systemowych?
Ed Avis
Nie może, albo co gorsza, jeśli to się kiedykolwiek zdarzy, twoja kolumna jest wężem. sysnamejest typem zdefiniowanym przez użytkownika z usert_type_id256. Nie ma, ALTER TYPEwięc nie ma sposobu, aby go zmienić. Musiałbyś utworzyć nowy typ i zmienić wszystkie kolumny, które używały starego typu, na nowe. Gdyby firma MS kiedykolwiek zdecydowała się to zmienić , musiałaby przenieść istniejące dane tabeli systemowej do nowego typu. Możesz oczekiwać, że zrobią to dla tabel systemowych, o których już wiedzą, ale wszelkie tabele użytkowników musiałyby zostać zmigrowane przez użytkowników
Panagiotis Kanavos