2009-09-05 21 views
39

ho creato alcuni tipi definiti dall'utente nel DB, come di seguitoAlter utente tipo definito in SQL Server

CREATE TYPE [dbo].[StringID] FROM [nvarchar](20) NOT NULL 

e assegnato a varie tabelle. Le mie tabelle in db sono in vari schemi (non solo DBO)

Ma mi sono reso conto che ho bisogno di campo più grande, e ho bisogno di modificare, ad esempio, aumento da nvarchar a nvarchar, ma non c'è nessun tipo ALTER

I ho bisogno di uno script che temp table/cursor qualunque e di salvare lì tutte le tabelle e i campi in cui viene utilizzato il mio tipo. Quindi modifica i campi esistenti nel tipo di base, ad es. da CustID [StringID] a CustID [nvarchar (20)]. Elimina il tipo di utente e ricrearlo con un nuovo tipo, ad es. nvarchar (50) e, infine, arretrato campi al tipo di utente

io non avere regole definiscono il tipo, quindi non c'è bisogno di eliminare le regole e ri-aggiungerli

Io non sono molto familiare con T-Sql, quindi ogni aiuto è apprezzato.

risposta

26

Questo è quello che uso normalmente, anche se un po 'manuale:

/* Add a 'temporary' UDDT with the new definition */ 
exec sp_addtype t_myudt_tmp, 'numeric(18,5)', NULL 


/* Build a command to alter all the existing columns - cut and 
** paste the output, then run it */ 
select 'alter table dbo.' + TABLE_NAME + 
     ' alter column ' + COLUMN_NAME + ' t_myudt_tmp' 
from INFORMATION_SCHEMA.COLUMNS 
where DOMAIN_NAME = 't_myudt' 

/* Remove the old UDDT */ 
exec sp_droptype t_mydut 


/* Rename the 'temporary' UDDT to the correct name */ 
exec sp_rename 't_myudt_tmp', 't_myudt', 'USERDATATYPE' 
+0

Questo è un buon inizio. Ho aggiunto TABLE_SCHEMA in select poiché le mie tabelle non sono tutte in schema dbo, ma in vari altri schemi. Ora ho bisogno di capire come selezionare un cursore o una tabella temporanea, quindi eseguire un'istruzione creata una stringa. Grazie per l'aiuto – bzamfir

+2

Questa è probabilmente l'unica strada percorribile, poiché sfortunatamente, SQL Server non ha un comando "ALTER TYPE" (perché no?) –

+9

Puoi votare per il comando "ALTER TYPE" su https: // connect .microsoft.com/SQLServer/feedback/dettagli/319134/msft-mso-support-alter-type –

5

there's a good example of a more comprehensive script here

Vale la pena notare che questo script includerà vista se ne avete. L'ho eseguito e invece di eseguire exec in linea generato uno script come l'output che ho poi ottimizzato e gestito.

Inoltre, se si dispone di funzioni/sproc utilizzando i tipi di defeined dell'utente, è necessario eliminarli prima di eseguire lo script.

Lesson Learned: in futuro, non preoccuparti degli UDT, sono più fastidi di quanto valgano.

SET NOCOUNT ON 

DECLARE @udt VARCHAR(150) 
DECLARE @udtschema VARCHAR(150) 
DECLARE @newudtschema VARCHAR(150) 
DECLARE @newudtDataType VARCHAR(150) 
DECLARE @newudtDataSize smallint 
DECLARE @OtherParameter VARCHAR(50) 

SET @udt = 'Name' -- Existing UDDT 
SET @udtschema = 'dbo' -- Schema of the UDDT 
SET @newudtDataType = 'varchar' -- Data type for te new UDDT 
SET @newudtDataSize = 500 -- Lenght of the new UDDT 
SET @newudtschema = 'dbo' -- Schema of the new UDDT 
SET @OtherParameter = ' NULL' -- Other parameters like NULL , NOT NULL 
DECLARE @Datatype VARCHAR(50), 
    @Datasize SMALLINT 

DECLARE @varcharDataType VARCHAR(50) 

DECLARE @Schemaname VARCHAR(50), 
    @TableName VARCHAR(50), 
    @FiledName VARCHAR(50) 

CREATE TABLE #udtflds 
    (
     Schemaname VARCHAR(50), 
     TableName VARCHAR(50), 
     FiledName VARCHAR(50) 
    ) 

SELECT TOP 1 
     @Datatype = Data_type, 
     @Datasize = character_maximum_length 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE Domain_name = @udt 
     AND Domain_schema = @udtschema 

SET @varcharDataType = @Datatype 
IF @DataType Like '%char%' 
    AND @Datasize IS NOT NULL 
    AND (@newudtDataType <> 'varchar(max)' 
      OR @newudtDataType <> 'nvarchar(max)' 
     ) 
    BEGIN 
     SET @varcharDataType = @varcharDataType + '(' 
      + CAST(@Datasize AS VARCHAR(50)) + ')' 
    END 

INSERT INTO #udtflds 
     SELECT TABLE_SCHEMA, 
       TABLE_NAME, 
       Column_Name 
     FROM INFORMATION_SCHEMA.COLUMNS 
     WHERE Domain_name = @udt 
       AND Domain_schema = @udtschema 

DECLARE @exec VARCHAR(500) 

DECLARE alter_cursor CURSOR 
    FOR SELECT Schemaname, 
       TableName, 
       FiledName 
     FROM #udtflds 

OPEN alter_cursor 
FETCH NEXT FROM alter_cursor INTO @Schemaname, @TableName, @FiledName 

WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SET @exec = 'Alter Table ' + @Schemaname + '.' + @TableName 
      + ' ALTER COLUMN ' + @FiledName + ' ' + @varcharDataType 
     EXECUTE (@exec 
       ) 
     FETCH NEXT FROM alter_cursor INTO @Schemaname, @TableName, @FiledName 

    END 

CLOSE alter_cursor 

SET @exec = 'DROP TYPE [' + @udtschema + '].[' + @udt + ']' 
EXEC (@exec 
    ) 

SET @varcharDataType = @newudtDataType 

IF @newudtDataType Like '%char%' 
    AND @newudtDataSize IS NOT NULL 
    AND (@newudtDataType <> 'varchar(max)' 
      OR @newudtDataType <> 'nvarchar(max)' 
     ) 
    BEGIN 
     SET @varcharDataType = @varcharDataType + '(' 
      + CAST(@newudtDataSize AS VARCHAR(50)) + ')' 
    END 

SET @exec = 'CREATE TYPE [' + @newudtschema + '].[' + @udt + '] FROM ' 
    + @varcharDataType + ' ' + @OtherParameter 
EXEC (@exec 
    ) 

OPEN alter_cursor 
FETCH NEXT FROM alter_cursor INTO @Schemaname, @TableName, @FiledName 

WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SET @exec = 'Alter Table ' + @Schemaname + '.' + @TableName 
      + ' ALTER COLUMN ' + @FiledName + ' ' + '[' + @newudtschema 
      + '].[' + @udt + ']' 
     EXECUTE (@exec 
       ) 
     FETCH NEXT FROM alter_cursor INTO @Schemaname, @TableName, @FiledName 
    END 

CLOSE alter_cursor 
DEALLOCATE alter_cursor 
SELECT * 
FROM #udtflds 

DROP TABLE #udtflds 

1: http://www.sql-server-performance.com/2008/how-to-alter-a-uddt/ ha sostituito http://www.sql-server-performance.com/faq/How_to_alter_a%20_UDDT_p1.aspx

+0

Grande sceneggiatura! L'ho appena usato per modificare il tipo di dati sottostante del mio UDT dbo.percentage, da decimale (9, 2) a decimale (9, 4). – bloparod

+0

il link è ora rotto – Rory

+1

Ho aggiornato il collegamento interrotto nella risposta di @ Robin all'indirizzo corrente per quella risposta. –

3

Le soluzioni qui fornite possono essere applicate solo se tipi definiti dall'utente sono utilizzati solo in definizioni di tabella, e se le colonne UDT non sono indicizzati.

Alcuni sviluppatori hanno anche SP e funzioni utilizzando i parametri UDT, che non sono coperti neanche. (Vedi commenti su Robin's link e nel Connect entry)

Il collegamento di entrata a partire dal 2007 è stato finalmente chiuso dopo 3 anni:

Grazie per aver inviato questo suggerimento, ma data la sua priorità relativa ai molti altri articoli in la nostra coda, è improbabile che lo completeremo effettivamente. Come tale, siamo chiudendo questo suggerimento come "non risolverà ".

ho cercato di risolvere un problema simile ALTERing XML SCHEMA COLLECTIONS, ei passi sembrano da applicare soprattutto per ALTER TYPE, troppo:

Per eliminare un tipo definito dall'utente, i seguenti passaggi sono necessari:

  • Se una colonna della tabella fa riferimento all'UDT, deve essere convertita al tipo sottostante
  • Se la colonna della tabella presenta un vincolo predefinito, eliminare il vincolo predefinito
  • Se una procedura o la funzione ha parametri UDT, la procedura o la funzione deve essere interrotta
  • Se c'è un indice su una colonna UDT, l'indice deve essere eliminato
  • Se l'indice è una chiave primaria, tutte le chiavi esterne devono essere caduto
  • Se non ci sono calcolate le colonne in base a una colonna UDT, le colonne calcolate devono essere caduto
  • Se non vi sono indici su queste colonne calcolate, gli indici devono essere sceso
  • Se ci sono schema-bound viste, funzioni o procedure basate su tabelle contenenti colonne UDT, questi oggetti devono essere eliminati
-3

Semplice DROP TYPE prima quindi CREATE TYPE ancora con correzioni/modifiche?

C'è un semplice test per vedere se è stato definito prima di rilasciarlo ... proprio come un tavolo, un proc o una funzione - se non fossi al lavoro, guarderei cosa è?

(I scremato solo al di sopra anche ... se ho letto male mi scuso in anticipo;)

+16

Non è possibile rilasciare il tipo se è in uso. –

4

Come devio dice che non c'è modo di modificare semplicemente un UDT se è in uso.

Un SMS di lavoro che ha funzionato per me è stato quello di generare uno script di creazione e apportare le modifiche appropriate; rinominare l'UDT esistente; eseguire lo script di creazione; ricompilare i relativi sproc e rilasciare la versione rinominata.

+0

Come si rinomina l'UDT esistente? – Muflix

5

Stiamo usando la seguente procedura, ci consente di ricreare un tipo da zero, che è "un inizio". Rinomina il tipo esistente, crea il tipo, ricompila i processi memorizzati e quindi elimina il vecchio tipo. Questo si prende cura degli scenari in cui semplicemente cadere la vecchia definizione del tipo fallisce a causa di riferimenti a quel tipo.

Utilizzo Esempio:

exec RECREATE_TYPE @schema='dbo', @typ_nme='typ_foo', @sql='AS TABLE([bar] varchar(10) NOT NULL)' 

Codice:

CREATE PROCEDURE [dbo].[RECREATE_TYPE] 
    @schema  VARCHAR(100),  -- the schema name for the existing type 
    @typ_nme VARCHAR(128),  -- the type-name (without schema name) 
    @sql  VARCHAR(MAX)  -- the SQL to create a type WITHOUT the "CREATE TYPE schema.typename" part 
AS DECLARE 
    @scid  BIGINT, 
    @typ_id  BIGINT, 
    @temp_nme VARCHAR(1000), 
    @msg  VARCHAR(200) 
BEGIN 
    -- find the existing type by schema and name 
    SELECT @scid = [SCHEMA_ID] FROM sys.schemas WHERE UPPER(name) = UPPER(@schema); 
    IF (@scid IS NULL) BEGIN 
     SET @msg = 'Schema ''' + @schema + ''' not found.'; 
     RAISERROR (@msg, 1, 0); 
    END; 
    SELECT @typ_id = system_type_id FROM sys.types WHERE UPPER(name) = UPPER(@typ_nme); 
    SET @temp_nme = @typ_nme + '_rcrt'; -- temporary name for the existing type 

    -- if the type-to-be-recreated actually exists, then rename it (give it a temporary name) 
    -- if it doesn't exist, then that's OK, too. 
    IF (@typ_id IS NOT NULL) BEGIN 
     exec sp_rename @[email protected]_nme, @newname= @temp_nme, @objtype='USERDATATYPE' 
    END;  

    -- now create the new type 
    SET @sql = 'CREATE TYPE ' + @schema + '.' + @typ_nme + ' ' + @sql; 
    exec sp_sqlexec @sql; 

    -- if we are RE-creating a type (as opposed to just creating a brand-spanking-new type)... 
    IF (@typ_id IS NOT NULL) BEGIN 
     exec recompile_prog; -- then recompile all stored procs (that may have used the type) 
     exec sp_droptype @[email protected]_nme; -- and drop the temporary type which is now no longer referenced 
    END;  
END 

GO 


CREATE PROCEDURE [dbo].[recompile_prog] 
AS 
BEGIN 
    SET NOCOUNT ON; 
    DECLARE @v TABLE (RecID INT IDENTITY(1,1), spname sysname) 
    -- retrieve the list of stored procedures 
    INSERT INTO 
     @v(spname) 
    SELECT 
     '[' + s.[name] + '].[' + items.name + ']'  
    FROM 
     (SELECT sp.name, sp.schema_id, sp.is_ms_shipped FROM sys.procedures sp UNION SELECT so.name, so.SCHEMA_ID, so.is_ms_shipped FROM sys.objects so WHERE so.type_desc LIKE '%FUNCTION%') items 
     INNER JOIN sys.schemas s ON s.schema_id = items.schema_id  
     WHERE is_ms_shipped = 0; 

    -- counter variables 
    DECLARE @cnt INT, @Tot INT; 
    SELECT @cnt = 1; 
    SELECT @Tot = COUNT(*) FROM @v; 
    DECLARE @spname sysname 
    -- start the loop 
    WHILE @Cnt <= @Tot BEGIN  
     SELECT @spname = spname   
     FROM @v   
     WHERE RecID = @Cnt; 
     --PRINT 'refreshing...' + @spname  
     BEGIN TRY  -- refresh the stored procedure   
      EXEC sp_refreshsqlmodule @spname  
     END TRY  
     BEGIN CATCH   
      PRINT 'Validation failed for : ' + @spname + ', Error:' + ERROR_MESSAGE(); 
     END CATCH  
     SET @Cnt = @cnt + 1; 
    END; 

END 
+0

Grazie per questo sprocs mi ha risparmiato un sacco di tempo – pateketu

0

Il modo più semplice per farlo è attraverso l'esploratore oggetto di Visual Studio, che è anche supportato nell'edizione Comunità.

Una volta ottenuto il server made a connection, passare al tipo, fare clic con il tasto destro e selezionare Visualizza codice, apportare le modifiche allo schema del tipo definito dall'utente e fare clic su Aggiorna. Visual Studio dovrebbe mostrare tutte le dipendenze per quell'oggetto e generare script per aggiornare il tipo e ricompilare le dipendenze.

0

1. Denominare il vecchio UDT,
2.Esegui query, 3. Elimina il vecchio UDT.

0

Nuova risposta ad una vecchia domanda:

Visual Studio Progetti di database gestire il calo e il processo di ricreare quando si distribuisce le modifiche. Rilascerà i proc memorizzati che utilizzano gli UDDT e quindi li ricrea dopo aver rilasciato e ricreato il tipo di dati.

+0

Non so perché il downvote. Se questa non è una risposta legittima, fammi sapere perché. – mcfea

Problemi correlati