【问题标题】:Simulate enums in TSQL?在 SQL 中模拟枚举?
【发布时间】:2009-06-08 11:28:59
【问题描述】:

我最近不小心写了一个非常丑陋的存储过程,我希望我有枚举,

例如。

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

我了解 SQL 2000 没有枚举作为一流的语言结构,您使用哪些编码约定来模拟枚举或以其他方式解决相同的问题?

或者我注定只使用 VARCHAR 和 IF @account_category='cat1'?

编辑:T-SQL 和 C# 是客户端语言。

编辑:谢谢大家!很多好的建议,我希望我能接受几个答案,我已经投票给每个人了-

答案总结

  • 使用 int 依赖于 C# 的枚举。好的 对于 C# 客户端代码,制作 TSQL 客户端 代码可读性较差。
  • 使用 Char/Varchar。不适合 C# 客户端代码 (不利于本地化),使得 TSQL 代码更具可读性。
  • 使用参数检查代码限制 参数,或使用约束 如果是表列或外键 该参数将被插入 放入表格中。

【问题讨论】:

标签: sql-server tsql


【解决方案1】:

您可以查看this question 的答案。据我所知,枚举类型不是 SQL Server 的一部分。

无论如何,最好为枚举使用整数 (INT, TINYINT, ...) 类型而不是字符串类型。通常,您选择的编程语言中的枚举类型对应于整数而不是字符串。

在 C# 中,默认情况下,每个枚举值都对应一个整数,从 0 开始。您甚至可以在它们之间进行转换,因此这是有效的代码:

public enum MyEnum
{
    FirstEnumValue = 0,
    SecondEnumValue = 1
}

...

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

而且 LINQtoSQL 也支持这一点。如果你有一个枚举类型的属性并且你的数据库列是一个整数类型,那么转换是自动的。

【讨论】:

  • 如果您使用这种技术,那么明确指定枚举的基础值可能是个好主意,以确保任何未来的更新都不会意外破坏您的 C# 代码和数据库值之间的相关性.例如:公共枚举 MyEnum { FirstEnumValue = 1, SecondEnumValue = 2 } 等
  • 同意,我通常采用默认值并在最后添加新值,但明确表示可能是个好主意。
【解决方案2】:

有时 CHAR 类型比 INT 更有用 - 固定大小的 char 不会占用太多存储空间,您可以直接在数据库字段中看到“枚举”值。代码方面没有区别,但直接使用 SQL 工具时进步很大。

【讨论】:

    【解决方案3】:

    您可以使用CASE statement

    要从结果集中创建枚举式示例,您可以执行以下操作:

    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

    【讨论】:

      【解决方案4】:

      在 PostgreSql 中,我只使用带有约束的 VARCHARs ...

      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

      【讨论】:

      【解决方案5】:

      我通常更喜欢调用参数@account_category_code 并将其设为CHAR(3),如果枚举值只有几个并且它们都可以用三个字母清晰地表达。然后使用检查约束强制执行域。如果有多个值(超过 4 或 5 个),那么我通常会切换到一个名为 @account_category_type_id 的 tinyint/smallint,并有一个域表可供参考。我们的组织没有硬性规定,但我觉得这很有效。

      【讨论】:

        【解决方案6】:

        在对枚举使用 CHAR 类型时要格外小心,如果您希望您的应用程序/数据库走向国际,请完全避免使用它。
        不要将 DATA 与它的表示混淆:就像单词应该暗示的那样,枚举(迭代)是一个数字,它的描述是完全不同的业务。简而言之,使用 CHAR 变量/字段作为枚举,您将自己与特定语言联系起来进行描述:例如,您可以忘记国际化。你能想象“Weltmeisterschaft”这个词是什么意思吗?用哪种语言——此外——有多少种不同的写法? 实际上,(tiny)int 实际上具有非内部自动描述的值的缺点:我没有说它是完美的解决方案!

        【讨论】:

        • 恕我直言,枚举的“代码”(account_category_code)永远不应本地化。这类似于本地化定义 c#/c++ 枚举的应用程序源代码。相反,您应该拥有 account_category_type_desc(按照我们的命名法),即人工显示的枚举描述,这就是您要本地化的内容。
        • 1) 你不会让你的最终用户使用你的源代码(但你可以很容易地为枚举定义不同的翻译) 2) 如果你让你的最终用户使用代码,你就是遇到麻烦:他们可能不知道您的语言,或者即使他们知道,也可能故意不使用它:请记住,如果他们可以访问数据库,他们可以手动插入值。 3)如果你使用代码而不是描述,事情就更糟糕了:什么是“WMS”就像一个 int 一样晦涩难懂,因为你必须猜测地球上(字面意思)是哪种语言,这是什么意思。
        • 4) 您冒着人员(或外部文件 - 还要记住您无法控制的外部来源)插入非法值的风险:但是,在插入之前通过良好的数据验证可以轻松避免这种情况进入表或使用到过程/函数中。我同意这不是一个完美的解决方案,但根据我的经验(18 年),当与不同文化和语言的人一起工作时,对表和枚举使用 CHAR 键可以隐藏很多我以前从未想过的小问题。不过,这是我的建议,我认为我永远不会进入您的办公室重构您的代码/数据库 :)
        • @Turro,我们是否达成了暴力协议? :) 我同意枚举描述将是本地化的理想选择。但是再想想应用程序代码 - 您不会创建第二个枚举,其后面的 int 值与第一个具有本地化下拉列表的值相同。相反,您拥有包含每个枚举值的翻译的资源文件(或类似文件)。请参阅此线程中的“答案”,以查看我使用基于 CHAR 的枚举的非常有限的情况。代码是 PK,您可以稍后(如果需要)基于自然 CHAR PK 而不是人工身份密钥轻松定义本地化表。
        • “暴力协议”?我可以喜欢它!开玩笑,不,也许我根本不是故意要暴力或严厉:I_do_apologize,如果我让你这么想的话。我只是想证明我的观点是正确的:我目前正在编写一个在许多国家(现在欧洲和非洲,很快亚洲)运行的应用程序,而且我在本地化方面遇到了很多麻烦,一般来说,不仅仅是枚举。根据我的经验(可能是有限的),枚举的数字可以是一个简单的(奇怪但真实的)通用基础,而不是字符串。几乎我所有的枚举也保存在 tables 中:我发现测试 enum=1 而不是 enum="Бз" 更容易。我欠你一杯啤酒:)
        【解决方案7】:

        在 SQL 中,您通过将项目放在表中来枚举项目。为您的帐户类别创建一个查找表,并让此参数接受新表的主键。

        【讨论】:

          【解决方案8】:

          您可以创建一个视图来模拟枚举。看这篇文章http://www.olegsych.com/2008/07/t4-template-for-generating-sql-view-from-csharp-enumeration/

          【讨论】:

          【解决方案9】:

          在 Transact-SQL 中执行此操作的最简单方法是使用 CHECK 约束。您可以通过herehere 阅读更多相关信息。此约束在 PostgreSQL 和 Oracle 中也可用。

          【讨论】:

            猜你喜欢
            • 2015-04-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-07-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多