Имитировать перечисления в TSQL?

Недавно я случайно написал действительно уродливый хранимый фрагмент, где мне хотелось, чтобы у меня были перечисления,

Eg.

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

Я понимаю, что SQL 2000 не имеет перечислений как конструкцию языка первого класса, какие соглашения кодирования вы используете для имитации перечислений или иным образом адресуете ту же проблему?

Или я обречен просто использовать VARCHAR и IF @account_category = 'cat1'?

EDIT: T-SQL и С# являются языками клиента.

EDIT: Спасибо всем! Много хорошего совета, я бы хотел принять несколько ответов, я проголосовал за всех -

Сводка ответов

  • Lean on С# enum с помощью int. Хорошо для кода клиента С#, делает клиент TSQL код менее читабельный.
  • Используйте Char/Varchar. Плохо для кода клиента С# (не подходит для локализации), делает Код TSQL более читабельный.
  • Использовать код проверки параметров для ограничения параметр или использовать ограничение на столбец таблицы или внешний ключ, если параметр будет вставлен в таблицу.

Ответ 1

Вы можете взглянуть на ответ на этот вопрос. Насколько я знаю, типы перечислений не являются частью SQL Server.

Во всяком случае, лучше использовать для ваших перечислений интегральный тип (INT, TINYINT,...), чем тип строки. Обычно типы перечислений на вашем языке программирования лучше подходят для целых чисел, чем для строк.

В С# по умолчанию каждое значение enum соответствует целому числу, начиная с 0. Вы можете даже использовать между ними, поэтому это допустимый код:

public enum MyEnum
{
    FirstEnumValue,
    SecondEnumValue
}

...

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

И LINQtoSQL также поддерживает это. Если у вас есть свойство перечисления, и ваш столбец базы данных является целым типом, преобразование выполняется автоматически.

Ответ 2

В PostgreSql я просто использую VARCHAR с привязанными ограничениями...

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[]))

Мне не нравится использовать числовые типы для моделирования ENUM, потому что они недостаточно описательны. С приведенной выше схемой я сразу вижу, какие возможные значения получает, и сразу же понимаю смысл этих значений. Я также получаю безопасность типа, поскольку я не могу вставить недопустимые значения в этот столбец.

Подробнее о ограничениях для Postgres см. здесь: http://www.postgresql.org/docs/8.1/static/ddl-constraints.html

Ответ 3

Я обычно предпочитаю вызывать параметр @account_category_code и сделать его CHAR (3), если есть только несколько значений перечисления, и все они могут быть четко выражены тремя буквами. Затем домен вводится с контрольным ограничением. Если имеется более чем несколько значений (больше, чем около 4 или 5), я обычно переключался бы на tinyint/smallint с именем @account_category_type_id и имел бы таблицу доменов для ссылки на нее. У меня нет жесткого правила в моей организации, но я считаю, что это хорошо работает.

Ответ 5

Иногда тип CHAR более полезен, чем INT - фиксированный размер CHAR не занимает много места хранения, и вы можете видеть "перечисляемые" значения непосредственно в полях базы данных. Никакая разница с кодовой частью, но большой прогресс, работая непосредственно с инструментами SQL.

Ответ 6

Будьте особенно осторожны при использовании типа CHAR для перечисления и вообще избегайте его, если вы хотите, чтобы ваше приложение /db вышло на международном уровне.
Не путайте DATA с презентацией: как следует из слов, enum (eration) - это число, это описание - совершенно другое дело. Чтобы сделать его коротким, используя переменную/поле CHAR для перечисления, вы привязываете себя к определенному языку для описания: например, вы можете забыть о интернационализации. Можете ли вы представить себе, что означает слово "Weltmeisterschaft", на каком языке и, более того, сколько разных способов написания это неправильно? Фактически, (крошечный) int имеет фактически недостаток значений, не интуитивно авто-описательный: я не сказал, что это идеальное решение!

Ответ 7

В SQL вы перечисляете элементы, помещая их в таблицу. Создайте таблицу поиска для своих категорий учетных записей, и этот параметр принимает первичный ключ для новой таблицы.

Ответ 8

Самый простой способ сделать это в Transact-SQL - это ограничение CHECK. Вы можете прочитать об этом здесь или здесь. Это ограничение также доступно в PostgreSQL и Oracle.

Ответ 9

Вы можете использовать оператор CASE.

Чтобы создать пример enum-esque из набора результатов, вы можете сделать что-то вроде этого:

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

В основном вы запускаете целое число с помощью инструкции SWITCH. Поместите его в свою хранимую процедуру, чтобы вам не приходилось писать один и тот же код снова и снова. Надеюсь, это поможет. enter code here