Condividi tramite


Regole di confronto dei database indipendenti

Si applica a:SQL ServerIstanza gestita di SQL di Azure

Varie proprietà incidono sull'ordinamento e sulla semantica di uguaglianza dei dati testuali, ad esempio distinzione maiuscole/minuscole, distinzione caratteri accentati/non accentati e linguaggio di base utilizzato. Queste qualità vengono espresse in SQL Server tramite la scelta di regole di confronto per i dati. Per una discussione più approfondita sulle collazioni stesse, vedere Collazione e supporto Unicode.

Le regole di confronto si applicano non solo ai dati archiviati nelle tabelle utente, ma a tutto il testo gestito da SQL Server, inclusi metadati, oggetti temporanei, nomi di variabili e così via. La gestione di tali elementi risulta diversa nei database indipendenti rispetto a quelli non indipendenti. Questa modifica non influisce su molti utenti, ma consente di garantire l'indipendenza e l'uniformità dell'istanza. Ma ciò potrebbe anche causare confusione e problemi per le sessioni che accedono sia ai database indipendenti che ai database non indipendenti.

Il comportamento della collation dei database contenuti è leggermente diverso dal comportamento nei database non contenuti. Questo comportamento è generalmente utile, in quanto consente l'indipendenza dell'istanza e favorisce la semplicità. Alcuni utenti potrebbero avere problemi, in particolare quando una sessione accede a database indipendenti e non indipendenti.

Questo articolo illustra il contenuto della modifica ed esamina le aree in cui la modifica potrebbe causare problemi.

Nota

Per database SQL di Azure, le regole di confronto per i database indipendenti sono diverse. Le regole di confronto del database e le regole di confronto del catalogo possono essere impostate durante la creazione del database e non possono essere aggiornate. Specificare un set di regole di confronto per i dati (COLLATE) e un set di regole di confronto del catalogo per i metadati di sistema e gli identificatori di oggetto (CATALOG_COLLATION). Per altre informazioni, vedere CREATE DATABASE.

Database non indipendenti

Tutti i database hanno regole di confronto predefinite che possono essere impostate durante la creazione o la modifica di un database. Queste regole di confronto vengono usate per tutti i metadati nel database e per impostazione predefinita per tutte le colonne stringa all'interno del database. Gli utenti possono scegliere regole di confronto diverse per qualsiasi colonna specifica tramite la clausola COLLATE.

Esempio 1

Se si lavora ad esempio a Pechino, è possibile che venga utilizzata una regola di confronto cinese:

ALTER DATABASE MyDB
    COLLATE Chinese_Simplified_Pinyin_100_CI_AS;

Ora, se si crea una colonna, le regole di confronto predefinite sono queste regole di confronto cinesi, ma è possibile sceglierne un'altra se si vuole:

CREATE TABLE MyTable
(
    mycolumn1 NVARCHAR,
    mycolumn2 NVARCHAR COLLATE Frisian_100_CS_AS
);
GO

SELECT name, collation_name
FROM sys.columns
WHERE name LIKE 'mycolumn%';
GO

Il set di risultati è il seguente.

name            collation_name
--------------- ----------------------------------
mycolumn1       Chinese_Simplified_Pinyin_100_CI_AS
mycolumn2       Frisian_100_CS_AS

Questo approccio sembra relativamente semplice, ma insorgono vari problemi. Poiché le regole di confronto per una colonna dipendono dal database in cui viene creata la tabella, si verificano problemi con l'uso di tabelle temporanee archiviate in tempdb. Le regole di confronto di tempdb di solito corrispondono alle regole di confronto per l'istanza, che non deve necessariamente corrispondere alle regole di confronto del database.

Esempio 2

Si consideri ad esempio il database (cinese) illustrato in precedenza, se usato in un'istanza con regole Latin1_General di confronto:

CREATE TABLE T1 (T1_txt NVARCHAR (MAX));
GO

CREATE TABLE #T2 (T2_txt NVARCHAR (MAX));
GO

A prima vista, queste due tabelle hanno lo stesso schema, ma poiché le regole di confronto dei database differiscono, i valori sono incompatibili:

SELECT T1_txt, T2_txt
FROM T1
     INNER JOIN #T2
         ON T1.T1_txt = #T2.T2_txt;

Il set di risultati è il seguente.

Messaggio 468, livello 16, stato 9, riga 2

Impossibile risolvere il conflitto delle regole di confronto tra "Latin1_General_100_CI_AS_KS_WS_SC" e "Chinese_Simplified_Pinyin_100_CI_AS" nell'operazione di uguaglianza.

Per correggere questo problema è necessario confrontare esplicitamente la tabella temporanea. SQL Server semplifica questa operazione fornendo la DATABASE_DEFAULT parola chiave per la COLLATE clausola .

CREATE TABLE T1 (T1_txt NVARCHAR (MAX));
GO

CREATE TABLE #T2 (T2_txt NVARCHAR (MAX) COLLATE DATABASE_DEFAULT);
GO

SELECT T1_txt, T2_txt
FROM T1
     INNER JOIN #T2
         ON T1.T1_txt = #T2.T2_txt;

Questa query viene ora eseguita senza errori.

Il comportamento dipendente dalle regole di confronto è rilevabile anche con le variabili. Si consideri la funzione seguente:

CREATE FUNCTION f (@x INT)
RETURNS INT
AS
BEGIN
    DECLARE @I AS INT = 1;
    DECLARE @İ AS INT = 2;
    RETURN @x * @i;
END

Si tratta di una funzione piuttosto particolare. In una collazione sensibile al maiuscolo/minuscolo, la clausola di ritorno @i non può essere associata né a @I né a . Nelle regole di confronto Latin1_General senza distinzione tra maiuscole e minuscole, @i viene associato a @I e la funzione restituisce 1. Tuttavia, nelle regole di confronto Turkish senza distinzione tra maiuscole e minuscole, @i viene associato a e la funzione restituisce 2. Questa funzione può causare seri problemi in un database che passa da un'istanza all'altra con regole di confronto diverse.

Database contenuti

Poiché uno degli obiettivi di progettazione dei database indipendenti è di renderli autosufficienti, è necessario eliminare la dipendenza dalle regole di confronto di istanza e tempdb. A questo scopo, nei database indipendenti viene introdotto il concetto di regole di confronto del catalogo. Tali regole vengono utilizzate per metadati di sistema e oggetti temporanei. I dettagli vengono forniti nel modo seguente.

In un database contenuto le regole di confronto del catalogo sono Latin1_General_100_CI_AS_WS_KS_SC. Queste regole di confronto sono le stesse per tutti i database indipendenti in tutte le istanze di SQL Server e non possono essere modificate.

Le regole di confronto del database vengono mantenute, ma utilizzate solo come regole di confronto predefinite per i dati utente. Per impostazione predefinita, le regole di confronto del database sono uguali a quelle di model, ma possono essere modificate dall'utente tramite un comando CREATE o ALTER DATABASE come con i database non indipendenti.

Nella clausola CATALOG_DEFAULT è disponibile la nuova parola chiave COLLATE, che viene utilizzata come collegamento alle regole di confronto correnti per i metadati nei database indipendenti e non indipendenti. Ovvero, in un database non contenuto, CATALOG_DEFAULT restituisce le regole di confronto del database correnti, poiché i metadati vengono collocati secondo le regole di confronto del database. In un database indipendente, questi due valori potrebbero essere diversi, poiché l'utente può modificare le regole di confronto del database in modo che non corrisponda alle regole di confronto del catalogo.

Nella tabella seguente viene riepilogato il comportamento di vari oggetti sia nei database non indipendenti che in quelli indipendenti:

Articolo Database non indipendente Database contenuto
Dati utente (impostazione predefinita) DATABASE_DEFAULT DATABASE_DEFAULT
Dati temporanei (impostazione predefinita) tempdb collazione DATABASE_DEFAULT
Metadati UFX DATABASE_DEFAULT / CATALOG_DEFAULT CATALOG_DEFAULT
Metadati temporanei tempdb collazione CATALOG_DEFAULT
Variabili Collazione dell'istanza CATALOG_DEFAULT
Etichette Goto Collazione dell'istanza CATALOG_DEFAULT
Nomi di cursore Collazione dell'istanza CATALOG_DEFAULT

Nella tabella temporanea dell'esempio precedentemente descritto, è possibile osservare che questo comportamento delle regole di confronto elimina l'esigenza di una clausola COLLATE esplicita nella maggior parte degli usi della tabelle temporanee. In un database indipendente questo codice ora viene eseguito senza errori, anche se le regole di confronto di database e istanza sono diverse:

CREATE TABLE T1 (T1_txt NVARCHAR (MAX));
GO

CREATE TABLE #T2 (T2_txt NVARCHAR (MAX));
GO

SELECT T1_txt, T2_txt
FROM T1
     INNER JOIN #T2
         ON T1.T1_txt = #T2.T2_txt;

Questa query funziona perché sia T1_txt che T2_txt sono allineati con la regola di confronto del database contenuto.

Intersezione tra contesti contenuti e non contenuti

Finché una sessione in un database indipendente rimane indipendente, dovrà rimanere all'interno del database al quale è connessa. In questo caso, il comportamento è semplice. Se, tuttavia, avviene il passaggio di una sessione tra contesti indipendenti e non indipendenti, il comportamento diventa più complesso, poiché è necessario creare un collegamento tra i due set di regole. Ciò può verificarsi in un database parzialmente indipendente, perché un utente potrebbe USE accedere a un altro database. In questo caso, la differenza nelle regole di confronto viene gestita in base al principio seguente.

  • Il comportamento delle regole di confronto per un batch viene determinato dal database in cui inizia il batch.

Questa decisione si prende prima dell'emissione di qualsiasi comando, incluso un comando iniziale USE. Cioè, se un batch inizia in un database contenuto, ma il primo comando è USE verso un database non contenuto, il comportamento di confronto del database contenuto viene comunque utilizzato per il batch. Dato questo scenario, un riferimento a una variabile, ad esempio, potrebbe avere più risultati possibili:

  • Il riferimento potrebbe individuare esattamente una corrispondenza. In questo caso, il riferimento funziona senza errori.

  • Il riferimento potrebbe non trovare una corrispondenza nelle regole di confronto correnti in cui ne esiste una precedente. Viene generato un errore che indica che la variabile non esiste, anche se apparentemente è stata creata.

  • Il riferimento potrebbe trovare più corrispondenze originariamente distinte. Anche questo genera un errore.

Questo argomento viene illustrato con alcuni esempi. Per questi, si presuppone che sia presente un database parzialmente indipendente denominato MyCDB con le regole di confronto del database impostate sulle regole di confronto predefinite, Latin1_General_100_CI_AS_WS_KS_SC. Si presuppone che il collation dell'istanza sia Latin1_General_100_CS_AS_WS_KS_SC. la sola differenza tra le due regole di confronto riguarda la distinzione tra maiuscole e minuscole.

Esempio 1

Nell'esempio seguente viene illustrato il caso in cui il riferimento trova esattamente una corrispondenza.

USE MyCDB;
GO

CREATE TABLE #a (x INT);

INSERT INTO #a VALUES (1);
GO

USE master;
GO

SELECT * FROM #a;
GO

Results:

Il set di risultati è il seguente.

x
-----------
1

In questo caso, il risultato #a identificato viene associato sia nelle regole di confronto del catalogo senza distinzione tra maiuscole e minuscole che nelle regole di confronto di istanza con distinzione tra maiuscole e minuscole e il codice funziona correttamente.

Esempio 2

Nell'esempio seguente viene illustrato il caso in cui il riferimento non trova una corrispondenza nelle regole di confronto correnti in cui ne esiste una precedente.

USE MyCDB;
GO

CREATE TABLE #a (x INT);

INSERT INTO #A VALUES (1);
GO

In questo caso #A viene associato ad #a nelle regole di confronto predefinite senza distinzione tra maiuscole e minuscole e l'inserimento funziona.

Il set di risultati è il seguente.

(1 row(s) affected)

Se tuttavia si continua lo script...

USE master;
GO

SELECT * FROM #A;
GO

il tentativo di associazione ad #A nelle regole di confronto di istanza con distinzione tra maiuscole e minuscole restituisce un errore:

Il set di risultati è il seguente.

Msg 208, Level 16, State 0, Line 2
Invalid object name '#A'.

Esempio 3

Nell'esempio seguente viene illustrato il caso in cui il riferimento trova più corrispondenze originariamente distinte. Si inizierà innanzitutto in tempdb (per cui sono valide le stesse regole di confronto con distinzione tra maiuscole e minuscole dell'istanza) e verranno eseguite le istruzioni seguenti.

USE tempdb;
GO

CREATE TABLE #a (x INT);
GO

CREATE TABLE #A (x INT);
GO

INSERT INTO #a VALUES (1);
GO

INSERT INTO #A VALUES (2);
GO

Questa query ha esito positivo, poiché le tabelle sono distinte in queste regole di confronto:

Il set di risultati è il seguente.

(1 row(s) affected)
(1 row(s) affected)

Se si passa al database indipendente, si noterà tuttavia che l'associazione a queste tabelle non è più possibile.

USE MyCDB;
GO

SELECT * FROM #a;
GO

Il set di risultati è il seguente.

Msg 12800, Level 16, State 1, Line 2
The reference to temp table name #a is ambiguous and cannot be resolved. Possible candidates are #a and #A.