2009-02-23 20 views
24

Tenemos dos columnas en una base de datos que actualmente es de tipo varchar (16). La cosa es que contiene números y siempre contendrá números. Por lo tanto, queremos cambiar su tipo a entero. Pero el problema es que, por supuesto, ya contiene datos.Cambiar el tipo de una columna con números de varchar a int

¿Hay alguna manera de que podamos cambiar el tipo de esa columna de varchar a int, y no perder todos los números que ya están allí? Esperemos que algún tipo de sql podamos simplemente ejecutar, sin tener que crear columnas temporales y crear un programa C# o algo para hacer la conversión, etc. ... Me imagino que podría ser bastante fácil si SQL Server tiene alguna función para convertir cadenas a números, pero soy muy inestable en SQL. Bastante solo funciona con C# y accede a la base de datos a través de LINQ to SQL.

Nota: Sí, hacer que la columna varchar en primer lugar no era una muy buena idea, pero lamentablemente es la forma en que lo hicieron.

Respuesta

30

La única manera confiable de hacer esto va a utilizar una tabla temporal, pero no va a ser mucho sql:

select * into #tmp from bad_table 
truncate table bad_table 
alter bad_table alter column silly_column int 
insert bad_table 
select cast(silly_column as int), other_columns 
from #tmp 
drop table #tmp 
+0

#tmp es un nombre aleatorio de una tabla tmp? – Svish

+1

Buena respuesta - Diría esto primero - selecciona el elenco (silly_column como int), other_columns de bad_table Para asegurarte de que no tienes ningún problema de conversión y todos son de hecho. – brendan

+3

De todos los nombres que inventé, ¿hizo un comentario sobre el #tmp? – cjk

8

Sólo cambia el tipo de datos en el estudio de gestión

(puede que tenga que ir a Herramientas> Opciones> Diseñadores, y deshabilitar la opción que evita guardar los cambios que vuelven a crear la tabla)

+0

costumbre de que pierda todos los valores a continuación ?? – Svish

+0

No. Pruébalo en una mesa de prueba si quieres? – ctrlalt3nd

+0

Acabo de hacer esto y funcionó perfectamente. Primero, verifiqué si todos los valores existentes eran números almacenados en tipo de cadena y si podía convertir con éxito todos los varchar a tipo numérico. Después de deshabilitar todas las referencias a la columna (Índices, claves, desencadenantes, ...) y seguí y apliqué el cambio en MSSMS. ¡Genial! – Rynkadink

1

Aprecio las respuestas anteriores, pero también pensé que una respuesta más completa sería útil para otros buscadores ...

Hay algunas advertencias que serían útiles si realiza los cambios en una tabla de tipo de producción.

  1. Si usted tiene una columna deidentidad definida en la tabla, tendrá que establecer IDENTITY_INSERT de forma interrumpida durante la re-inserción de los datos. También deberá usar una lista de columnas explícita.
  2. Si usted quiere estar seguro de no matar a los datos en la base de datos, utilice TRANSACTIONS todo el truncado/alterar/reinsertar proceso
  3. Si usted tiene una gran cantidad de datos, a continuación, tratando de hacer sólo el cambio en SQ Server Management Studio podría fallar con un tiempo de espera y podría perder datos.

Para ampliar la respuesta que dio @cjk, mira el siguiente:

Nota: 'tuc' es sólo un marcador de posición en esta secuencia de comandos para el nombre de tabla reales comienzan a tratar iniciar la transacción

print 'Selecting Data...' 
    select * into #tmp_tuc from tuc 

    print 'Truncating Table...' 
    truncate table tuc 

    alter table tuc alter column {someColumnName} {someDataType} [not null] 
    ... Repeat above until done 

    print 'Reinserting data...' 
    set identity_insert tuc on 
    insert tuc (
    <Explicit column list (all columns in table)> 
) 
    select 
    <Explicit column list (all columns in table - same order as above)> 
    from #tmp_tuc 
    set identity_insert tuc off 

    drop table #tmp_tuc 
    commit 
    print 'Successful!' 
end try 
begin catch 
    print 'Error - Rollback' 
    if @@trancount > 0 
    rollback 

    declare @ErrMsg nvarchar(4000), @ErrSeverity int 
    select @ErrMsg = ERROR_MESSAGE(), @ErrSeverity = ERROR_SEVERITY() 

    set identity_insert tuc off 

    RAISERROR(@ErrMsg, @ErrSeverity, 1) 
end catch 
18

La forma más sencilla de hacerlo es:

alter table myTable alter column vColumn int; 

esto funcionará como lon g como

  1. todos los datos caben dentro de un int
  2. todos los datos se puede convertir a int (es decir, un valor de "automóvil" fallará)
  3. no hay índices que incluyan vColumn.Si hay índices, deberá incluir un drop y crear para que vuelvan a donde estaban.
+2

@svish: Realmente quería que fuera "coche" no 'carbón'. – jmoreno

+0

¡Oh! Lo siento. Comprenda lo que quería decir con eso ahora, jeje :) – Svish

+0

esto funcionó. Estaba fallando al intentar a través del estudio de administración – PowerMan2015

Cuestiones relacionadas