2017-06-14 63 views
1

我有一個類似於下面的例子的MySQL問題。MySQL嵌套表記錄編號

  • 有兩張人名姓名錶,由他們的護照號碼標識第一張桌子上有父母。
  • 第二個表有CHILDREN,與他們的父母護照ID相關聯(我只考慮父母一方 - 父母/每個家庭)。
  • 較低的護照ID值意味着一個年輕的人(因此,最年輕的父母具有最低的ID;而第一個孩子出生在一個家庭有孩子中是最低的ID在該家族)

實例表:

父母

PassportID – ParentNAME 

098765432 – Kate 
– John 
111222333 – Mary 

兒童

PassportID – ChildNAME – ParentID 

211222333 – Peter – 111222333 
222333444 – Gabriel –
222222222 – Lara – 111222333 
233333333 – Angela –
244444444 – Philip –
255555555 – Michael – 111222333 
277777777 – Betty – 098765432 
266666666 – Eleanor – 098765432 
299999999 – Amanda – 111222333 
288888888 – Robert – 111222333 

我知道如何加入,這些表進行排序,採用原始ID:

HTTP:sqlfiddle.com /#9/98b5a/1/0

出於某種原因SQLfiddle開始失敗,所以我再次在這個其他很酷的MySQL測試中的例子: http://rextester.com/EYIX74197

但我想顯示簡單的增長數字,而不是顯示原始ID。所以,問題是:

我怎樣才能做一個選擇來自這兩個表,並得到所有這些人拿着幾自動編號列的這顯示人們的基於1的年齡排名的列表,在此方法:

  • 最古老的家長將有秩= 1,下一個,秩= 2,和
  • 所以 並在每個家庭中最古老的孩子將有秩= 1,未來 一個2,等等。

結果舉例:

ParentAgeRANK - ParentNAME – ChildBornRANK – ChildNAME 

1 – John – 1 – Gabriel 
1 – John – 2 – Angela 
1 – John – 3 – Philip 
2 – Kate – 1 – Eleanor 
2 – Kate – 2 – Betty 
3 – Mary – 1 – Peter 
3 – Mary – 2 – Lara 
3 – Mary – 3 – Michael 
3 – Mary – 4 – Robert 
3 – Mary – 5 – Amanda 

我想我會需要使用一對夫婦的MySQL變量,@ParentAgeRank和@ChildBornRank的,設置它們的原始值0,再總結各1行,但只有在父ID改變時(在第一種情況下)或者子ID改變(在第二種情況下)。但是,當父id改變時,@ChildBornRank必須重置爲0。 我會知道如何使用PHP腳本來完成此操作,該腳本可以使用PHP變量來評估PassportID並增加排名。

但在這種情況下,我被迫使用純MySQL語句獲得排名列表。

這個想法甚至可能嗎?當另一個變量的值改變時如何處理重置一個變量?

非常感謝你的建議

編輯:

雖然我的例子中只有10行,這是爲了從兩個表約10萬條記錄每一個運行。

@Parfait提供的第一個解決方案的確可以使用幾行;但是當我在現實世界中嘗試它時,我的服務器會掛起。

通過@Parfait第2解決方案做了回「磁盤已滿」錯誤信息,所以我想這是關係到1日評論中的東西這個頁面(太多連接和GROUP BY語句):https://dev.mysql.com/doc/refman/5.7/en/full-disk.html

+0

您的可變意見將比以下提供的第一個(迄今爲止)解決方案更有效率 – Strawberry

+0

感謝您的意見@Strawberry。但關於如何照顧變化和重置的任何想法? – abu

回答

1
SELECT CASE WHEN @prev = x.parent_id THEN @i:[email protected] ELSE @i:[email protected]+1 END parentrank 
    , x.parentname 
    , CASE WHEN @prev = x.parent_id THEN @j:[email protected]+1 ELSE @j:=1 END childrank 
    , x.childname 
    , @prev:=parent_id 
    FROM (SELECT p.passportid parent_id 
      , p.parentname 
      , c.passportid child_id 
      , c.childname 
     FROM parents p 
     JOIN children c 
      ON c.parentid = p.passportid 
     ) x 
    JOIN (SELECT @prev:=null,@i:=0,@j:=0) vars 
ORDER 
    BY x.parent_id 
    , x.child_id; 
+------------+------------+-----------+-----------+------------------+ 
| parentrank | parentname | childrank | childname | @prev:=parent_id | 
+------------+------------+-----------+-----------+------------------+ 
|   1 | John  |   1 | Gabriel |   12345678 | 
|   1 | John  |   2 | Angela |   12345678 | 
|   1 | John  |   3 | Philip |   12345678 | 
|   2 | Kate  |   1 | Eleanor |   98765432 | 
|   2 | Kate  |   2 | Betty  |   98765432 | 
|   3 | Mary  |   1 | Peter  |  111222333 | 
|   3 | Mary  |   2 | Lara  |  111222333 | 
|   3 | Mary  |   3 | Michael |  111222333 | 
|   3 | Mary  |   4 | Robert |  111222333 | 
|   3 | Mary  |   5 | Amanda |  111222333 | 
+------------+------------+-----------+-----------+------------------+ 
+0

太好了。這似乎至少用我簡單的表格示例工作。還沒有時間用我的大桌子來嘗試。說實話,在你發佈它的時候,我已經以類似的方式解決了我的問題,並忙於在我正在編寫的報告中包含這些數據。當我完成時,我會發布我的解決方案,如果它有某種不同,並且標記爲好,如果它更快,當然。非常感謝 !! – abu

+0

我希望你能原諒我對這個評論的真實性持懷疑態度。 – Strawberry

+0

大聲笑。我的意見哪一部分是你的意思?沒有更多的研究。草莓解決方案在2秒鐘內完成工作,因此它完全擊敗@Parfait解決方案。我已經做了或多或少像草莓一樣,但他/他之前在這裏發佈。唯一的區別是** CASE WHEN ... THEN ... END **語法。我用** IF(,,)**代替。另外,我在SET語句前設置**初始變量值,而不是使用JOIN設置它們。但實質上,它是相同的解決方案,因爲查詢,計數器和比較以相同的方式工作。非常感謝你們兩位! – abu

1

考慮相關計數子查詢:

SELECT 
    (SELECT Count(*) FROM Parents sub 
    WHERE sub.PassportID <= p.PassportID) AS ParentRANK, 

    p.PassportID As ParentID, p.ParentNAME, 

    (SELECT Count(*) FROM Children sub 
    WHERE sub.PassportID <= c.PassportID 
    AND sub.ParentID = c.ParentID) AS ChildRANK, 

    c.PassPortID As ChildID, c.ChildNAME  

FROM Parents p 
INNER JOIN Children c 
    ON p.PassportID = c.ParentID 

SQL Fiddle


使用替代

0表和COUNT(DISTINCT ...))在彙總查詢的排名:

SELECT 
     Count(DISTINCT subP.PassportID) AS ParentRANK, 
     p.PassportID As ParentID, p.ParentNAME,   
     Count(DISTINCT subC.PassportID) AS ChildRANK,   
     C.PassPortID As ChildID, c.ChildNAME 

FROM Parents p 
INNER JOIN Children c 
    ON p.PassportID = c.ParentID 

LEFT JOIN Parents subP 
    ON subP.PassportID <= p.PassportID 

LEFT JOIN Children subC 
    ON subC.PassportID <= c.PassportID 
    AND subC.ParentID = c.ParentID 

GROUP BY p.PassportID, p.ParentName, c.PassportID, c.ChildName 
ORDER BY 1,4 

SQL Fiddle

+0

嗨。很好。非常感謝。它適用於我的示例表格。問題是我的真實表格要大得多(我的服務器現在已經運行了10分鐘的查詢並且仍然沒有結果)。我編輯了我原來的答案。你能提出一個消耗更少資源的改進方案嗎? – abu

+0

使用'JOIN'表查看更新的替代版本。讓我知道這是否更有效。 – Parfait

+0

我無法運行你的第二個SQL小提琴示例@Parfait。這可能是一個sqlfiddle錯誤,但該頁面不會在我的瀏覽器中加載。 在任何情況下:我試圖使您的查詢適應我的真實數據庫,並且SQL服務器耗盡內存。 所以我猜這個查詢效率低於前一個;) 無論如何感謝 – abu

0

這是essentialy同樣的方式來做到這一點通過@Strawberry上面提供:https://stackoverflow.com/a/44578041/710788

我只是把我的版本,以更好地瞭解我提到的差異:

SET @prank=0, @crank=1, @curp=0, @curc=0; 

SELECT 
    if(o.Passportid<>@curp, @prank:[email protected]+1, @prank) as 'ParentRANK', 
    o.ParentName, 
    if(o.Passportid<>@curp, @crank:=1, @crank:[email protected]+1) as 'ChildRANK', 
    o.ChildName, 
    if(o.Passportid<>@curp, @curp:=o.Passportid, @curp) as 'current_P' 
FROM (
    SELECT p.Passportid,p.ParentNAME, c.PassportID as childID,c.ChildNAME,c.ParentID 
    FROM parents AS p INNER JOIN children as c on p.PassportID=c.ParentID 
    ORDER BY p.PASSPORTID,c.PassportID 
) AS o; 
與553003對父母和子女1106983速度

比較:影響

解決上述

0行,找到1106983行。 3個查詢的持續時間:7.020秒。

溶液@Strawberry影響

0行,實測1106983行。 1個查詢的持續時間:6.489秒。

注意:這些行比我最初說的我需要處理的更多。我只是添加它們來更好地測試速度差異。