【发布时间】:2016-07-13 04:20:54
【问题描述】:
我正在尝试将行与“真实”事物对应的多对一关系的表合并。
我正在编写一个二十一点模拟器,它将游戏历史存储在数据库中,每次运行都会生成一组新表。这些表实际上更像是模板,因为每个游戏都有自己的一组 3 个可变表(玩家、手牌和比赛)。这是布局,其中 suff 是用户指定的用于当前运行的后缀:
- cards
- id INTEGER PRIMARY KEY
- cardValue INTEGER NOT NULL
- suit INTEGER NOT NULL
- players_suff
- whichPlayer INTEGER PRIMARY KEY
- aiType TEXT NOT NULL
- hands_suff
- id BIGSERIAL PRIMARY KEY
- whichPlayer INTEGER REFERENCES players_suff(whichPlayer) *
- whichHand BIGINT NOT NULL
- thisCard INTEGER REFERENCES cards(id)
- matches_suff
- id BIGSERIAL PRIMARY KEY
- whichGame INTEGER NOT NULL
- dealersHand BIGINT NOT NULL
- whichPlayer INTEGER REFERENCES players_suff(whichPlayer)
- thisPlayersHand BIGINT NOT NULL **
- playerResult INTEGER NOT NULL --AKA who won
只创建一张卡片表,因为它的值是恒定的。
所以在运行模拟器两次后你可能会:
hands_firstrun
players_firstrun
matches_firstrun
hands_secondrun
players_secondrun
matches_secondrun
如果你对这两个运行使用相同的 AI 参数(即 player_firstrun 和 player_secondrun 完全相同),我希望能够组合这些表。问题是我插入手的方式让这变得非常混乱:whichHand 不能是 BIGSERIAL,因为 hands_suff 行与“实际手”的关系很多:1。 match_suff 的处理方式相同,因为二十一点“游戏”实际上由一组游戏组成:每个玩家与庄家的配对。所以对于 3 名玩家,你实际上每轮有 3 行。
目前我选择表中最大的 whichHand,将其加 1,然后插入一只手的所有行。如果我要合并 2 个可能都非常大的表,我担心这种“查询和插入”会非常慢。
当我合并表时,我觉得我应该能够(完全在 SQL 中)查询 whichHand 和 whichGame 中的最大值,然后使用它们合并表,为表中每个唯一的 whichHand 和 whichGame 递增它们正在合并。
(我看到了this question,但它无法在 2 个不同的地方使用生成的 ID)。我正在使用 Postgres,如果答案是特定的就可以了。
* 遗憾的是 postgres 不允许参数化的表名,所以这必须通过手动字符串替换来完成。不是世界末日,因为该程序不是面向网络的,除了我之外没有人可能会打扰它,但是 SQL 注入漏洞并没有让我高兴。
** matches_suff(whichPlayersHand) 原本要引用 hands_suff(whichHand) 但 foreign keys must reference unique values。 whichHand 不是唯一的,因为一手牌由多行组成,每行“持有”一张牌。要查询一手牌,您选择所有那些在 whichHand 中具有相同值的行。如果不使用数组,我想不出更优雅的方式来做到这一点。
编辑:
这就是我现在拥有的:
thomas=# \dt
List of relations
Schema | Name | Type | Owner
--------+----------------+-------+--------
public | cards | table | thomas
public | hands_first | table | thomas
public | hands_second | table | thomas
public | matches_first | table | thomas
public | matches_second | table | thomas
public | players_first | table | thomas
public | players_second | table | thomas
(7 rows)
thomas=# SELECT * FROM hands_first
thomas-# \g
id | whichplayer | whichhand | thiscard
----+-------------+-----------+----------
1 | 0 | 0 | 6
2 | 0 | 0 | 63
3 | 0 | 0 | 41
4 | 1 | 1 | 76
5 | 1 | 1 | 23
6 | 0 | 2 | 51
7 | 0 | 2 | 29
8 | 0 | 2 | 2
9 | 0 | 2 | 92
10 | 0 | 2 | 6
11 | 1 | 3 | 101
12 | 1 | 3 | 8
(12 rows)
thomas=# SELECT * FROM hands_second
thomas-# \g
id | whichplayer | whichhand | thiscard
----+-------------+-----------+----------
1 | 0 | 0 | 78
2 | 0 | 0 | 38
3 | 1 | 1 | 24
4 | 1 | 1 | 18
5 | 1 | 1 | 95
6 | 1 | 1 | 40
7 | 0 | 2 | 13
8 | 0 | 2 | 84
9 | 0 | 2 | 41
10 | 1 | 3 | 29
11 | 1 | 3 | 34
12 | 1 | 3 | 56
13 | 1 | 3 | 52
thomas=# SELECT * FROM matches_first
thomas-# \g
id | whichgame | dealershand | whichplayer | thisplayershand | playerresult
----+-----------+-------------+-------------+-----------------+--------------
1 | 0 | 0 | 1 | 1 | 1
2 | 1 | 2 | 1 | 3 | 2
(2 rows)
thomas=# SELECT * FROM matches_second
thomas-# \g
id | whichgame | dealershand | whichplayer | thisplayershand | playerresult
----+-----------+-------------+-------------+-----------------+--------------
1 | 0 | 0 | 1 | 1 | 0
2 | 1 | 2 | 1 | 3 | 2
(2 rows)
我想把它们结合起来:
hands_combined table:
id | whichplayer | whichhand | thiscard
----+-------------+-----------+----------
1 | 0 | 0 | 6 --Seven of Spades
2 | 0 | 0 | 63 --Queen of Spades
3 | 0 | 0 | 41 --Three of Clubs
4 | 1 | 1 | 76
5 | 1 | 1 | 23
6 | 0 | 2 | 51
7 | 0 | 2 | 29
8 | 0 | 2 | 2
9 | 0 | 2 | 92
10 | 0 | 2 | 6
11 | 1 | 3 | 101
12 | 1 | 3 | 8
13 | 0 | 4 | 78
14 | 0 | 4 | 38
15 | 1 | 5 | 24
16 | 1 | 5 | 18
17 | 1 | 5 | 95
18 | 1 | 5 | 40
19 | 0 | 6 | 13
20 | 0 | 6 | 84
21 | 0 | 6 | 41
22 | 1 | 7 | 29
23 | 1 | 7 | 34
24 | 1 | 7 | 56
25 | 1 | 7 | 52
matches_combined table:
id | whichgame | dealershand | whichplayer | thisplayershand | playerresult
----+-----------+-------------+-------------+-----------------+--------------
1 | 0 | 0 | 1 | 1 | 1
2 | 1 | 2 | 1 | 3 | 2
3 | 2 | 4 | 1 | 5 | 0
4 | 3 | 6 | 1 | 7 | 2
"thiscard" 的每个值都表示 [1..104]--52 范围内的扑克牌,并带有一个额外的位来表示它是面朝上还是面朝下。由于空间原因,我没有发布实际的表格。 所以玩家 0(又名庄家)在第一局中有一手牌(黑桃七,空间皇后,梅花三)。
【问题讨论】:
-
有人介意解释否决票以便我编辑问题吗?
-
你能写出你拥有的数据的例子,以及你需要的数据吗?你也可以给出你现有的查询。
-
生成的表格应该看起来像什么(也就是 combine 的结果)?顺便说一句,你为什么想出一个表格动物园而不添加
game_id(你可以使用你当前的suff值作为那里的值)来区分相关的条目。目前的方式是对SQL数据库逻辑的严重滥用。 -
正如 rpy 也提到的,这是一种非常奇怪的数据库结构方式。您通过在表名中存储记录信息(游戏)来模糊结构和数据之间的界限。正如我所看到的,“suff”的信息会更合适地存储在可以正确查询的列中。
-
@AnthonyE 我认为这会引发区分哪些球员参与每场比赛的问题。当前方法的优点(尽管相信我,我希望有更好的方法)是匹配表代表一组球员的比赛,这些球员可以通过球员表中的 ID 引用。下一轮可能会有其他玩家(以及不同数量的玩家)。编辑:重要的原因是因为重点是设置不同类型的 AI 相互对抗。如果这变得混乱,整个事情就会崩溃。
标签: sql database postgresql merge