我有一个表transactions
,其中有列account_id
,device_id
和card_id
。我想创建一个新列token
定义为用户ID 。在共享至少前面提到的三列之一的值的交易之间,此新列将具有相同的值。
这个想法是创建一个用户标识符,该用户标识符由帐户,设备和卡组成。这个新ID比以前使用任何ID都“强”,例如,如果某人更改了他的帐户或设备,但没有更改他的卡,则他的交易仍将链接此新令牌ID之前的令牌。
在Redshift SQL中,哪种方法可以做到这一点?
示例:
transaction_id account_id device_id card_id token
1 1 1 1 1
2 1 2 2 1
3 2 2 3 1
4 3 3 3 1
5 4 4 4 2
6 5 4 5 2
7 6 8 2 1
8 7 7 7 3
在上面的示例中:
更新
我设法通过两个步骤获得了解决方案:
token
更新transaction_id
列。此步骤不能解决问题,因为例如T4应该具有令牌1,但是它具有令牌2,因为链接到T4的最早的事务是T2,而不是T1。这是代码
create table sandbox.test(
transaction_id integer,
account_id integer,
device_id integer,
card_id integer
);
insert into sandbox.test values
(1, 1, 1, 1),
(2, 1, 2, 2),
(3, 2, 2, 3),
(4, 3, 3, 3),
(5, 4, 4, 4),
(6, 5, 4, 5),
(7, 6, 8, 2),
(8, 7, 7, 7),
(9, 3, 9, 9),
(10, 10, 9, 9);
alter table sandbox.test
add column token int
default NULL;
-- Step 1
update sandbox.test
set token = A.token
from (
with links as (
select transaction_id,
first_value(transaction_id)
over(partition by account_id order by transaction_id rows unbounded preceding) as account_link,
first_value(transaction_id)
over(partition by device_id order by transaction_id rows unbounded preceding) device_link,
first_value(transaction_id)
over(partition by card_id order by transaction_id rows unbounded preceding) card_link
from sandbox.test
)
select l1.transaction_id, least(l2.account_link, l2.device_link, l2.card_link) token
from links l2
inner join links l1
on l2.transaction_id=least(l1.account_link, l1.device_link, l1.card_link)
) A
where sandbox.test.transaction_id=A.transaction_id;
-- Step 2
CREATE OR REPLACE PROCEDURE refresh_transactions() AS $$
DECLARE
transactions RECORD;
BEGIN
FOR transactions IN SELECT transaction_id FROM sandbox.test ORDER BY transaction_id LOOP
RAISE INFO '%', transactions.transaction_id;
EXECUTE 'update
sandbox.test
set token = (select A.token from sandbox.test A where
A.transaction_id = sandbox.test.token)
where transaction_id='||transactions.transaction_id||';';
END LOOP;
RETURN;
END;
$$ LANGUAGE plpgsql;
CALL refresh_transactions();
但是,此解决方案的第二部分(refresh_transactions()
调用)花费的时间太长,无法在具有数百万个事务的DB上运行,因此无法实现。也许有一种方法可以更有效地做到这一点?