【问题标题】:SQL join allowing only one match from each tableSQL 连接只允许每个表中的一个匹配项
【发布时间】:2013-05-08 19:47:14
【问题描述】:

我有两张桌子。一张桌子上有分配给每位顾客的优惠券,另一张桌子上有每位顾客的兑换信息。我基本上只需要为每个广告系列兑换优惠券,如果 UPC 与两个广告系列重叠,它将同时计入两个广告系列(但不会在一个广告系列中计算两次)。这是兑换表的想法

| customer_id | UPC  | redeem_date_id |
|-------------|------|----------------|
|     1234    | 3456 |       42       |
|     1234    | 3456 |       43       |
|     1234    | 3456 |       44       |
|     1234    | 3456 |       49       |

分配优惠券的桌子看起来像

 | customer_id | campaign_id | UPC  | print_date_id | expire_date_id |
 |-------------|-------------|------|---------------|----------------|
 |    1234     |      1      | 3456 |      35       |       45       |
 |    1234     |      1      | 3456 |      40       |       50       |
 |    1234     |      2      | 3456 |      41       |       51       |

在此示例中,客户的兑换次数多于分配的优惠券(因为他们可能在某处剪下优惠券等),但他们分配的优惠券也可能多于兑换次数。

显然,如果我做一个

where a.customer_id = b.customer_id and a.upc=b.upc and 
redeem_date_id between print_date_id and expire_date_id

我将获得比我需要的更多的记录。我不希望每次活动都计算多次相同的兑换,并且我不希望获得比原来更多的优惠券。例外情况是,不同的活动可以计算相同的兑换,但不能在一个活动中计算。 (因此,如果兑换表只有第一个观察结果,我希望输出表有两个兑换 - 一个用于活动 1 中的任一优惠券 - 我不在乎哪个 - 一个用于活动 2。)

这确实是一个分配问题 - 在一个活动中,我想在兑换表中查找匹配项 - 加入它 - 然后为下一次观察寻找匹配项(不重复使用第一个匹配的兑换)。因此,输出表的许多可能方式之一是:

| customer_id |campaign_id|UPC |print_date_id|expire_date_id|redeem_date_id|
|-------------|-----------|----|-------------|--------------|--------------|
|    1234     |      1    |3456|     35      |        45    |      42      |
|    1234     |      1    |3456|     40      |        50    |      43      |
|    1234     |      2    |3456|     41      |        51    |      42      |

非常感谢任何帮助

【问题讨论】:

  • 同一客户能否在同一天为同一UPC和同一campaign(即同一redeem_date_id)兑换超过1张优惠券?
  • 是的,所以如果您剪下两张相同的优惠券并在一笔交易中赎回,它基本上看起来就像在赎回表中的两个相同的观察结果。 (如果您正在寻找唯一标识符,我可以对这些观察或其他内容进行编号)。
  • 我正在考虑使用GROUP BY 来展平表格,但需要保留正确的print_date_id - expire_date_id 对。
  • 我没有问过 - 你的 RDBMS (SQL Flavor) 是什么? MySql、SQL Server、Oracle 等?
  • Oracle(我对它非常陌生)

标签: sql oracle join allocation


【解决方案1】:

您可以使用子查询来选择最小日期。比如:

select *
from a inner join b
on a.customer_id = b.customer_id
   and a.upc = b.upc
   and redeem_date_id between print_date_id and expire_date_id
where b.print_date_id = (
   select min(print_date_id)
   from b as b2
   where b2.customer_id = a.customer_id
   and b2.upc = a.upc
   and a.redeem_date_id between b2.print_date_id and b2.expire_date_id
)

虽然我还没有测试过它。

但还有其他事情困扰着我。检查您的优惠券

 | customer_id | campaign_id | UPC  | print_date_id | expire_date_id |
 |-------------|-------------|------|---------------|----------------|
 |    1234     |      1      | 3456 |      35       |       45       |

以及您的兑换数据

| customer_id | UPC  | redeem_date_id |
|-------------|------|----------------|
|     1234    | 3456 |       42       |
|     1234    | 3456 |       43       |

他们没有任何信息来区分在 35-45 日有效的优惠券是在 42 日还是 43 日兑换的。

换句话说,似乎缺少某些信息:此时兑换的是哪张优惠券?每张优惠券没有唯一的ID吗?不能录下来吗?

我认为虽然今天可以找到解决您的问题的技术解决方案,但您记录的信息对于此类应用程序而言不够完整。

【讨论】:

  • 当然,如果每张打印的优惠券都有一个绝对唯一的标识符,将分配的优惠券与兑换相匹配,那将是一件轻而易举的事。不幸的是,我没有制定优惠券行业标准的政策。通常,条形码甚至不是特定活动所独有的(这个问题的一部分),更不用说每张打印的优惠券了。
  • 好的 - 抱歉,我在大西洋的另一边知道这一点:)
  • @GeorgeHarrison,如果查询有帮助,请告诉我;也是我答案的后半部分 - 会编辑,但它对后来的读者有普遍价值吗?
  • @GeorgeHarrison,另一个想法是,优惠券是否可以在兑换时记录一个唯一的“兑换 ID”?这将创建您需要的信息并且问题消失了?
  • 这个例子的输出应该有 3 行。优惠券表的第一行与兑换表的前 3 行中的任何一行匹配。优惠券表的第二行与兑换表中的任何行匹配(只要不是从第一个匹配项重复的信息)。优惠券表的第三行与兑换表中的任何行匹配(这是一个不同的广告系列,所以我们不担心重叠)。我知道,很好,也很混乱。
猜你喜欢
  • 1970-01-01
  • 2015-04-15
  • 1970-01-01
  • 1970-01-01
  • 2019-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多