2016-10-21 52 views
1

在PostgreSQL 9.5.4我一直播放器的相關信息,從各種社會網絡:在CTE表減少的記錄數

# TABLE words_social; 

    sid | social | female | given | family | photo | place | stamp | uid 
-------+--------+--------+---------+--------+-------+-------+------------+----- 
aaaaa |  1 |  0 | Abcde1 |  |  |  | 1470237061 | 1 
aaaaa |  2 |  0 | Abcde2 |  |  |  | 1477053188 | 1 
aaaaa |  3 |  0 | Abcde3 |  |  |  | 1477053330 | 1 
kkkkk |  3 |  0 | Klmnop3 |  |  |  | 1477053810 | 2 
kkkkk |  4 |  0 | Klmnop4 |  |  |  | 1477053857 | 2 
ggggg |  2 |  0 | Ghijk2 |  |  |  | 1477053456 | 3 
ggggg |  3 |  0 | Ghijk3 |  |  |  | 1477053645 | 3 
ggggg |  4 |  0 | Ghijk4 |  |  |  | 1477053670 | 3 
xxxxx |  4 |  0 | Xyzok |  |  |  | 1470237393 | 4 
(9 rows) 

的1,2,3,在social 4個的值表示 「臉譜」,「推特」等

對於一個球員,我總是可以選擇她最近的信息:

# select * from words_social s1 WHERE stamp = 
     (SELECT max(stamp) FROM words_social s2 WHERE s1.uid = s2.uid); 

    sid | social | female | given | family | photo | place | stamp | uid 
-------+--------+--------+---------+--------+-------+-------+------------+----- 
aaaaa |  3 |  0 | Abcde3 |  |  |  | 1477053330 | 1 
kkkkk |  4 |  0 | Klmnop4 |  |  |  | 1477053857 | 2 
ggggg |  4 |  0 | Ghijk4 |  |  |  | 1477053670 | 3 
xxxxx |  4 |  0 | Xyzok |  |  |  | 1470237393 | 4 
(4 rows) 

然後是另一臺存儲CURREN牛逼的遊戲(我省略了下面的一些列):

# select gid, created, finished, player1, player2 from words_games; 

gid |   created   | finished | player1 | player2 
-----+-------------------------------+----------+---------+--------- 
    1 | 2016-10-21 14:51:12.624507+02 |   |  4 |  1 
    2 | 2016-10-21 14:51:22.631507+02 |   |  3 | 
(2 rows) 

每當用戶(例如使用uid 1)連接到服務器,我送她,她正在參與的遊戲:

# select  gid, created, finished, player1, player2 from words_games where player1 = 1 
    union select gid, created, finished, player2, player1 from words_games where player2 = 1; 

gid |   created   | finished | player1 | player2 
-----+-------------------------------+----------+---------+--------- 
    1 | 2016-10-21 14:51:12.624507+02 |   |  4 |  1 
(1 row) 

我的問題:對於上面的UNION SELECT語句,我需要從words_social表中添加用戶信息 - 以便我可以在我的2人遊戲中顯示用戶照片和遊戲板上方的名稱。

所以我嘗試這與CTE(以及與用戶的名字添加i.given列):

# with user_infos AS (select * from words_social s1 WHERE stamp = 
     (SELECT max(stamp) FROM words_social s2 WHERE s1.uid = s2.uid)) 
select  g.gid, g.created, g.finished, g.player1, g.player2, i.given from words_games g join user_infos i on (g.player1=i.uid) where g.player1 = 1 
union select g.gid, g.created, g.finished, g.player2, g.player1, i.given from words_games g join user_infos i on (g.player2=i.uid) where g.player2 = 1; 

gid |   created   | finished | player1 | player2 | given 
-----+-------------------------------+----------+---------+---------+-------- 
    1 | 2016-10-21 14:51:12.624507+02 |   |  1 |  4 | Abcde3 
(1 row) 

這個效果很好,但我還是有以下問題 -

我擔心CTE表user_infos會變得非常大,一旦我的遊戲有很多玩家。

如何重寫查詢,以便user_infos只保存相關記錄?

我不能只是執行

# with user_infos AS (select * from words_social s1 WHERE stamp = 
     (SELECT max(stamp) FROM words_social s2 WHERE s1.uid = s2.uid)) 
     AND s1.uid = 1 
     ... 

,因爲我還需要比賽的對手的相關信息(名字和姓氏,照片)。

回答

1

你應該用另一種方式包裝它。

word_games開始,然後加入words_social表。

也可以使用dinstinct on(postgres特定)函數來避免第二次查找表。

那麼到底:

with game_finder as (
select g.gid, g.player1, g.player2 
from words_games g where g.player1 = 1 
union 
select g.gid,g.player2, g.player1 
from words_games g where g.player2 = 1), 
player1_infos as (
select distinct on (uid) 
    gf.gid, 
    uid, 
    social, 
    given 
from words_social ws 
inner join game_finder gf on gf.player1 = ws.uid 
ORDER BY uid, stamp DESC 
), 
player2_infos as (
select gf.gid, 
    uid, 
    social, 
    given 
from words_social ws 
inner join game_finder gf on gf.player2 = ws.uid 
ORDER BY uid, stamp DESC 
) 
select * 
from game_finder gf 
left outer join player1_infos p1 on gf.gid = p1.gid 
left outer join player2_infos p2 on gf.gid = p2.gid; 
+1

好,你也可以使用橫向連接,也就是比明顯快ON子句(也特定於postgresql) – Nemeros

+0

謝謝! 'player2_infos'中缺少'(uid)'的特徵嗎? –

+1

對不起,否則你將會爲同一用戶重複一行 – Nemeros

2

user_infos查詢可以被改寫,使用如下:

with user_infos as (
    select row_number() over (partition by uid order by stamp desc), * from words_social 
) 
select g.gid, g.created, g.finished, g.player1, g.player2, i.given from words_games g 
join user_infos i on g.player1=i.uid and i.row_number = 1 and g.player1 = 1 
union select g.gid, g.created, g.finished, g.player2, g.player1, i.given from words_games g 
join user_infos i on g.player2=i.uid and i.row_number =1 and g.player2 = 1;