2013-05-10 68 views
-1

如何使用值爲循環的列(即1,2,3,1,2,3,1,2,3 ....)來計算並輸出循環的索引號? 因此,例如在這個簡化表...如何處理循環列以在SQL中輸出循環編號?

num cir 
1 1 
2 2 
3 3 
4 1 
5 2 
6 3 
7 1 
8 2 
9 3 

如何我能得到這個?

num cir index 
1 1 1 
2 2 1 
3 3 1 
4 1 2 
5 2 2 
6 3 2 
7 1 3 
8 2 3 
9 3 3 

其實,我試圖管理表十分巨大(數百萬條記錄時間160列),所以如果有多個解決方案,我想聽聽更高效的...謝謝。

+1

它看起來像指數剛好等於地板((NUM - 1)/ 3)+ 1,除非我失去了一些東西? – bengoesboom 2013-05-10 19:22:50

+0

糟糕。我只是補充了'num'列以避免一個表僅由一列組成!其實num不是一個有序的。對不起。 – Blaszard 2013-05-10 19:28:03

+4

表格沒有以任何特定的順序存儲,所以如果不在'num'上排序,應該如何確定給定記錄屬於哪個組?你試圖解決的問題的更廣泛的背景是什麼? – eggyal 2013-05-10 19:29:15

回答

1

假設num1是有序的(儘管可能有間隙),解決此問題的一種方法是根據找到較小值num的迴路編號的次數來分配索引。我想在MySQL中做到這一點最明顯的方法是使用相關子查詢:

select t.*, 
     (select count(*) from t t2 where t2.cir = t.cir and t2.num <= t.num 
     ) as `index` 
from t 

如果num沒有排序,那麼你有問題。 SQL表本質上是無序的,所以對於給定的行沒有「之前」和「之後」的概念。也就是說,除非您有某種方式對結果進行排序,否則沒有可靠的方法來分配索引。

+0

顯然'num'沒有很好的順序(就這個循環數而言,我們可以想象)。 – eggyal 2013-05-10 19:40:56

+0

@eggyal。 。 。我接受了這個評論意味着公式floor((num-1)/ 3)+ 1)'不起作用。 OP應該澄清。 – 2013-05-10 19:43:04

+0

很抱歉有很多混淆,但完全忘記了'num'。其實,我想要處理的是棒球的擊球陣容。所以'cir'的範圍從1到9,我希望每次通過order表示'index',通常範圍是1到5.我可以用來顯示'index'的唯一列是'cir'。你上面說的OP是什麼? – Blaszard 2013-05-10 20:08:24

0

嘗試用非接下來cirsakes和他們的計數這個自聯接:

SELECT t1.num AS num, t1.cir AS cir, COUNT(*) AS index 
    FROM t AS t1 JOIN t AS t2 on t2.cir = t1.cir AND t2.num <= t1.num 
    GROUP BY t1.num, t1.cir 
; 
+0

請注意,OP表示該表包含「數百萬」記錄 - 因此,您的結果集將包含* trillions *(10^12)條記錄(聚合成數百萬行)。 – 2013-05-11 12:26:47

3

Gordon Linoff is right:在SQL,表確實沒有內在的順序。但是,仍然有一種方法可以爲您的案例分配索引。唯一的問題是,這個命令是不確定的,一個1可能與一個2組合在一起,不一定是跟隨它的那個(按照您可能期望的任何特定順序)。也就是說,最終結果可能與您的示例類似:

num cir index 
--- --- ----- 
1 1 1 
2 2 1 
3 3 1 
4 1 2 
5 2 2 
6 3 2 
7 1 3 
8 2 3 
9 3 3 

但它很可能是例如這個代替:

num cir index 
--- --- ----- 
7 1 1 
2 2 1 
3 3 1 
4 1 2 
8 2 2 
6 3 2 
1 1 3 
5 2 3 
9 3 3 

如果num不是「秩序井然」,因爲你把它(因此,我假設,不能用於排序)。

的想法是排序的cir列中的數據集只

num cir 
--- --- 
1 1 
4 1 
7 1 
2 2 
5 2 
8 2 
3 3 
6 3 
9 3 

,然後用變量賦值來產生index

num cir    index 
--- ---    ----- 
1 1 1    1 
4 1 2    2 
7 1 3    3 
2 2  1  -> 1 
5 2  2   2 
8 2  3   3 
3 3   1  1 
6 3   2  2 
9 3   3  3 

方法如下:

SELECT 
    num, 
    cir, 
    `index` 
FROM (
    SELECT 
    num, 
    @index := @index * (cir = @lastcir) + 1 AS `index`, 
    @lastcir := cir AS cir 
    FROM 
    yourtable, 
    (SELECT @index := 0, @lastcir := 0) v 
    ORDER BY 
    cir 
) s 
ORDER BY 
    `index`, 
    cir 
; 

可以猜到,這個表達式

@index := @index * (cir = @lastcir) + 1 

是分配索引的那個。基本上,如果你刪除* (cir = @lastcir)部分,你會得到

@index := @index + 1 

這可能不需要解釋:它只是增加了@index值。

每當遇到新的cir值時(還記得,數據集是在cir上排序的),還有一點需要重新設置枚舉。在MySQL中,布爾表達式(如cir = @lastcir)在預期數字的上下文中隱式轉換爲數字,就像算術表達式的上下文一樣。更具體地說,對於true將其轉換爲1,對於false將其轉換爲0。因此,只要cir等於@lastcir(即以前行的cir),該index表達基本上等同於@index := @index + 1,但是當cir@lastcir不同(這意味着我們剛剛遇到一個新的cir組),表達實際上變成@index := 0 + 1,即枚舉現在重新開始。

如果你願意,你可以測試這個解決方案at SQL Fiddle

+2

+1。 。 。你在排序中澄清問題做得非常好。我討厭表格被排序的假設,因爲它似乎在小數據集上的實踐中起作用。但是它可能會在並行機器上以及插入和刪除的數據上失敗。 – 2013-05-11 15:29:31

+0

謝謝。我仍然需要花更多的時間學習你的代碼,所以我只是試着在這個時候運行它,但是它按照我的預期工作。 – Blaszard 2013-05-12 15:53:17

0

試試這個

SELECT 
    num, 
    cir, 
    @row_num := IF(@prev_cir<cir,@row_num,@row_num+1) as cir_index, 
    @prev_cir:= cir 
FROM 
(SELECT @row_num := 0) r 
JOIN (
    SELECT 
     num, 
     cir 
    FROM 
     mytable 
    ORDER BY 
     num 
) t 

首先,我要確保記錄被num排序。然後我chk如果以前cir與當前一個。如果以前cir是比當前更大,我遞增cir_index

SQLFIDDLE