2010-11-05 62 views
2

我試圖按700個符號的每日回報率進行排名。MySQL按每天的價值排名

例如:

date  symbol pct_return 
----------------------------- 
1100101 IBM  1.2 
1100101 AAPL  2.1 
1100101 HPQ  -0.5 

約700多個條目,這樣的日期1100101

1100102 IBM  -.02 
1100102 AAPL  -.6 
1100102 HPQ  1.9 

約700多個條目,這樣的日期1100102

我所試圖做的是創建一個查詢或存儲過程來循環每一天,然後對每個符號在每一天內的百分比回報進行排名和插入排名值。

我想爲百分比回報的升序和降序排名插入排名值。排名後僅僅3個符號

樣品表看起來像:

date  symbol pct_return rank_asc rank_desc 
------------------------------------------------------ 
1100101 IBM  1.2    2   2 
1100101 AAPL  2.1    3   1 
1100101 HPQ  -0.5   1   3 
1100102 IBM  -.02   2   2 
1100102 AAPL  -.6    1   3 
1100102 HPQ  1.9    3   1 
+0

請提供該表的CREATE TABLE語句。 – 2010-11-05 20:42:25

+0

CREATE TABLE'T_0_ranked2'( 'date' int(11)default NULL, 'sym' varchar(8)default NULL, 'pct_return' decimal(8,2)default NULL, 'event_id' int(10) unsigned NOT NULL, 使用BTREE的主鍵('event_id') )ENGINE = MyISAM DEFAULT CHARSET = latin1; (1100101,'IBM','1.20',1),(1100101,'AAPL','2.10',2),(1100101,'HPQ',' - 0.50',3)插入'T_0_ranked2'VALUES ,(1100102, 'IBM', ' - 0.02',4),(1100102, 'AAPL', ' - 0.60',5),(1100102, 'HPQ', '1.90',6); – 2010-11-05 21:44:46

回答

0

這是組內集合的典型問題,這是左自排斥加入解決。

你不需要任何存儲過程來獲得你想要的結果,只是一個簡單的INSERT INTO ... SELECT ...查詢就可以做到。

這裏是與所提供的數據的示例腳本:

 
CREATE TABLE shuffled_symbols ( 
    dat INT NOT NULL 
    ,symbol VARCHAR(4) NOT NULL 
    ,pct_return DECIMAL(4,2) NOT NULL 
    ,PRIMARY KEY (dat ,symbol) 
); 
CREATE TABLE ranked_symbols ( 
    dat INT NOT NULL 
    ,symbol VARCHAR(4) NOT NULL 
    ,pct_return DECIMAL(4,2) NOT NULL 
    ,rank_asc INT UNSIGNED NOT NULL 
    ,rank_desc INT UNSIGNED NOT NULL 
); 

INSERT INTO shuffled_symbols (dat,symbol,pct_return) VALUES (1100101,'IBM',1.2); 
INSERT INTO shuffled_symbols (dat,symbol,pct_return) VALUES (1100101,'AAPL',2.1); 
INSERT INTO shuffled_symbols (dat,symbol,pct_return) VALUES (1100101,'HPQ',-0.5); 
INSERT INTO shuffled_symbols (dat,symbol,pct_return) VALUES (1100102,'IBM',-0.02); 
INSERT INTO shuffled_symbols (dat,symbol,pct_return) VALUES (1100102,'AAPL',-0.6); 
INSERT INTO shuffled_symbols (dat,symbol,pct_return) VALUES (1100102,'HPQ',1.9); 

這裏是計算行列查詢(對不起,壞的格式,我無法把它裏面<pre>標籤正確顯示):

INSERT INTO ranked_symbols ( dat, symbol, pct_return, rank_asc, rank_desc ) SELECT ars.dat, ars.symbol, ars.pct_return, ars.rank_asc, COUNT(ss3.dat)+1 rank_desc FROM ( SELECT ss1.dat, ss1.symbol, ss1.pct_return, COUNT(ss2.dat)+1 rank_asc FROM shuffled_symbols ss1 LEFT JOIN shuffled_symbols ss2 ON ss2.dat = ss1.dat AND ss2.pct_return < ss1.pct_return GROUP BY ss1.dat, ss1.symbol ) ars LEFT JOIN shuffled_symbols ss3 ON ss3.dat = ars.dat AND ss3.pct_return > ars.pct_return GROUP BY ars.dat, ars.symbol ;

請注意,此查詢將只返回有效的行列,如果你沒有給定日期符號的重複。這就是爲什麼我使用PRIMARY KEY (dat ,symbol)創建了shuffled_symbols表格。

在ranked_symbols表,你得到如下結果:

 
SELECT * FROM ranked_symbols; 

+---------+--------+------------+----------+-----------+ 
| dat  | symbol | pct_return | rank_asc | rank_desc | 
+---------+--------+------------+----------+-----------+ 
| 1100101 | AAPL |  2.10 |  3 |   1 | 
| 1100101 | HPQ |  -0.50 |  1 |   3 | 
| 1100101 | IBM |  1.20 |  2 |   2 | 
| 1100102 | AAPL |  -0.60 |  1 |   3 | 
| 1100102 | HPQ |  1.90 |  3 |   1 | 
| 1100102 | IBM |  -0.02 |  2 |   2 | 
+---------+--------+------------+----------+-----------+ 
6 rows in set (0.00 sec)         
+0

謝謝布魯諾!有效。不勝感激。你的筆記在點上,符號列表中沒有任何模糊,並且讚賞主鍵的使用。 – 2010-11-05 22:38:52

1

你可以使用這個語法來選擇你選擇的行號:

SELECT @row := @row + 1 as row, t.* 
FROM table t, (SELECT @row := 0) r; 

然後你可以選擇所有值與ORDER BY每天上升和下降,並將它們插入到您的表中。

來源:http://snippets.dzone.com/posts/show/6831

實施例:

INSERT INTO [your table] 
SELECT date, symbol, pct_return, @row := @row + 1 
FROM [your other table] t, (SELECT @row := 0) r 
ORDER BY pct_return ASC; 

要獲得的升值,然後在具有類似的查詢相同的表的更新,以獲得降值。

+0

布倫特,我在PERL中使用你的代碼的改編結束了。我發現它更具可擴展性和快速性。 PERL是我管理需要經歷多日的循環的最簡單方式。我將在其他評論中發佈代碼。 – 2010-11-07 03:42:50

+1

很高興我能服務。 – 2010-11-08 14:10:37

0

下面是我如何擴大對布倫特的 例如使用PERL。這對我很有幫助,我非常感謝 社區的支持。

要運行命令行代碼:

rank.pl FromTableNoRank ToTableWithRank pct_return DESC

#!/usr/bin/perl -w 

use strict; 
use warnings; 
use Carp; 

// connect to database here 

// Not enough command-line arguments, helpful error message. 
if(@ARGV!=4) { 
    die("$0 requires four arguments. 1.FromTable 2.ToTable 3.Order by value(ex.pct_return) 4.ASC (low = 1) or DESC(high = 1)\n"); 
} 

// Use variables for insert to minimize errors 
// $OrderBy is the value to rank 
// $AscDesc declares which way to rank 
my $FromTable = $ARGV[0]; 
my $ToTable = $ARGV[1]; 
my $OrderBy = $ARGV[2]; 
my $AscDesc = $ARGV[3]; 


// DateTable is table of dates for use within the insert query. Used to loop through and rank individual days. 
my $query7 = "SELECT dat FROM DateTable ORDER BY dat ASC"; 
my $sth7 = $dbh->prepare($query7) || carp DBI::errstr; 
$sth7->execute() || carp DBI::errstr; 

// Fetchrow_hashref holds all dates from date tables and while loop walks through one at a time 
// The insert sorts by a value and then a row number is added to provide a rank of values 
// The nested sth exists because need to reference $dateVar from fetchrow 
while(my $ref = $sth7->fetchrow_hashref()) { 
    my $dateVar = $ref->{dat}; 
    print "$dateVar \n"; 
    my $query6 = "INSERT INTO $ToTable 
     SELECT t.*,". '@rownum := @rownum +1' . " 
     FROM $FromTable t, ".'(SELECT @rownum := 0) r 
     WHERE dat ='."$dateVar 
     ORDER BY $OrderBy $AscDesc"; 
    my $sth6 = $dbh->prepare($query6) || carp DBI::errstr; 
    $sth6->execute() || carp DBI::errstr; 
    $sth6->finish(); 
} 

$sth7->finish(); 
$dbh->disconnect(); 
+0

這個解決方案不起作用(查詢,而不是PERL代碼),因爲它給你一個行號,而不是一個等級,也就是說如果你有兩個符號具有相同的pct_return,它將以一個隨機順序排序並返回一個不同的爲每個排名。 – 2010-11-07 07:40:40

+0

你的權利,布魯諾。謝謝你指出。當我在查詢中遇到一些規模問題並且它會掛起時,我的數據庫中有超過200,000個條目。我編寫了PERL代碼以正確的方向移動。我不確定如何優雅地提出可擴展的解決方案。思考? – 2010-11-08 21:51:33