2015-05-26 20 views
0

我對SQL相當陌生,並試圖根據3個非常大的數據庫表計算新的字段。下面是一個抽象:從多個表中計算日期的新字段:更新或過程?

  • 表1:玩家(包含生日字段)
  • 表2:比賽(包含DATETIME場)
  • 表3:遊戲(有外鍵引用players.id和tournaments.id)

我想在遊戲桌上添加一個字段,其中包含比賽當天玩家年齡的十進制表示。

我需要編寫一個過程/操作循環來完成這個嗎?或者有沒有辦法用更新查詢來做到這一點?

+0

你確定你想存儲的計算值嗎?如果出生日期得到糾正或比賽重新安排,你會處理更新計算器編輯年齡字段? –

+0

它可能並不理想,但爲了簡單和性能(在進行統計時),我想在此情況下存儲它。我不希望對出生日期進行更改(在我很少的情況下,我會再次更新該領域),並且比賽全部結束,因此不會進行重新安排。 – user3925713

+0

您可能想看看使用TIMESTAMPDIFF函數的官方文檔中的年齡計算:http://dev.mysql.com/doc/refman/5.0/en/date-calculations.html。這只是一個整數。如果你需要精確的計算,看看這裏的算法:http://stackoverflow.com/a/30377142/4665459 –

回答

1

您可以使用UPDATE語句做到這一點。 (但是,你真的想嗎?)

首先,寫出SELECT聲明,它會給你結果。

SELECT g.player_id 
    , g.tournament_id 
    , p.birthday 
    , t.tournament_date 
    , DATEDIFF(t.tournament_date,p.birthday) AS days_diff 
    FROM games g 
    JOIN player p ON p.id = g.player_id 
    JOIN tournament t ON t.id = g.tournament_id 

只需添加一個表達式,執行您要執行的計算並將其作爲列返回。

然後,您可以將該SELECT語句用作UPDATE語句中的內聯視圖。假設你已經添加了一個age_in_days列到games

UPDATE games d 
    JOIN ( 
     SELECT g.player_id 
       , g.tournament_id 
       , p.birthday 
       , t.tournament_date 
       , DATEDIFF(t.tournament_date,p.birthday) AS days_diff 
      FROM games g 
      JOIN player p ON p.id = g.player_id 
      JOIN tournament t ON t.id = g.tournament_id 
     ) s 
    ON s.player_id  = d.player_id 
    AND s.tournament_id = d.tournament_id 
    SET s.age_in_days = s.days_diff 

接下來,我們必須要關注「大」表,並避免產生回退的船載貨量(如果它們是一個巨大的交易InnoDB表)。

如果這是一個問題,打破它,通過在聯視圖的查詢中添加一個謂詞,例如,WHERE g.player_id = 42,並運行相同的更新,每進行一次player_id做「批處理」的更新操作。


如果你想在「十進制年份」年齡,你需要開發一個表達式來返回它。 (作爲一個基本的近似,通過幾天的一年365.25數除以天數的差異。這將讓你非常接近。)


(在我的答案的時候,我問,你真的想。

要注意的是,如果一個球員birthday值被更新或tournament_date改變時,存儲在games表的計算值將是不一致的。

+0

真棒!謝謝。我不知道你可以加入查詢而不是表格。 (正如我所說,我是新的XD) – user3925713

+0

請注意內聯視圖和性能影響。 ('SELECT'查詢包裝在parens中,被視爲一個表格,MySQL將其稱爲「派生表格」,查詢結果被物化爲一個「臨時」表格,然後外部語句針對「臨時「table。因爲它與實際的'TEMPORARY TABLE'不同,所以我暫時放在引號中。)還有其他的查詢模式可以使用,我只舉了一個方法的例子。 – spencer7593

0

你可以試試這個

Update games 
set age = (SELECT FLOOR(DATEDIFF(DAY, players.BirthDate, tournaments.datetime)/365.25) from players,tournaments) 
where players.id=games.id;