SQL - 优化Redshift中的嵌套查询

时间:2017-10-23 08:10:39

标签: sql amazon-redshift

希望在这里挑选人们的智慧。 (目前的方法在底部)

请参阅下面的SQL Fiddle Link。 http://sqlfiddle.com/#!17/4a818/1

create table paymentmethod (
  methodtype varchar(6) not null,
  methodname varchar(6) not null
);

insert into paymentmethod values
  ('cc', 'mstr'),
  ('cc', 'visa'),
  ('cc', 'amex')
;

create table chargepolicy (
  accountname varchar(6) not null,
  methodtype varchar(6) not null,
  methodname varchar(6) not null,
  chargerate float not null
);

insert into chargepolicy values
  ('acct1','cc', 'mstr', 0.02),
  ('acct1','cc', 'visa', 0.02),
  ('acct1','cc', 'amex', 0.025),
  ('acct2','cc', 'all', 0.015),
  ('acct3','cc', 'amex', 0.03),
  ('acct3','cc', 'all', 0.02),
  ('acct4','cc', 'visa', 0.0),
  ('acct4','cc', 'all', 0.025)
 ;


select * from chargepolicy, paymentmethod
where chargepolicy.methodtype = paymentmethod.methodtype
and (chargepolicy.methodname = paymentmethod.methodname
     or chargepolicy.methodname = 'all')
order by 1,2,3;

所以,这是一个假设的案例(显然)。我有Visa,MasterCard,Amex等付款方式,然后是每种方法的收费标准。费率将根据帐户而有所不同。这些解释方法&速率映射在另一个表中定义。

现在,当我为每种方法定义费率时,一切正常(例如acct1和acct2)。当我们来到acct3和acct4时,事情变得有趣 - 这就是我需要帮助的地方。在acct3中,我说对于美国运通而言,收费应该是3%,而对于其他一切(所有 - 美国运通卡),它应该是2%。同样,在acct4中,我希望Visa的费用为0%,其他一切费用为2.5%。

当前SQL的编写方式,我得到了acct3.amex和acct4.visa的两个值。

我该如何简化呢。它必须是一个直截了当的东西,但我不相信我正在看它。

这就是我的想法:

http://sqlfiddle.com/#!17/36a1c/6

select * 
from 
  chargepolicy, 
  paymentmethod
where 
  chargepolicy.methodtype = paymentmethod.methodtype
  and (chargepolicy.methodname = paymentmethod.methodname
     or (chargepolicy.methodname = 'all'
    and paymentmethod.methodname not in (
    select methodname from chargepolicy cp2 where cp2.accountname = chargepolicy.accountname
      and cp2.methodname !='all')
    ))
order by 1,2,3;

但是由于我的实际用例有很多其他选项需要映射(例如国家,产品,货币等),我不确定我当前的方法是否可扩展 - 嵌套查询太多。

1 个答案:

答案 0 :(得分:1)

我的方法就是这样,我认为它更容易理解。

select 
ac.accountname,
pm.methodtype,
pm.methodname,
coalesce(cp1.chargerate,cp2.chargerate) as chargerate
from 
  paymentmethod as pm
  join (select distinct accountname from chargepolicy) as ac on 1=1
  left join chargepolicy as cp1 on pm.methodname=cp1.methodname and ac.accountname=cp1.accountname 
  left join chargepolicy as cp2 on cp2.methodname='all' and ac.accountname=cp2.accountname 
order by 1,2,3;

http://sqlfiddle.com/#!17/36a1c/11