Сохранить результаты 3 игроков за игру в PostgreSQL - PullRequest
1 голос
/ 26 октября 2011

Я пытаюсь сохранить результаты карточной игры матчей (всегда с 3 игроками) в PotsgreSQL 8.4.9

У меня есть почти все (смотри ниже, пожалуйста), только 2 второстепенные части отсутствуют.

  1. Сначала я пытаюсь создать процедуру PL / pgSQL для сохранения результатов
  2. А затем мне нужно заявление о выборе соединения, чтобы получить дату матча, имена игроков, пол, аватары, очки и, если игрок преждевременно вышел из игры

Я создал 3 таблицы SQL:

    create table pref_users (
            uid varchar(32) primary key,
            first_name varchar(64),
            female boolean,
            avatar varchar(128)
    }

    create table pref_games {
            gid serial,
            rounds integer not null,
            finished timestamp default current_timestamp
    }

    create table pref_scores (
            uid varchar(32) references pref_users,
            gid serial references pref_games,  /* XXX serial ok here? */
            money integer not null,
            quit boolean
    );

Вот моя процедура PL / pgSQL, где мне нужна помощь, пожалуйста:

    create or replace function pref_insert_scores(
        _uid0 varchar, _money0 integer, _quit0 boolean,
        _uid1 varchar, _money1 integer, _quit1 boolean,
        _uid2 varchar, _money2 integer, _quit2 boolean,
        _rounds integer) returns void as $BODY$
            begin

            insert into pref_games (rounds) values (_rounds);

            -- XXX how do I get the _gid of this new game?

            insert into pref_scores (uid, gid, money, quit)
                values(_uid0, _gid, _money0, _quit0);

            insert into pref_scores (uid, gid, money, quit)
                values(_uid1, _gid, _money1, _quit1);

            insert into pref_scores (uid, gid, money, quit)
                values(_uid2, _gid, _money2, _quit2);
            end;
    $BODY$ language plpgsql;

А затем мне нужна помощь, чтобы объединить результаты с данными first_name, female, avatar из первой таблицы, чтобы я мог отобразить список сыгранных игр за последние 7 дней в таблице на веб-странице:

01.12.2011  Alice $10        Bob $20 Charlie -$30  17 rounds
01.12.2011  Alice $0 (quit)  Bob $20 Charlie -$20  5  rounds

UPDATE:

С мю слишком короткая помощь Теперь мои таблицы заполнены данными, но я все еще не могу понять, как составить список всех игр, выполненных игроком - вместе с его 2 противниками и их баллы.

У меня есть таблица со всеми играми:

# select * from pref_games limit 5;
 gid | rounds |          finished
-----+--------+----------------------------
  1 |     10 | 2011-10-26 14:10:35.46725
  2 |     12 | 2011-10-26 14:34:13.440868
  3 |     12 | 2011-10-26 14:34:39.279883
  4 |     14 | 2011-10-26 14:35:25.895376
  5 |     14 | 2011-10-26 14:36:56.765978

Тогда у меня есть все 3 игрока (и их оценки), которые участвовали в игре № 3:

# select * from pref_scores where gid=3;
         uid           | gid | money | quit
-----------------------+-----+-------+------
 OK515337846127        |   3 |   -37 | f
 OK40798070412         |   3 |   -75 | f
 MR2871175175044094219 |   3 |   112 | f

И это все игры, в которые играет игрок с uid = DE9411:

# select * from pref_scores where id='DE9411';
  uid   | gid | money | quit
--------+-----+-------+------
 DE9411 |  43 |    64 | f
 DE9411 | 159 |  -110 | f
 DE9411 | 224 |    66 | f
 DE9411 | 297 |   -36 | f
 DE9411 | 385 |    29 | f
 DE9411 | 479 |   -40 | f
 DE9411 | 631 |   -14 | f
 DE9411 | 699 |   352 | f
 DE9411 | 784 |   -15 | f
 DE9411 | 835 |   242 | f

Но как мне перечислить 2 других игроков и их результаты в приведенном выше наборе результатов?

Ответы [ 4 ]

1 голос
/ 26 октября 2011

Этот запрос должен работать для получения необходимого списка с текущей схемой.Однако при таком количестве соединений производительность может быть не такой высокой.Поскольку вы знаете, что у вас всегда есть 3 пользователя, в зависимости от ожидаемого размера этой таблицы, вы можете проверить производительность на наличие одного игрового стола с ненормализованной информацией о пользователе.

select g.finished, u1.uid u1, s1.money m1, s1.quit q1,  u2.uid u2, s2.money m2, s2.quit
q2, u3.uid u3, s3.money m3, s3.quit q3, g.rounds
from pref_games g
inner join pref_scores s1 on s1.gid = g.gid 
inner join pref_scores s2 on s2.gid = g.gid and s2.uid > s1.uid
inner join pref_scores s3 on s3.gid = g.gid and s3.uid > s2.uid
inner join pref_users u1 on s1.uid = u1.uid
inner join pref_users u2 on s2.uid = u2.uid
inner join pref_users u3 on s3.uid = u3.uid
and g.finished > CURRENT_DATE - interval '1 week'
1 голос
/ 26 октября 2011

Вы не хотите serial в pref_scores, просто int:

create table pref_scores (
        uid varchar(32) references pref_users,
        gid int references pref_games,  /* XXX serial ok here? */
        money integer not null,
        quit boolean
);

Вы хотите использовать INSERT ... RETURNING ... INTO:

create or replace function pref_insert_scores(
    _uid0 varchar, _money0 integer, _quit0 boolean,
    _uid1 varchar, _money1 integer, _quit1 boolean,
    _uid2 varchar, _money2 integer, _quit2 boolean,
    _rounds integer) returns void as $BODY$
declare
    _gid int;
begin
    insert into pref_games (rounds) values (_rounds) returning gid into _gid;
    -- etc...
0 голосов
/ 27 октября 2011
        gid serial references pref_games,  /* XXX serial ok here? */

Здесь вы должны использовать «int», а не «serial» - так как вам нужно ссылаться на очень конкретную запись в pref_games.

0 голосов
/ 26 октября 2011

В строке:

        finished timestamp default current_timestamp

Я бы настоятельно рекомендовал использовать

        finished timestamptz default current_timestamp

, поскольку это позволяет использовать более точную арифметику даты / времени в отношении изменений летнего времени в качестве фактической даты /время хранится в GMT - оно также лучше подходит для интернационализации.

Из руководства по pg9.1.1 '8.5.Типы даты / времени ':

[...]

Примечание. Стандарт SQL требует, чтобы запись только отметки времени была эквивалентна отметке времени без часового пояса, и PostgreSQL соблюдает это поведение.(Выпуски до 7.3 рассматривали это как метку времени с часовым поясом.) Timestamptz принимается как сокращение для метки времени с часовым поясом;это расширение PostgreSQL.

[...]

Для метки времени с часовым поясом внутренне сохраненное значение всегда указано в UTC (универсальное координированное время, традиционно известное как среднее время по Гринвичу, GMT).Входное значение с указанным явным часовым поясом преобразуется в UTC с использованием соответствующего смещения для этого часового пояса.Если во входной строке не указан часовой пояс, предполагается, что он находится в часовом поясе, указанном системным параметром часового пояса, и преобразуется в UTC с использованием смещения для часового пояса.

Когда отметка временикогда выводится значение часового пояса, оно всегда преобразуется из UTC в текущий часовой пояс и отображается как местное время в этом поясе.Чтобы увидеть время в другом часовом поясе, измените часовой пояс или используйте конструкцию AT TIME ZONE (см. Раздел 9.9.3).

[...]

...