2009-06-08 18 views
11

Hace poco escribí accidentalmente un programa almacenado realmente feo en el que deseaba tener enums,¿Simular enumeraciones en TSQL?

Por ejemplo.

CREATE PROCEDURE Proc_search_with_enum @user int, @account_category {enum} 

entiendo que SQL 2000 no tiene enumeraciones como primera construcción del lenguaje de clase, que convenciones de codificación que utiliza para simular las enumeraciones o de cualquier modo abordar el mismo tema?

¿O estoy destinado a usar VARCHAR e IF @ account_category = 'cat1'?

EDITAR: T-SQL y C# son los idiomas del cliente.

EDITAR: ¡Gracias a todos! Un montón de buenos consejos, me gustaría poder aceptar varias respuestas, he votado en todo el mundo UP

Resumen de las respuestas

  • Lean on enumeración C# 's utilizando int. Bueno para el código de cliente C#, hace que el cliente TSQL código sea menos legible.
  • Usar Char/Varchar. Malo para el código de cliente de C# (no es bueno para la localización), hace que código TSQL sea más legible.
  • parámetro Use código de comprobación para restringir el parámetro, o utilizar una restricción en una columna de tabla o una clave externa si va a ser insertado en una tabla el parámetro.
+0

Eche un vistazo a esta pregunta: http://stackoverflow.com/questions/681828/sqlserver-how-to-bind-fixed-values-to-column/681847 – LukeH

Respuesta

10

Puede echar un vistazo a la respuesta al this question. Hasta donde yo sé, los tipos enum no son parte de SQL Server.

De todos modos, es mejor utilizar un tipo integral (INT, TINYINT, ...) para sus enumeraciones que un tipo de cadena. Por lo general, los tipos de enumeración en su lenguaje de programación de elección se corresponden mejor con enteros que con cadenas.

En C#, por defecto cada valor de enumeración corresponde a un número entero, empezando por 0. Incluso puede emitir entre ellos, por lo que este es un código válido:

public enum MyEnum 
{ 
    FirstEnumValue, 
    SecondEnumValue 
} 

... 

// Assuming you have opened a SqlDataReader. 
MyEnum enumValue = (MyEnum) reader["account_category"]; 

Y LinqToSql también es compatible con esto. Si tiene una propiedad tipada enum y su columna de base de datos es un tipo entero, la conversión es automática.

+3

Si opta por esta técnica, entonces es probable que una buena idea para especificar explícitamente los valores subyacentes de la enumeración para garantizar que las actualizaciones futuras no rompan accidentalmente la correlación entre su código C# y los valores de la base de datos. Por ejemplo: public enum MyEnum {FirstEnumValue = 1, SecondEnumValue = 2} etc – LukeH

+0

De acuerdo, normalmente tomo los valores predeterminados y agrego nuevos valores al final, pero hacerlo explícito es probablemente una buena idea. –

2

en PostgreSQL sólo tiene que utilizar VARCHAR con limitaciones adjuntos ...

CREATE TABLE movie_clip (  
    type VARCHAR(40) NULL CHECK(type IN ('trailer', 'commercial')), 
); 

#=> insert into movie_clip (type) values ('trailer'); 
INSERT 0 1 
#=> insert into movie_clip (type) values ('invalid value'); 
ERROR: new row for relation "movie_clip" violates check constraint "movie_clip_type_check" 

#=> \d movie_clip 
.... 
"movie_clip_type_check" CHECK (type::text = ANY (ARRAY['trailer'::character varying, 'commercial'::character varying]::text[])) 

no me gusta el uso de tipos numéricos para la simulación de ENUM, porque no son lo suficientemente descriptivo. Con el esquema anterior, puedo ver de inmediato qué valores posibles recibe, y también entiendo el significado de esos valores de inmediato. También obtengo seguridad de tipo, ya que no puedo insertar valores inválidos en esa columna.

Para más detalles sobre las restricciones para Postgres, ver aquí: http://www.postgresql.org/docs/8.1/static/ddl-constraints.html

+0

PostGreSQL tiene soporte enum http://www.postgresql.org/docs/9.3/static/datatype-enum.html. Para verlos en PgAdmin, debes activarlos en tus preferencias. –

1

tipo CHAR A veces es más útil que la INT - tamaño fijo carbón no toma mucho espacio de almacenamiento y se puede ver los valores "enumeradas" directamente en campos de base de datos. No hay diferencia desde el lado del código, pero es un gran avance al trabajar directamente con herramientas SQL.

2

Por lo general, prefiero llamar al parámetro @account_category_code y convertirlo en CHAR (3), si solo hay unos pocos valores de enum y todos se pueden expresar limpiamente con tres letras. Entonces el dominio se aplica con una restricción de verificación. Si hay más de un puñado de valores (más de 4 o 5), generalmente cambiaría a tinyint/smallint llamado @account_category_type_id y tendré una tabla de dominio para hacer referencia a él. No tenemos una regla dura y rápida en mi organización, pero creo que esto funciona bien.

1

Tenga mucho cuidado al usar el tipo CHAR para enum, y evítelo en absoluto si desea que su aplicación/db vaya internacionalmente.
No confunda los DATOS con su presentación: como las palabras deben sugerir, una enumeración es un número, su descripción es un negocio totalmente diferente. Para abreviar, usando una variable CHAR/campo para una enumeración, te vinculas a un idioma particular para su descripción: puedes olvidarte de la internazionalización, por ejemplo. ¿Puedes imaginarte lo que significa la palabra "Weltmeisterschaft", en qué idioma y, además, cuántas formas diferentes de escribir mal puede haber? En realidad, una (pequeña) int tiene la desventaja de los valores no intrínsecamente autodescriptivos: ¡No dije que sea la solución perfecta!

+2

En mi humilde opinión el "código" (account_category_code) de una enumeración nunca debe ser localizado. Esto sería análogo a localizar el código fuente de la aplicación que definía una enum C#/C++. En su lugar, debe tener account_category_type_desc (según nuestra nomenclatura) que es la descripción enum humana mostrada, esto es lo que usted localizaría. – ahains

+0

1) No permitirá que su usuario final juegue con su código fuente (pero puede definir fácilmente diferentes traducciones para la enumeración) 2) Si deja que el usuario final use códigos, tendrá problemas: pueden no conoce su idioma o, incluso si lo saben, puede deliberadamente no querer usarlo: tenga en cuenta que si tienen acceso a la base de datos pueden insertar valores manualmente.3) Si usa códigos en lugar de descripción, las cosas son aún peores: lo que es "WMS" es tan oscuro como un int, ya que tiene que adivinar qué idioma en la tierra (literalmente) es, y qué significa esto. –

+0

4) Se corre el riesgo de que personas (o archivos externos, tengan en cuenta también fuentes externas fuera de su control) insertando valores ilegales: esto podría evitarse fácilmente, con una buena validación de datos antes de insertar en la tabla o usar en el proc/función. Estoy de acuerdo en que no es una solución perfecta, pero en mi experiencia (18 años) cuando trabajé con personas de diferentes culturas e idiomas, el uso de las teclas CHAR para tablas y enumeraciones puede esconder tantos pequeños problemas en los que nunca antes había pensado. Sin embargo, ese es mi consejo, y no creo que nunca vuelva a su oficina para refaccionar su código/dbs :) –

1

En SQL, enumera elementos poniéndolos en una tabla. Cree una tabla de búsqueda para las categorías de su cuenta y haga que este parámetro acepte la clave principal para la nueva tabla.

2

Puede crear una vista para simular el Enum. Vea este artículo http://www.olegsych.com/2008/07/t4-template-for-generating-sql-view-from-csharp-enumeration/

+0

Este enlace se ha ido. Las respuestas deben incluir la información pertinente de un enlace y del enlace en sí mismo – Aphillippe

+0

. Todavía puede encontrar esa página aquí: https://web.archive.org/web/20160728054915/http://www.olegsych.com:80/ 2008/07/t4-template-for-generate-sql-view-from-csharp-enumeration / – Justin

0

La manera más fácil de hacer esto en Transact-SQL es con una restricción CHECK. Puede leer más al respecto here o here. Esta restricción también está disponible en PostgreSQL y Oracle.

0

Puede usar CASE statement.

Para crear un ejemplo de enumeración al estilo de un conjunto de resultados, se podría hacer algo como esto:

SELECT 
    FirstName, 
    LastName, 
    CASE JobTitle WHEN 0 THEN 'Software Developer' WHEN 1 THEN 'Software Architect' WHEN 2 THEN 'President' ELSE 'Staff' END AS 'Job Title', 
    Salary 
FROM 
    Employees 

Es, básicamente, ejecutar un número entero a través de algo así como una sentencia switch. Colóquelo en su procedimiento almacenado para que no tenga que escribir el mismo código una y otra vez. Espero que esto ayude. enter code here