SQL - 从多个列中分配/减去列

时间:2016-01-24 09:46:21

标签: sql postgresql google-bigquery

我有一个名为wallet的表,它记录所有钱包交易。假设用户可以通过4种方式向钱包添加资金,即credit_src1,credit_src2,credit_src3,credit_src4,我有各自的列。此外,用户可以从他们的帐户中扣款,因此我有一个与之对应的列。 信用卡或借记卡的每笔交易都记录在具有相应交易ID的表中。用户只能对事务ID执行一次操作。

当用户从钱包借记时,我想检索每个信用来源中剩余的相应金额。假设从每个来源平均扣除金额。如果金额在一列中达到0,则会从剩余列中平均扣除,直到达到0。

这是源表:

ID    src1    src2    src3   src4    debit
==========================================
1     10      0       0      0       0
2     10      0       0      0       0
3     0       50      0      0       0
4     0       0       40     0       0
5     0       0       0      0       30
6     0       0       0      0       70

目的地表应该是所有来源的累积总和减去每个来源的相等借方:

ID    src1    src2    src3   src4    debit
==========================================
1     10      0       0      0       0
2     20      0       0      0       0
3     20      50      0      0       0
4     20      50      40     0       0
5     10      40      30     0       30
6     0       20      10     0       70

我可以使用此查询从各种来源获得一笔钱

SELECT
SUM(src1) OVER (ORDER BY ID),
SUM(src2) OVER (ORDER BY ID),
SUM(src3) OVER (ORDER BY ID),
SUM(src1) OVER (ORDER BY ID)
FROM wallet

我无法弄清楚如何在所有来源之间平均分配借记金额。任何形式的帮助将不胜感激。

http://sqlfiddle.com/#!15/893c6/4

1 个答案:

答案 0 :(得分:2)

BigQuery及其BQL非常强大,可以克服一些评论中提到的限制问题!至少在某些情况下喜欢这个。所以...

以下是您正在寻找的内容。 使用JS UDF

完全在BigQuery中
SELECT id, src1, src2, src3, src4, debit FROM JS(
// input table
(
  SELECT GROUP_CONCAT(tx) AS txs 
  FROM (
    SELECT CONCAT(STRING(id), '|' , STRING(src1), '|' , 
                  STRING(src2), '|' , STRING(src3), '|' , 
                  STRING(src4), '|' , STRING(debit)
           ) AS tx
    FROM wallet
    ORDER BY id
  )
) ,
// input columns
txs,
// output schema
"[
{name: 'id', type: 'integer'},
{name: 'src1', type: 'integer'},
{name: 'src2', type: 'integer'},
{name: 'src3', type: 'integer'},
{name: 'src4', type: 'integer'},
{name: 'debit', type: 'integer'}
]",
// function
"function(r, emit){
  var tx_list = r.txs.split(',');
  var src1_total = 0;
  var src2_total = 0;
  var src3_total = 0;
  var src4_total = 0;
  var id  = 0;
  var debit = 0;
  var cut = 0;

  for (var i = 0; i < tx_list.length; i ++){
    var src = tx_list[i].split('|');

    id = parseInt(src[0]);
    src1_total += parseInt(src[1]);
    src2_total += parseInt(src[2]);
    src3_total += parseInt(src[3]);
    src4_total += parseInt(src[4]);
    debit = parseInt(src[5]);
    cut = debit;

    while (cut > 0) {
      if (src1_total > 0 && cut > 0) {src1_total--; cut--;}
      if (src2_total > 0 && cut > 0) {src2_total--; cut--;}
      if (src3_total > 0 && cut > 0) {src3_total--; cut--;}
      if (src4_total > 0 && cut > 0) {src4_total--; cut--;}
    }

    emit({
      id: id, src1: src1_total, src2: src2_total,
      src3: src3_total, src4: src4_total, debit: debit
    });
  }

}"
)

输出:

id  src1    src2    src3    src4    debit    
1     10       0      0        0       0     
2     20       0      0        0       0     
3     20      50      0        0       0     
4     20      50     40        0       0     
5     10      40     30        0      30     
6      0      10      0        0      70     

请注意:以上解决方案不够灵活。取决于您的桌子(钱包)的大小(行数),您迟早会看到它。并密切关注生产层,因为随着行的增长它可能会变高。

我的建议:万一你要提到上面提到的限制 - 你应该编写类似于你在你选择的客户端上看到的udf代码的逻辑