knowledge-database (beta)

Current group: comp.databases.

Database table for nested statistical query

Database table for nested statistical query  
Terrence Brannon
 Re: Database table for nested statistical query  
--CELKO--
 Re: Database table for nested statistical query  
--CELKO--
 Re: Database table for nested statistical query  
Terrence Brannon
 Re: Database table for nested statistical query  
Terrence Brannon
From:Terrence Brannon
Subject:Database table for nested statistical query
Date:Fri, 21 Jan 2005 19:41:38 +0000

I am designing a Postgresql schema for a website which will log
results of match interactions between players. Because players belong
to clans, I will do clan stats as well, but that's later.

When a player logs in, he will be
presented with these statistics: the last 10 battle results, his
personal 10 last battle results, the 3 people he has beaten the most,
the 3 people who have beaten him the most.

The last 2 statistics make it difficult for me to figure out how to
design the battle_t table. A battle has 2 players and a result of win,
lose, or draw represented by 1, 0, or -1.

Here is my current schema design. I would appreciate input into how
the battle_t table should be designed.

And could someone recommend a good text on database design?

CREATE TABLE player_t (
player_id SERIAL NOT NULL,
clan_id INT4,
screen_name VARCHAR(40) NOT NULL,
login_name VARCHAR(40) NOT NULL,
password VARCHAR(40) NOT NULL,
email VARCHAR(40),
elo INT4 DEFAULT 1600 NOT NULL,
date_joined TIMESTAMP,
PRIMARY KEY (player_id)
);

CREATE TABLE clan_t (
clan_id SERIAL NOT NULL,
clan_name VARCHAR(40),
clan_url VARCHAR(40),
player_id INT4,
PRIMARY KEY (clan_id)
);

CREATE TABLE battle_t (
battle_id SERIAL NOT NULL,
player1 INT4 NOT NULL,
player2 INT4 NOT NULL,
result INT4 NOT NULL,
timestamp TIMESTAMP NOT NULL,
PRIMARY KEY (battle_id)
);

/*==========================================================================*/
/* Foreign Keys
*/
/*==========================================================================*/

ALTER TABLE clan_t
ADD FOREIGN KEY (player_id) REFERENCES player_t (player_id);

/*==========================================================================*/
/* Indexes
*/
/*==========================================================================*/

CREATE UNIQUE INDEX IDX_player_t1 ON player_t (player_id);

CREATE INDEX IDX_clan_t1 ON clan_t (player_id);




--
Carter's Compass: I know I'm on the right track when,
by deleting something, I'm adding functionality.
From:--CELKO--
Subject:Re: Database table for nested statistical query
Date:21 Jan 2005 17:55:32 -0800
I think is more like what you want -- no reserved words, no proprietary
data types, DRI actions, reasonable lengths (a CHAR(40) password?!),
etc.

CREATE TABLE Players
(player_id INTEGER NOT NULL PRIMARY KEY,
clan_id INTEGER NOT NULL
REFERENCES Clans(clan_id)
ON UPDATE CASCADE,
screen_name VARCHAR(25) NOT NULL,
login_name VARCHAR (20) NOT NULL,
password VARCHAR(8) NOT NULL,
email VARCHAR(100) NOT NULL,
elo INTEGER DEFAULT 1600 NOT NULL,
membership_date TIMESTAMP NOT NULL);

CREATE TABLE Clans
(clan_id INTEGER NOT NULL PRIMARY KEY,
clan_name VARCHAR(20) NOT NULL,
clan_url VARCHAR(40) NOT NULL);

CREATE TABLE Battles
(battle_id INTEGER NOT NULL PRIMARY KEY,
winner_player_id INTEGER NOT NULL,
REFERENCES Players(player_id)
ON UPDATE CASCADE,
loser_player_id INTEGER NOT NULL
REFERENCES Players(player_id)
ON UPDATE CASCADE,
CHECK (winner_player_id <> loser_player_id),
battle_result INTEGER DEFAULT 0 NOT NULL
CHECK(battle_result IN (0, 1)), -- zero is a tie
battle_date TIMESTAMP NOT NULL);

>> ... these statistics: the last 10 battle results, his personal 10
last battle results, the 3 people he has beaten the most, the 3 people
who have beaten him the most. <<

Here are the skeletons for getting your stats. You can then add a join
to Players to get the names. The front end should handle picking the
number of rows to be displayed, not the backend.

SELECT winner_player_id, loser_player_id, battle_date
FROM Battles
WHERE :my_guy IN (winner_player_id, loser_player_id)

Would it be better to display the screen names? How do we handle ties?


SELECT P.screen_name, COUNT(*) AS losses_to_me
FROM Battles AS B, Players AS P
WHERE B.winner_player_id = :my_guy
AND B.loser_player_id = P.player_id
AND B.battle_status <> 0
GROUP BY P.screen_name;

SELECT P.screen_name, COUNT(*) AS wins_over_me
FROM Battles AS B, Players AS P
WHERE B.loser_player_id = :my_guy
AND B.winner_player_id = P.player_id
AND B.battle_status <> 0
GROUP BY P.screen_name;
From:--CELKO--
Subject:Re: Database table for nested statistical query
Date:23 Jan 2005 16:14:08 -0800
>> A player has many battles and a battle has many (2) players. The way
to handle a many-to-many relationship is to create an intermediate
table that each table has a one-to-many relationship with. Don't you
think that is a better way to handle this? <<

No, two players per battle is not "many" -- many means we have "1 to m"
where we do not have a constant value of (m).
From:Terrence Brannon
Subject:Re: Database table for nested statistical query
Date:Sat, 22 Jan 2005 00:41:33 +0000
Terrence Brannon writes:

> I am designing a Postgresql schema

I clearly need some education in this area. The schema below is not
normalized.

> for a website which will log results of match interactions between
> players. Because players belong to clans, I will do clan stats as
> well, but that's later.
>
> When a player logs in, he will be
> presented with these statistics: the last 10 battle results, his
> personal 10 last battle results, the 3 people he has beaten the most,
> the 3 people who have beaten him the most.
>
> The last 2 statistics make it difficult for me to figure out how to
> design the battle_t table. A battle has 2 players and a result of win,
> lose, or draw represented by 1, 0, or -1.
>
> Here is my current schema design. I would appreciate input into how
> the battle_t table should be designed.

Here follows the newer more sane schema. I think I can cobble up s SQL
query for it.

/*==========================================================================*/
/* Tables
*/
/*==========================================================================*/

CREATE TABLE player_t (
player_id SERIAL NOT NULL,
clan_id INT4,
screen_name VARCHAR(40) NOT NULL,
login_name VARCHAR(40) NOT NULL,
password VARCHAR(40) NOT NULL,
email VARCHAR(40),
elo INT4 DEFAULT 1600 NOT NULL,
date_joined TIMESTAMP,
PRIMARY KEY (player_id)
);

CREATE TABLE clan_t (
clan_id SERIAL NOT NULL,
clan_name VARCHAR(40),
clan_url VARCHAR(40),
player_id INT4,
PRIMARY KEY (clan_id)
);

CREATE TABLE battle_t (
battle_id SERIAL NOT NULL,
player1 INT4 NOT NULL,
player2 INT4 NOT NULL,
result INT4 NOT NULL,
timestamp TIMESTAMP NOT NULL,
PRIMARY KEY (battle_id)
);

CREATE TABLE player_battle_t (
player_id INT4 NOT NULL,
battle_id INT4 NOT NULL,
battle_time TIMESTAMP,
winner INT4,
PRIMARY KEY (player_id, battle_id)
);

/*==========================================================================*/
/* Foreign Keys
*/
/*==========================================================================*/

ALTER TABLE clan_t
ADD FOREIGN KEY (player_id) REFERENCES player_t (player_id);

ALTER TABLE player_battle_t
ADD FOREIGN KEY (player_id) REFERENCES player_t (player_id);

ALTER TABLE player_battle_t
ADD FOREIGN KEY (battle_id) REFERENCES battle_t (battle_id);

/*==========================================================================*/
/* Indexes
*/
/*==========================================================================*/

CREATE UNIQUE INDEX IDX_player_t1 ON player_t (player_id);

CREATE INDEX IDX_clan_t1 ON clan_t (player_id);

CREATE UNIQUE INDEX IDX_battle_t1 ON battle_t (battle_id);

CREATE INDEX IDX_player_battle_t1 ON player_battle_t (player_id);


--
Carter's Compass: I know I'm on the right track when,
by deleting something, I'm adding functionality.
From:Terrence Brannon
Subject:Re: Database table for nested statistical query
Date:Sun, 23 Jan 2005 23:59:58 +0000
"--CELKO--" writes:

> I think is more like what you want -- no reserved words, no proprietary
> data types, DRI actions, reasonable lengths (a CHAR(40) password?!),
> etc.
>
> CREATE TABLE Players
> (player_id INTEGER NOT NULL PRIMARY KEY,
> clan_id INTEGER NOT NULL
> REFERENCES Clans(clan_id)
> ON UPDATE CASCADE,
> screen_name VARCHAR(25) NOT NULL,
> login_name VARCHAR (20) NOT NULL,
> password VARCHAR(8) NOT NULL,
> email VARCHAR(100) NOT NULL,
> elo INTEGER DEFAULT 1600 NOT NULL,
> membership_date TIMESTAMP NOT NULL);
>
> CREATE TABLE Battles
> (battle_id INTEGER NOT NULL PRIMARY KEY,
> winner_player_id INTEGER NOT NULL,
> REFERENCES Players(player_id)
> ON UPDATE CASCADE,
> loser_player_id INTEGER NOT NULL
> REFERENCES Players(player_id)
> ON UPDATE CASCADE,
> CHECK (winner_player_id <> loser_player_id),
> battle_result INTEGER DEFAULT 0 NOT NULL
> CHECK(battle_result IN (0, 1)), -- zero is a tie
> battle_date TIMESTAMP NOT NULL);
>

A player has many battles and a battle has many (2) players. The way
to handle a many-to-many relationship is to create an intermediate
table that each table has a one-to-many relationship with. Don't you
think that is a better way to handle this?
   

Copyright © 2006 knowledge-database   -   All rights reserved