是否可以构造单个查询来匹配两个表,强制它们之间的1:1关系?

时间:2012-07-18 17:47:44

标签: mysql sql

对于那些对这个问题背后的原因感兴趣的人:我有一个工作正常的电子商务网站,但没有礼品券功能。添加货币GC应该非常简单,但我也想允许赠送特定产品(听起来很奇怪,但与我的行业相关)。因此,我计划创建一个新表来存放链接到特定用户和产品的礼券,我需要一种有效的方法来评估购物车和结帐页面上的表格。

想象表存在类似于以下内容的表:

CartContents
CartID          Integer (Unique sequential row identifier)
UserID          Integer
ProductID       Integer
Quantity        Integer

Gifts
GiftID          Integer (Unique sequential row identifier)  
ProductID       Integer
UserID          Integer
Quantity        Integer

这是一个过于简化的布局,但展示了这个想法。第一个表列出了用户购物车中的项目;每个产品一个记录(虽然真实产品将有可能变化的其他细节)。产品表还有产品的其他属性,但为了简单起见,我没有在此列出。第二个表是一组礼品证书,每个礼品证书都针对特定产品,已提供给此用户ID。

表数据可能如下所示:

CartContents
CartID          UserID      ProductID       Quantity
1               1           1               1
2               1           2               2
3               1           1               2
4               2           3               1

Gifts
ProductID       UserID      Quantity
1               1           1
2               1           1
3               3           1

是否可以构建一个单独的查询,每个购物车项目提供一行并链接上述两个表格,同时考虑到每个礼物只能链接到每个购物车项目一次?或者这是否需要在脚本中处理?

换句话说,因为用户1在他们的购物车中有产品1两次,并且他们只承诺了一个免费产品1,所以查询应返回cartID 1的匹配礼品记录,但不是cartID 3。查询,拉动对于用户ID 1,将返回:

CartID      ProductID       Quantity        unpaidQuantity
1           1               1               0
2           2               2               1
3           1               2               2

或者

CartID      ProductID       Quantity        unpaidQuantity
1           1               1               1
2           2               2               1
3           1               2               1

我意识到这个问题有不止一个“正确”答案的事实引起了一面红旗。实际上,每个GC应用于哪个购物车记录并不重要,因为最终结果(价格)将会相同。我很高兴地说'第一个'(最低的cartID)是应该链接的那个。

我的假设是数据库在这方面会比我写的任何脚本都高效得多;我甚至愿意打赌,我从来没有听说过一些疯狂的加入方式。我还假设任何这样的ColdFusion脚本可能有点复杂,因此需要相当多的开发和测试时间,而单个查询可能相对简单(虽然显然超出了我有限的SQL功能)。如果我在这方面不正确,我也会对此表示感谢。

我的设置,如果重要:

  • MySQL 5.0

  • ColdFusion 9

  • Windows 2000 AS

修改: 听起来数量列确实会导致问题,所以让我们继续假设在Gifts表中不存在数量。但它仍然必须存在于cartContents上。

2 个答案:

答案 0 :(得分:1)

我想到了另外一种方法,只需要和另外的group by和join。但是,它需要CartContents上的唯一ID。我不确定这是CartId应该是什么。但是,似乎用户可以拥有多个购物车,所以我认为不是。

这个想法是确定每个购物车中给定产品的第一条记录。然后,在加入礼物时使用此信息。

select CartID, UserID, ProductID, Quantity, FirstCCId  
from CartContents cc join
     (select CartID, UserID, ProductID, min(CartContentsId) as FirstCCId
      from CartContents cc
      group by CartID, UserID, ProductID
     ) ccmin
     on cc.CartId = ccmin.CartId and cc.UserId = ccmin.UserId and
        cc.ProductId = ccmin.ProductId left outer join
     Gifts g
     on cc.ProductID= g.ProductId and cc.UserID = g.userId and
        cc.CartContentsId = ccmin.FirstCCId

当礼品仅应用于一个产品系列行时,此方法有效。如果礼品的数量实际上大于任何给定行的数量,则此查询仍然只将其放在一行上。

答案 1 :(得分:0)

这有用吗?

select c.cartid, c.productid, c.quantity, c.quantity -
         case 
           when (select sum(c2.quantity) from CartContents c2 
                 where c.userid = c2.userid 
                   and c.productid = c2.productid 
                   and c.cartid < c2.cartid) < 
                 (select g.quantity from gifts g 
                  where c.userid = g.userid 
                    and c.productid = g.productid) then
             (select g.quantity from gifts g 
              where c.userid = g.userid 
                and c.productid = g.productid) - 
             (select sum(c2.quantity) from CartContents c2 
              where c.userid = c2.userid 
                and c.productid = c2.productid 
                and c.cartid < c2.cartid) 
           else 0 
         end UnpaidQuantity
from CartContents c
where userid = 1