如何在T-SQL中将结构体类型作为列值创建?

3
我正在为我的游戏制作数据库,需要存储大量的C风格结构体。
struct stats{
    int strength, stamina, agility, intelligence, etc..;
}

我一直在研究如何在T-SQL中创建用户定义的数据类型,MSDN明确表示用户定义的数据类型不能用作列类型:

用户定义的表类型不能用作表中的列或结构化用户定义类型中的字段。

是否没有解决方法或其他方式可以在其中创建基于struct的系统?我还需要一个struct来存储技能,我有大约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....)

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

1
那不是很规范化。你应该考虑将其拆分为单独的列。 - Daniel A. White
通常情况下,你希望为每个结构体定义一个表格,其中列与结构体中的每个字段对齐。 - Joel Coehoorn
2个回答

3

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

  1. Make a primary key for the Player table that isn't a VARCHAR. A VARCHAR column isn't a good primary key; a better key type would be an INT (or a BIGINT if you expect more than 2^31-1 players ;)). Key lookup with integers is faster compared to key lookup with strings. Also consider that you will have to reference players by their primary key in other tables (detail tables).

    The easiest way is to have SQL Server create such an integer key for you. You can do this by adding an IDENTITY column to the table, and make that column the primary key. In that case, for each insert into the player table a key will be assigned to the player. You will have to add an INDEX on the table for the player_name column though as at some point you will have to look up players by their name.

    Eg:

    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. As Gordon already pointed out, structs or arrays of structs can't be stored in a table as such. A good way of designing your tables is for each logically grouped set of data for a player, create a (detail) table that links to the player table. Relational databases have an easier time with tables that have as few columns as possible.

    For a group of information (a struct) that does not change like a player_location you could argue to store this information directly in the player table (columns X, Y and Z). Better still is to have that logically grouped set of information in a separate table player_location. You would then have a 1:1 relation between the player table and the location table.

    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)
    );
    

    Other groups of information like player_equipment will continually grow, as I assume players will pick up equipment as they play through the game. Another aspect is that you will probably add new equipment as the game grows (through mods say). Say you have 100 types of equipment now but in your expansion you would add 100 new types of equipment. Say you take the previous advice, create a table with 100 columns and then when you release the mod you would then have to add 100 new columns.

    Having so many columns in a table is a bad idea in itself, plus you would have to alter the equipment table when you release the mod. Another aspect in that way of thinking is that you would have to store 100 (or 200 after the mod) columns of data that would not necessarily contain any relevant information. A player might only have 20 equipment and you would have to store 100 (200) columns. That would be a waste of disk/memory space.

    A better way to model this is to have a definition table that defines the equipment and a player-equipment table that stores what equipment the player is holding. Example:

    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)
    );
    

    When you release a new mod, you would add new equipment in the equipment table and when a player picks up new equiment you would add a row to the player_equipment table referencing the equipment by its ID.

无论如何,这些都是你深入挖掘的一些想法。一个好的数据库模型将使您更轻松地编写查询(不那么复杂),并且将允许数据库消耗更少的内存和磁盘空间。

2
这是您的表格:
CREATE TABLE [dbo].[Players](
    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....
)

这表明您应该有几个其他的表和列:
  • Player_SkillsSkills:每个玩家和每种技能都有一行,可能还有一个技能等级列。
  • Location:每个位置都有一行,包含有关位置的信息。 LocationId 将在 Players 表中。
  • Player_EquipmentEquipment:每个玩家和每个设备都有一行。
我不知道 player_statsplayer_customization 是什么。也许它们只是适用于 Players 的合适列;也许它们应该成为自己的表。
将关系数据库视为编程结构(例如“结构”)并不合适。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接