Я пытаюсь объединить таблицы, где строки соответствуют многим: 1 отношениям с "реальными" вещами.
Я пишу симулятор блэкджека, который хранит историю игр в базе данных с новым набором таблиц, сгенерированных каждым прогоном. Таблицы действительно больше похожи на шаблоны, поскольку каждая игра имеет свой собственный набор из трех изменяемых таблиц (игроков, рук и матчей). Здесь макет, где 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 для обоих этих прогонов (т.е. игроки_firstrun и players_secondrun точно такие же). Проблема в том, что способ, которым я вставляю руки, делает это действительно беспорядочным: whatHand не может быть BIGSERIAL, потому что отношения строк hands_suff с "фактическими руками" много: 1. match_suff обрабатывается одинаково, потому что "игра" в блэкджек на самом деле состоит из набора игр: набора пар каждого игрока против дилера. Итак, для 3 игроков у вас на самом деле есть 3 ряда для каждого раунда.
В настоящее время я выбираю самый большой из нихHand в таблице, добавляю 1 к нему, а затем вставляю все строки для одной руки. Я беспокоюсь, что этот "запрос и вставка" будет очень медленным, если я объединю 2 таблицы, которые могут быть как угодно большими.
Когда я объединяю таблицы, я чувствую, что должен (полностью в SQL) запрашивать наибольшие значения, в которыхHand и whichGame после этого используют их, объединяют таблицы, увеличивая их для каждого уникального whoHand и whatGame в таблице сливается.
(я видел этот вопрос, но он не обрабатывает сгенерированный идентификатор в двух разных местах). Я использую Postgres, и это нормально, если ответ специфичен для него.
* грустно postgres не позволяет параметризовать имена таблиц, поэтому это должно было быть сделано путем ручной замены строки. Не конец света, так как программа не ориентирована на веб-сайты, и никто, кроме меня, скорее всего не потрудится с ней, но уязвимость SQL-инъекций не делает меня счастливой.
** matches_suff (whichPlayersHand) изначально собирался ссылаться на hands_suff (whoHand), но внешние ключи должны ссылаться на уникальные значения. whichHand не уникален, потому что рука состоит из нескольких строк, причем каждая строка "удерживает" одну карту. Чтобы запросить руку, вы выбираете все эти строки с тем же значением в whichHand. Я не мог придумать более элегантный способ сделать это, не прибегая к массивам.
EDIT:
Это то, что у меня есть сейчас:
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 (он же дилер) была рука (Семь из пик, Королева пространств, 3 из клубов) в первой игре.