使用SQLite将组中的行相乘

时间:2017-04-06 18:11:24

标签: sql 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等功能。

2 个答案:

答案 0 :(得分:2)

通常,如果SQLite不能这样做,您可以编写自定义函数。详细信息取决于您使用的编程语言,这里使用DBD::SQLite在Perl中。请注意,以这种方式创建的函数不是存储过程,它们存在于该连接中,每次连接时都必须重新创建。

对于聚合函数,您必须创建一个处理聚合的类。 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"
);

同样,细节会因您的特定语言而有所不同,但基本想法将是相同的。

这比获取每一行并获取聚合产品要快得多。

答案 1 :(得分:1)

您可以计算行数,然后使用递归cte进行乘法运算。然后获取包含乘法最终结果的每个类的max 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