2017-04-06 70 views
1

我有一個查詢返回令牌具有特定分類的概率。使用SQLite將組中的行相乘

token  class  probPaired 
---------- ---------- ---------- 
potato  A   0.5 
potato  B   0.5 
potato  C   1.0 
potato  D   0.5 
time  A   0.5 
time  B   1.0 
time  C   0.5 

我需要將每個class的概率乘以它們的總和。

-- Imaginary MUL operator 
select class, MUL(probPaired) from myTable group by class; 

class  probability 
---------- ---------- 
A   0.25 
B   0.5 
C   0.5 
D   0.5 

如何在SQLite中執行此操作? SQLite沒有像LOG/EXP或變量的功能 - 解決方案mentioned in other questions

+0

@GurV這些問題的答案並不適用於SQLite的,[它缺乏LOG或EXP(https://sqlite.org/lang_corefunc.html)實施變通。 – Schwern

回答

1

您可以計算行號,然後使用遞歸cte進行乘法運算。然後獲得包含最終乘法結果的每個類的最大rnum(計算的row_number)值。

--Calculating row numbers 
with rownums as (select t1.*, 
       (select count(*) from t t2 where t2.token<=t1.token and t1.class=t2.class) as rnum 
       from t t1) 
--Getting the max rnum for each class 
,max_rownums as (select class,max(rnum) as max_rnum from rownums group by class) 
--Recursive cte starts here 
,cte(class,rnum,probPaired,running_mul) as 
    (select class,rnum,probPaired,probPaired as running_mul from rownums where rnum=1 
    union all 
    select t.class,t.rnum,t.probPaired,c.running_mul*t.probPaired 
    from cte c 
    join rownums t on t.class=c.class and t.rnum=c.rnum+1) 
--Final value selection 
select c.class,c.running_mul 
from cte c 
join max_rownums m on m.max_rnum=c.rnum and m.class=c.class 

SQL Fiddle

2

一般來說,如果SQLite無法做到這一點,您可以改爲編寫自定義函數。細節取決於你使用的是什麼編程語言,在Perl中使用DBD::SQLite。請注意,以這種方式創建的函數不是存儲過程,它們存在於該連接中,並且每次連接時都必須重新創建。

對於聚合函數,您必須創建一個處理聚合的類。 MUL非常簡單,只是存儲產品的一個對象。

{ 
    package My::SQLite::MUL; 

    sub new { 
     my $class = shift; 
     my $mul = 1; 
     return bless \$mul, $class; 
    } 

    sub step { 
     my $self = shift; 
     my $num = shift; 

     $$self *= $num; 

     return; 
    } 

    sub finalize { 
     my $self = shift; 

     return $$self; 
    } 
} 

然後,您將安裝它作爲聚合函數MUL它採用一個參數,並使用該類。

my $dbh = ...doesn't matter how the connection is made... 

$dbh->sqlite_create_aggregate("MUL", 1, "My::SQLite::MUL"); 

現在您可以在查詢中使用MUL

my $rows = $dbh->selectall_arrayref(
    "select class, MUL(probPaired) from myTable group by class" 
); 

同樣,細節會因您的特定語言而有所不同,但基本思路是相同的。

這比獲取每一行並獲取聚合產品要快得多。