【问题标题】:SQL colum field with multiple fixed values具有多个固定值的 SQL 列字段
【发布时间】:2011-06-25 13:38:42
【问题描述】:

假设您有一个固定的值列表(字符串):“None”、“Skype”、“ICQ”、“GoogleTalk”、“MSN”等。

用户只能选择该字符串中的一个作为他的主要即时消息应用程序。

将此字段称为假设表ContactInformationsIM。使用 SQL 表,您将如何为 IM 字段建模?解决方案应该让填充列表框的代码从数据库加载可能的选择。当用户做出选择并按下“保存”按钮时,代码应更新IM 字段。

所以,我会这样做:

ContactInformations 具有IM 类型的int 字段,引用IMListID 字段。 IMListID 是下表的键:

IMNameList

IMListID   int, primary key, not null
text       varchar(100)

所以,在创建数据库时,我会将支持的即时消息应用程序的所有名称插入到IMList 表中,我会将ContactInformationsIM 字段设置为默认值0 ("无”)。

填充可能的 IM 应用程序名称列表很容易(从 IMNameList 表中获取),更新不太容易,因为我隐含假设“none”的键是 0,“Skype”的键是 1 , "ICQ" 是 2 等等,我做了另一个隐含的假设:当用户从列表框中选择 "Skype" 时,"Skype" 的索引是 1。

你会如何解决这个问题?

【问题讨论】:

    标签: sql database-design


    【解决方案1】:

    我不会为 IM 名称使用 ID 号。他们自己有足够的身份。这是使用 PostgreSQL 的一种方法。

    CREATE TABLE IMNameList (
      IMName VARCHAR(35) PRIMARY KEY
    );
    
    insert into IMNameList values
    ('None'), 
    ('Skype'), 
    ('ICQ'), 
    ('GoogleTalk'), 
    ('MSN');
    

    您还希望在 IMNameList 上设置一个 INSTEAD OF DELETE 触发器(未显示),以防止所有人删除“无”值。 (无论您是否使用 ID 号都是如此。如果您使用 ID 号,则需要对 IMName 附加一个 UNIQUE 约束。)

    CREATE TABLE ContactInformations (
        user_id integer primary key,      -- references users, not shown
        IM VARCHAR(35) NOT NULL DEFAULT 'None' 
            REFERENCES IMNameList (IMName) 
            ON UPDATE CASCADE
            ON DELETE SET DEFAULT
    );
    
    INSERT INTO ContactInformations VALUES 
    (1, 'Skype'),
    (2, 'MSN');
    

    使用 ON DELETE SET DEFAULT,您可以从 IMNameList 中删除行,而不必担心它们是否仍在使用中。基本假设是您不会删除仍然存在的 IM 平台。

    DELETE FROM IMNameList
    WHERE IMName = 'MSN';
    
    SELECT * 
    FROM ContactInformations;
    
    user_id  IM
    --
    1        Skype
    2        None
    

    这会处理数据库方面的问题。在应用程序方面,很容易获得有效 IM 平台的列表。

    SELECT IMName
    FROM IMNameList
    ORDER BY IMName;
    

    ContactInformation 的更新不需要了解任何有关 IM id 号码的信息。要将第一个用户的 IM 从“Skype”更改为“ICQ”,只需

    UPDATE ContactInformations
    SET IM = 'ICQ'
    WHERE user_id = 1 
      AND IM = 'Skype';
    

    【讨论】:

    • 原则上我喜欢你的解决方案。我担心的是字段 IM 是一个 varchar,所以基本上磁盘空间被浪费了。此外,使用 varchar 作为主键是否更慢?
    • 在给定值的情况下,条目的平均长度为 5.5 个字节,或比 32 位整数大 2 个字节。使用 varchar 作为外键可以消除从现在到时间结束的每个 SELECT 语句的连接。
    【解决方案2】:

    如果您获取应用程序的名称及其 ID,我认为更新表没有任何问题。我唯一要改变的是将“none”设置为 NULL 而不是 0。

    【讨论】:

      【解决方案3】:

      这是一个非常常见的场景,应该非常容易实现,我不知道你使用的是什么语言(甚至是网络?)

      但通常,列表控件可以是数据绑定到数据源,您可以指定“文本字段”和“值字段”,在您的情况下,值字段将是 IM 字段,而文本字段应该是 IMName,您应该在 IM 字段中退出与其他表的连接。

      【讨论】:

        【解决方案4】:

        你可以使用 MySQL ENUM 类型。

        有关 Enum 和您的解决方案的比较,请参阅以下主题。

        MySQL ENUM type vs join tables

        【讨论】:

          【解决方案5】:

          当使用用户永远不会更改的预定义类型时,我在我的应用程序中使用枚举。这可以确保正确的整数存储在数据库中。

          枚举 IMListType { 没有设置, Skype, ICQ, 微信公众号, 雅虎 }

          【讨论】:

            【解决方案6】:

            很难准确说出您的问题是什么。也许是这样:“当我向 IMNameList 添加一条新记录时,如何确保我没有使用已经使用过的数字?”

            如果是这样,您正在为 IMListID 字段寻找一个自动递增的数字。 This question 的措辞与您的不完全一样,但公认的答案向您展示了一种适用于所有数据库平台的方法。

            【讨论】:

            • 我有一个“固定”的字符串列表。这个列表变化缓慢。用户只能从该列表中选择他的 IM 应用程序。我的应用程序(web应用程序,桌面应用程序,它没有任何区别)的表示层不需要知道列表,其他人将它传递给他。此外,当用户选择“ICQ”时,我想在 IM 字段中轻松存储对“ICQ”的引用(而不是直接字符串“ICQ”)。 Enum 可能不太适合,因为我的列表不像(“男性”,“女性”),它基本上不应该改变。一对(字符串,id-code)应该可以完成这项工作。
            • 我明白你想要做什么,我同意字符串,id-code 可以正常工作。我的问题是您似乎已经解决了问题,所以我不知道您要我们说什么。尽管您说“更新不那么容易”,但我找不到更新任何表格的问题。
            • 嗨,我提出了这个问题,因为我不是数据库设计方面的专家(我必须为一个项目设计一个),即使我已经看到了建模该问题的正确方法,我有兴趣知道是否有其他方法(可能是模式,标准方法)来解决它!谢谢大家。
            猜你喜欢
            • 2019-03-13
            • 1970-01-01
            • 1970-01-01
            • 2013-04-14
            • 1970-01-01
            • 1970-01-01
            • 2013-04-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多