sql-server - 创建结构类型作为 T-SQL 的列值?

标签 sql-server tsql

我正在为我的游戏创建一个数据库,我需要存储大量 C 风格的结构。

struct stats{
    int strength, stamina, agility, intelligence, etc..;
}

我一直在研究如何在 t-sql 中创建用户定义的数据类型,MSDN 特别指出用户定义的数据类型不能用作列类型:

A user-defined table type cannot be used as a column in a table or a field in a structured user-defined type.

是否没有解决方法或其他方法可以在其中创建基于结构的系统?我还需要一个技能结构,我有大约 120 多种技能需要存储在我的玩家表下。我想要的表格看起来像这样:

CREATE TABLE [dbo].[Player](
    player_name nvarchar (20),
    gold int,
    player_stats stats,                 // array of 4 ints
    player_skills skills,               // array of 120+ tinyints
    player_location location,           // array of 3 floats (x,y,z)
    player_customization customization, // array of 20+ tinyints
    player_equipment equipment,         // array of 8 ints
    etc....)

有没有一种简单的方法可以做到这一点,还是我只需要将所有这些添加为单独的列类型?感谢您的帮助。

最佳答案

除了 Gordon 的建议之外还有几个额外的建议:

  1. Player 表创建一个不是 VARCHAR 的主键。 VARCHAR 列不是一个好的主键;更好的 key 类型是 INT(或者 BIGINT,如果您期望超过 2^31-1 个玩家;))。与使用字符串的键查找相比,使用整数的键查找更快。还要考虑到您必须通过其他表(详细信息表)中的主键来引用玩家。

    最简单的方法是让 SQL Server 为您创建这样一个整数键。您可以通过向表中添加一个 IDENTITY 列并使该列成为主键来实现这一点。在这种情况下,对于每次插入播放器表,都会为播放器分配一个键。您将不得不在表中为 player_name 列添加一个 INDEX,尽管在​​某些时候您将不得不通过他们的名字查找球员。

    例如:

    CREATE TABLE player(
        player_id INT IDENTITY(1,1) NOT NULL,
        player_name NVARCHAR(128),
        -- ... other columns
        CONSTRAINT PK_player PRIMARY KEY CLUSTERED (player_id)
    );
    
    CREATE INDEX
        IX_player_name
    ON
        player(player_name);
    
  2. 正如 Gordon 已经指出的那样,结构或结构数组不能存储在表中。设计表格的一个好方法是为玩家的每个逻辑分组数据集创建一个链接到玩家表格的(详细信息)表格。关系数据库更容易使用列数尽可能少的表。

    对于一组不会像 player_location 那样改变的信息(一个结构),您可以争论将这些信息直接存储在播放器表中(列 XYZ)。更好的办法是将逻辑分组的信息集放在单独的表 player_location 中。然后,您将在玩家表和位置表之间建立 1:1 的关系。

    CREATE TABLE player_location(
        player_id INT NOT NULL,
        x FLOAT NOT NULL,
        y FLOAT NOT NULL,
        z FLOAT NOT NULL,
        CONSTRAINT PK_player_location PRIMARY KEY CLUSTERED (player_id)
        CONSTRAINT FK_player_location FOREIGN KEY(player_id) REFERENCES player(player_id)
    );
    

    player_equipment 等其他信息组会不断增加,因为我假设玩家在玩游戏时会拾取装备。另一个方面是,随着游戏的发展,你可能会添加新设备(比如通过模组)。假设您现在有 100 种设备,但在您的扩展中您将添加 100 种新设备。假设您接受了之前的建议,创建了一个包含 100 列的表,然后当您发布 mod 时,您将不得不添加 100 个新列。

    在一个表中有这么多列本身就是一个坏主意,而且你必须在发布 mod 时更改设备表。这种思维方式的另一个方面是您必须存储 100(或 mod 之后的 200)列数据,这些数据不一定包含任何相关信息。一个玩家可能只有 20 件装备,而您必须存储 100 (200) 列。那会浪费磁盘/内存空间。

    对此建模的更好方法是使用一个定义设备的定义表和一个存储玩家持有的设备的玩家设备表。示例:

    CREATE TABLE equipment(
        equipment_id INT NOT NULL,
        equipment_name NVARCHAR(128) NOT NULL,
        -- ...
        CONSTRAINT PK_equipment PRIMARY KEY CLUSTERED (equipment_id)
    );
    
    CREATE TABLE player_equipment(
        player_id INT NOT NULL,
        equipment_id INT NOT NULL,
        amount INT NOT NULL,
        CONSTRAINT PK_player_equipment PRIMARY KEY CLUSTERED (player_id,equipment_id),
        CONSTRAINT FK_player_equipment FOREIGN KEY(player_id) REFERENCES player(player_id),
        CONSTRAINT FK_equipment FOREIGN KEY(equipment_id) REFERENCES equipment(equipment_id)
    );
    

    当你发布一个新的 mod 时,你会在 equipment 表中添加新设备,当玩家拿起新设备时,你会在 player_equipment 表中添加一行通过 ID 引用设备。

无论如何,这些都是您可以深入研究的一些想法。一个好的数据库模型将使您能够以更简单的方式(不太复杂)编写查询,并允许数据库占用更少的内存和磁盘空间。

关于sql-server - 创建结构类型作为 T-SQL 的列值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40539966/

相关文章:

sql - 存储过程及其使用的表

mysql - 为什么 SQL 不匹配两个字符串?

php - SQL 更新可选参数 PHP

sql - 如何从 SQL Server 中的 try/catch 子句中获取内部错误

sql - 避免子查询

sql - 如何将OFFSET/FETCH 和WITH TIES 结合在一起?

sql-server - 如何在另一个程序中获取一个程序的RaiseError消息

sql-server - 在 Azure Functions 上使用 Microsoft Report Viewer

sql-server - 这个支点能否更有效地完成?

sql - .Net SqlCommand.ExecuteNonQuery 中的查询超时,适用于 SQL Server Management Studio