【发布时间】:2021-10-04 22:40:28
【问题描述】:
我正在查询使用空值作为通配符的表,如果另一行包含非通配符值,则可以覆盖它。例如:
表 1:客户 - 包含客户和相关产品:
create table #cust (
id int not null,
product varchar(3) not null
)
insert into #cust
values (1,'ABC'),(1,'DEF'),(1,'GHI')
============
id | product
------------
1 | ABC
1 | DEF
1 | GHI
============
表 2:回扣 - 包含客户从每种产品中获得的回扣。一个空产品字段指定了一个默认折扣,适用于所有产品,但明确指定的产品除外:
create table #rebate (
cust_id int not null,
product varchar(3) NULL,
rebate numeric(5,2) not null
)
insert into #rebate
values (1,null,0.25),(1,'ABC',0.05)
==========================
cust_id | product | rebate
--------------------------
1 | null | 0.25
1 | ABC | 0.05
==========================
因此,这位客户 a 获得了所有产品的 25% 回扣,但他们获得 5% 的“ABC”除外。
我试图用这样一种简单的方式编写代码:
select *
from #cust c
left join #rebate r
on c.id = r.cust_id
and c.product = isnull(r.product, c.product)
但是,这样做的结果是 ABC 产品上的重复(匹配 r.product 为 null,并且 r.product = c.product 部分的连接):
======================================
id product cust_id product rebate
--------------------------------------
1 ABC 1 NULL 0.25 -- duplication
1 DEF 1 NULL 0.25
1 GHI 1 NULL 0.25
1 ABC 1 ABC 0.05 -- duplication. This is the row needed
=======================================
有什么建议吗?
【问题讨论】:
-
那么你想要的逻辑是什么? 2 行不是重复的,因为它们明显不同;
product和rebate的值不同。JOIN也按预期工作,好像JOIN在另一个表中有 2 行匹配,你得到 2 行,而不是 1。 -
你想达到什么目的?特定客户的价目表?
-
谢谢大家,我同意上述观点 - SQL 正在按照逻辑运行,但所需的输出是每个客户、每个产品的单个回扣 - 指定 产品回扣应覆盖默认回扣。以下 Marc Guillot 和 Thorsten Kettner 的建议都是正确的。现在正在测试它们。再次感谢!
-
旁注:在现实世界中,您当然不应该调用表#cust,因为这不是客户表(每个客户一行)。例如,您可以称之为
customer_product。并且列id不应称为id,因为如果它是表的ID,则表中每个ID 将只有一行。你应该叫它cust_id之类的。 -
如果特定产品的返利数量往往明显低于每位客户的产品数量,我会使用双左连接方法,但将返利保留在两个表中(客户级别返利,和客户产品级别的回扣),而不是试图将它们合并为一个。我希望它更容易理解、更容易维护、更容易适应等等。
标签: sql sql-server tsql join