Domanda

Ho una tabella postgresql che è per lo più un tavolo del ponte ma ha anche alcune cose extra.

Essenzialmente contiene le informazioni sui giocatori in un gioco. Quindi abbiamo un ID unico per questo caso di un giocatore in un gioco. Quindi un ID che è FK al tavolo da gioco e un ID che è FK a Player Table. Ci sono anche altre cose irrilevanti. Qualcosa del genere:

Table players_games
| id        | 12564
| player_id | 556
| game_id   | 156184
.

Quello che voglio fare è trovare quanti occasioni ci sono di un giocatore che gioca con un altro. Quindi, se il giocatore1 è nello stesso gioco di Player2, hanno giocato insieme una volta. Ci sono 2+ giocatori in un gioco.

Quindi quello che voglio fare è popolare una nuova tabella, che contiene tre valori: Player_lo, Player_hi, Times_Played.

E avere una riga per ogni coppia e il numero di volte in cui hanno giocato, o se finisce per essere più efficiente, una riga per ogni iterazione e avere il valore impostato come 1 in modo che questi possano essere aggiunti insieme in seguito, forse distribuiti . Quindi potresti vedere qualcosa come:

p1, p2, 1
p1, p2, 1
.

E questi sono ridotti più tardi a:

p1, p2, 2
.

Quindi mi stavo chiedendo se ci fosse un certo modo intelligente per farlo con SQL, o se c'è SQL che può ridurre il mio sforzo di programmazione, prima di iniziare a scrivere uno script Python leggermente complesso per farlo.

È stato utile?

Soluzione

Per fare questo, devi fare un self-join sulla tabella Player_Games.Il primo sottoquery è per il primo giocatore e il secondo per il secondo giocatore.Il giocatore "Primo" è quello con l'ID del giocatore inferiore.

select pg1.player_id as player1, pg2.player_id as player2, count(*) as num_games
from (select distinct game_id, player_id
      from  players_games pg
     ) pg1 join
     (select distinct game_id, player_id
      from players_games pg
     ) pg2
     on pg1.game_id = pg2.game_id and
        pg1.player_id < pg2.player_id
group by pg1.player_id, pg2.player_id
.

Nota che la condizione di join utilizza un "<" su ID del lettore.Questo per prevenire il conteggio dei duplicati (quindi i giocatori A, B non sono anche contati come B, A).

Inoltre, ho aggiunto un "distinto" nei sottoqueri interni nel caso in cui un singolo giocatore potrebbe apparire più di una volta per un dato gioco.Forse questo non è necessario.Per essere sicuro, dovresti avere un indice unico sul tasto composito Game_id, Player_id.

Altri suggerimenti

select p1, p2, count(*) from (
    select 
      pg1.player_id as p1, pg1.game_id, pg2.player_id as p2
    from
      players_games pg1, players_games pg2
    where
      pg1.game_id = pg2.game_id and pg1.player_id != pg2.player_id
) foo
group by p1, p2
.

Nota che questo fa un full join su players_games in modo da poter essere molto lento se il tavolo è grande.La parte chiave è il group by per ottenere il conteggio.

SET search_path='tmp';
DROP TABLE players_game CASCADE;
CREATE TABLE players_game
        ( game_id INTEGER NOT NULL
        , player_id INTEGER NOT NULL
        );
INSERT INTO players_game(game_id,player_id) VALUES
 (1,100) ,(1,101) ,(2,100) ,(2,101)
,(3,100) ,(3,101) ,(4,102) ,(4,101)
        ;

WITH pair AS (
    SELECT g1.player_id AS p1
     , g2.player_id AS p2
    FROM players_game g1
    JOIN players_game g2 ON g1.game_id = g2.game_id
    WHERE g1.player_id < g2.player_id
    )
SELECT pa.p1 , pa.p2, COUNT(*) AS num_games
FROM pair pa
GROUP BY p1, p2
ORDER BY num_games DESC
        ;
.

Risultato:

SET
ERROR:  table "players_game" does not exist
CREATE TABLE
INSERT 0 8
 p1  | p2  | num_games 
-----+-----+-----------
 100 | 101 |         3
 101 | 100 |         3
 102 | 101 |         1
 101 | 102 |         1
(4 rows)
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top