通过字段的值对行进行配对的SQL

时间:2018-09-06 16:14:18

标签: sql postgresql postgresql-9.4

我有一张桌子:

create table transaction_log (
  id serial, 
  operation_type character varying(36),
  date timestamp with time zone,
  sum   double precision,
  user_id integer,
  PRIMARY KEY(id)
);

它保留两种类型的操作:blockunblock用于operation的多个用户(contragent_id)和批次(lot_id)和日期时间字段。

  • 一个用户可以执行多个阻止操作和未阻止操作
  • 具有阻止操作的记录之后可以进行一个取消阻止操作。
  • 阻止和取消阻止是顺序的。用户必须有一个阻止,下一个阻止只有在取消阻止操作发生之后。
  • 取消阻止的日期和时间可以与阻止相同。这意味着已阻止并立即解除阻止。
  • 一个用户可能在混合时间轴上具有多个阻止和取消阻止操作序列。
  • id是唯一的

例如:

id, sum, operation_type, date, user_id
1, 5900, blocked, 2018-01-05 11:00, 1
2, 3500, blocked, 2018-01-08 12:00, 2
3, 5900, unblock, 2018-02-11 09:00, 1
4, 1000, blocked, 2018-01-09 05:00, 3
5, 3500, unblock, 2018-01-24 19:00, 2 

因此,我需要获取SQL来获取所有具有相应取消阻止操作日期(如果存在)的阻止操作。例如:block_ID,总和,blocked_date,unblock_date。因此,我需要从示例数据中获取: 例如:

block_ID, sum, blocked_date, unblock_date
1, 5900, 2018-01-05 11:00, 2018-02-11 09:00
2, 3500, 2018-01-08 12:00, 2018-01-24 19:00
4, 1000, blocked, 2018-01-09 05:00, null

我想为此需要一个WITH语句,但是我无法理解如何正确匹配记录。

任何帮助表示赞赏。

BTW Postgres 9.4

2 个答案:

答案 0 :(得分:0)

您可以尝试以下方式

with block as
     (
    select * from transactions
    where operation='blocked'
    ),
    unblock as 
    (
    select * from transactions
    where operation='unblock'
    )
    select block.id as block_ID, block.sum,
    block.date, unblock.date from block
    left join unblock on block.user_id=unblock.user_id

答案 1 :(得分:0)

如果您的数据是一致的,则您仅在查找冻结日期之后的最小解除冻结日期。您可以在select user_id, sum, date as block, ( select min(ub.date) from blocktable ub where ub.operation_type = 'unblock' and ub.user_id = b.user_id and ub.date >= b.date ) as unblock from blocktable b where operation_type = 'blocked'; 子句的子查询中获得它:

FROM

或在select b.user_id, b.sum, b.date as block, ub.unblock from blocktable b left join lateral ( select min(ub.date) as unblock from blocktable ub where ub.operation_type = 'unblock' and ub.user_id = b.user_id and ub.date >= b.date ) b where operation_type = 'blocked'; 子句中使用横向联接:

select *
from blocktable b
left join lateral
(
  select *
  from blocktable ub
  where ub.operation_type = 'unblock'
  and ub.user_id = b.user_id
  and ub.date >= b.date
  order by ub.date
  fetch first 1 row only
) as unblock
where operation_type = 'blocked';

通过横向连接甚至可以得到整行:

LEAD

获取单个日期的另一个选项是select user_id, sum, block, unblock from ( select user_id, sum, date as block, lead(date) over (partition by user_id order by date, operation_type) as unblock, operation_type from mytable ) block_and_unblock where operation_type = 'blocked';

public static void main(String args[]) throws Exception {       
    String data="Test123";
    String key="AABBCC11";
    String cipher=new String(OpenSSL.encrypt("AES256", key.toCharArray(), data.getBytes(), true));
    //cipher=enc(data,key);
    String clear=new String(OpenSSL.decrypt("AES256", key.toCharArray(), cipher.getBytes()));
    System.out.println(clear);
}

public static String enc(String text, String key) throws Exception {
    Key keySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
    Cipher c = Cipher.getInstance("AES");
    c.init(Cipher.ENCRYPT_MODE, keySpec);
    byte[] encValue = c.doFinal(text.getBytes());
    return java.util.Base64.getEncoder().encodeToString(encValue);
}

如果您希望查询即使在出现不一致的情况下也能正常工作(尤其是两个彼此阻塞的记录或两个彼此不受阻塞的记录),则可能必须顺序选择数据,即在递归查询中或在应用程序中。