如何在SQL中匹配大多数特定于最不具体的记录?

时间:2013-06-16 16:18:56

标签: sql

这是背景故事。

我正在尝试生成一个包含特定人员正确佣金值的交易清单。不是每个人都有资格获得佣金,但是那些在佣金表中有条目的人可以指定他们获得的发票项目,项目子类别,项目类别和/或默认佣金价值。

我的问题在于构建佣金表的方式使得选择起来非常困难,如下所示:

委托表

staffid sequence invoiceitemid subclassid invclassid commission commtype 
------- -------- ------------- ---------- ---------- ---------- -------- 
KH      1        (null)        (null)     (null)     20.0       1        
KH      2        (null)        (null)     BOA        0.0        2        
KH      3        (null)        (null)     GRO        0.0        2        
KH      4        (null)        (null)     HEA        5.0        2        
KH      5        (null)        (null)     FTP        5.0        2        
KH      6        (null)        (null)     NTR        0.0        2        
KH      7        (null)        EUK        NTR        5.0        2        
KH      8        (null)        FOP        NTR        5.0        2        
KH      9        (null)        PUR        NTR        5.0        2        
KH      10       (null)        RC         NTR        5.0        2        
KH      11       (null)        (null)     MSC        0.0        2        
KH      12       (null)        (null)     MIS        0.0        2        
KH      13       1171          (null)     (null)     15.8       2        
KH      14       1173          (null)     (null)     15.2       2        



同样,根据COMMISSION表中最具体到最不具体的列,每个事务只应选择一个佣金值。

最具体 - invoiceitemid,subclassid,invclassid - 最不具体

例如1:
如果交易包括:

  • invoiceitemid:1234
  • 子类:FOP
  • invclass:NTR

SQL应该在子类(“FOP”)上匹配,而不是在invclass(“NTR”)上匹配,导致佣金为5.0而不是0.0

例如2: 如果交易不包括匹配:

  • invoiceitemid:1234
  • 子类:STR
  • invclass:BLA

SQL应匹配invoiceitemid(null),subclassid(null)和invclass(null),导致佣金为20.0

我尝试过什么 使用COALESCE(invoiceitemid,subclassid,invclassid)创建一个包含该记录中最具体项目的列。

但是,在第一个例子中,NTR出现在表格中的FOP之前,因此它首先被错误地匹配。 (见下文)

SELECT COALESCE(invoiceitemid, subclassid, invclassid) AS COMBINE, * 
FROM stcomm
WHERE staffid = 'KH'
ORDER BY sequence DESC

COMBINE staffid sequence invoiceitemid subclassid invclassid commission commtype 
------- ------- -------- ------------- ---------- ---------- ---------- -------- 
URN     KH      28       (null)        URN        MSC        0.0        2        
6326    KH      27       6326          (null)     (null)     0.0        2        
6325    KH      26       6325          (null)     (null)     0.0        2        
6324    KH      25       6324          (null)     (null)     0.0        2        
6328    KH      24       6328          (null)     (null)     0.0        2        
5671    KH      23       5671          (null)     (null)     20.0       2        
5793    KH      22       5793          (null)     (null)     20.0       2        
4263    KH      21       4263          (null)     (null)     0.0        2        
5081    KH      20       5081          (null)     (null)     20.0       2        
3759    KH      19       3759          (null)     (null)     0.0        2        
4846    KH      18       4846          (null)     (null)     0.0        2        
SUH     KH      17       (null)        SUH        SUP        5.0        2        
SUD     KH      16       (null)        SUD        SUP        5.0        2        
SUP     KH      15       (null)        (null)     SUP        0.0        2        
1173    KH      14       1173          (null)     (null)     15.2       2        
1171    KH      13       1171          (null)     (null)     15.8       2 


为了解决这个问题,我按顺序对序列字段进行了排序,以便首先选择最具体的“FOP”。这确实有效。

如何查询COMMISSION表以在我的交易中显示正确的佣金?

这是我的交易SQL:

SELECT T.staffid, T.invoiceid, T.invoiceitemid, I.subclassid, I.classid, T.quantity, T.invoiceprice
FROM TRANSACT T, INVOITEM I
WHERE T.invoiceitemid = I.invoiceitemid
AND T.staffid = 'KH'

staffid invoiceid invoiceitemid subclassid classid quantity invoiceprice 
------- --------- ------------- ---------- ------- -------- ------------ 
KH      2555.0    04000         FOP        NTR     2.00     3.40         
KH      3575.0    04000         FOP        NTR     7.00     11.90        
KH      3981.0    04000         FOP        NTR     6.00     10.20        
KH      4333.0    04000         FOP        NTR     1.00     1.79         
KH      6401.0    04000         FOP        NTR     5.00     8.95         
KH      7863.0    04000         FOP        NTR     12.00    21.48        

在没有选择主键的情况下,我从未遇到过如此奇怪设计的表。

如果您能提供任何帮助,我将非常感激!

2 个答案:

答案 0 :(得分:1)

一种方法:分别链接到每种类型的佣金,并使用案例子句来确定哪种是最具体的 - 如下:

SELECT T.staffid, 
       T.invoiceid, 
       T.invoiceitemid, 
       I.subclassid, 
       I.classid, 
       T.quantity, 
       T.invoiceprice,
       case
           when iic.staffid is not null then iic.commission
           when scc.staffid is not null then scc.commission
           when icc.staffid is not null then icc.commission
           else def.commission
       end Applicable_Commission
FROM TRANSACT T
JOIN INVOITEM I ON T.invoiceitemid = I.invoiceitemid
LEFT JOIN stcomm iic /* Invoice Item Commission */
  ON T.staffid = iic.staffid and 
     T.invoiceitemid = iic.invoiceitemid
LEFT JOIN stcomm scc /* Sub Class Commission */
  ON T.staffid = scc.staffid and 
     T.subclassid = scc.subclassid and 
     T.invclassid = scc.invclassid
LEFT JOIN stcomm icc /* Inv Class Commission */
  ON T.staffid = icc.staffid and 
     T.invclassid = icc.invclassid and 
     icc.subclassid is null
LEFT JOIN stcomm def /* Default Commission */
  ON T.staffid = iic.staffid and 
     def.invclassid is null and 
     def.subclassid is null and 
     def.invoiceitemid is null
WHERE T.staffid = 'KH'

答案 1 :(得分:0)

我认为你可以通过left outer join和聚合来获得你想要的东西:

select t.*
from (select t.invoiceid, t.invoiceitemid, t.classid, t.subclassId,
             t.quantity, t.invoiceprice, i.*
             min(i.sequence) over (partition by t.invoiceid, t.invoiceitemid) as minseq
      from TRANSACT t left outer join
           INVOITEM i
           on (t.staffid = i.staffid or i.staffid is NULL) and
              (t.invoiceitemid = i.invoiceitemid or i.invoiceitemid is null) and
              (t.classid = i.classid or i.classid is null) and
              (t.subclassid = i.subclassid or i.subclassid is null)
      where t.staffid = 'KH'
     ) t
where sequence = minseq or minseq is null

子查询中的join应该在发票清单中获得所有可能的匹配项。窗口函数计算匹配的最小序列号。然后,这用于在原始数据中为每个项目选择一行。