从查询中选择具有不同外键的行?

时间:2009-08-18 03:02:26

标签: sql

我刚才遇到了另一个SQL问题。我真的需要花一些时间来正确地学习它。

无论如何,我有其他人写的这个查询,它从几个不同的表中获取值。

现在,多个商品可以拥有相同的ProductID。因此,可能有3个项目返回全部具有相同的ProductID但它们具有不同的描述等。

我想每个ProductID只选择一个项目。我尝试过使用DISTINCT和group by但是我遇到了很多错误。这也适用于ACCESS数据库。

我认为这是因为select查询中使用的逻辑搞乱了我的分组。

这是查询(我尝试将其格式化得更好,使用了一个在线工具,但它仍然是一个巨大的混乱)

SELECT   tblproducts.productid,
     tblproducts.categorycode,
     tblproducts.scaletitle,
     tblproducts.picture,
     tblitems.cost,
     tblitems.modelnumber,
     tblitems.itemid,
     Iif([tblitems]![tradeapproved],Iif(([tblitems]![markup] / 100) <> 0,(Iif(([tblitems]![supplierdiscount] / 100) <> 0,
                                                                              [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount] / 100)),
                                                                              [tblitems]![cost])) * ([tblitems]![markup] / 100),
                                        0) + Iif(([tblitems]![supplierdiscount] / 100) <> 0,
                                                 [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount] / 100)),
                                                 [tblitems]![cost]) + [tblitems]![tradeapprovedcost] + [tblitems]![shippingcost],
         Iif(([tblitems]![markup] / 100) <> 0,(Iif(([tblitems]![supplierdiscount] / 100) <> 0,
                                                   [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount] / 100)),
                                                   [tblitems]![cost])) * ([tblitems]![markup] / 100),
             0) + Iif(([tblitems]![supplierdiscount] / 100) <> 0,
                      [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount] / 100)),
                      [tblitems]![cost]) + [tblitems]![shippingcost]) AS price
FROM     (tblitems
      INNER JOIN tblproducts
        ON tblitems.productid = tblproducts.productid)
     INNER JOIN tblsuppliers
       ON tblproducts.supplierid = tblsuppliers.supplierid
WHERE    tblproducts.categorycode = 'BS'
     AND tblitems.tradeapproved = 0
     AND tblsuppliers.active = on
     AND tblitems.isaccessory = false
ORDER BY Iif([tblitems]![tradeapproved],Iif(([tblitems]![markup] / 100) <> 0,(Iif(([tblitems]![supplierdiscount] / 100) <> 0,
                                                                              [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount] / 100)),
                                                                              [tblitems]![cost])) * ([tblitems]![markup] / 100),
                                        0) + Iif(([tblitems]![supplierdiscount] / 100) <> 0,
                                                 [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount] / 100)),
                                                 [tblitems]![cost]) + [tblitems]![tradeapprovedcost] + [tblitems]![shippingcost],
         Iif(([tblitems]![markup] / 100) <> 0,(Iif(([tblitems]![supplierdiscount] / 100) <> 0,
                                                   [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount] / 100)),
                                                   [tblitems]![cost])) * ([tblitems]![markup] / 100),
             0) + Iif(([tblitems]![supplierdiscount] / 100) <> 0,
                      [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount] / 100)),
                      [tblitems]![cost]) + [tblitems]![shippingcost])

有人可以快速修复此问题吗?感谢

2 个答案:

答案 0 :(得分:1)

好吧,既然你说你想学习这些东西:

内部联接会将项目连接到ProductId,但会产生一整套。因此,如果您有3个ProductIds和1个项目,您将获得

ProdId   ItemId  Description
1        1       Handy Dandy Randy Sandy!
2        1       Easily Accessible personal grooming comb.
3        1       This item provides a man or woman with extra re...

所以你真正想做的就是获得所有的ItemIds:

select ItemId from Item_tbl

然后遍历每个结果,每个项目获得一个ProductId:

select top 1 ProductId from Product_tbl where ItemId = 12345

现在,任何建议使用SQL循环的人都会被大吼大叫,而且(通常)也是如此。但这是一个棘手的问题,因为它不是人们通常做的事情。

你和group by一起走的是正确的。 Group By说“合并具有不同列X的所有行”,其中列X将是ItemId。所以:每个ItemId给我一行

现在你必须从具有ItemId的3个产品中选择一个ProductId 1. 作弊者的方法是不要在随机选择一个ProductId < / em>而是适合特定聚合函数的productId。最常见的是最小和最大。

select 
  ItemId, 
  max(ProductId) 
from Itemtbl i
inner join Producttbl p
  on i.itemid = p.itemId
group by ItemId

这将获得每个ItemId的最大ProductId。您也可以这样做以获得最低限度。

现在,更棘手的是找到符合标准的ProductId - 比如最近更新的。你想说的是“选择ItemId,max(updatedDate),然后拉出最大更新日期的ProductId - 但这在sql中不起作用(亲爱的上帝,我希望虽然它确实。)

此查询会产生错误结果:

select 
  ItemId, 
  max(ProductId), 
  max(updatdedDate)
from Itemtbl i
inner join Producttbl p
  on i.itemid = p.itemId
group by ItemId

因为最大ProductId 不一定来自具有max updatedDate 的行。

相反,你必须编写一个执行此操作的查询:

  1. 选择ItemId(例如5)和maxUpdated日期(例如5/5/2005)
  2. 返回到Products_tbl并找到ItemId为5且updatedDate为5/5/2005的ProductId
  3. 该查询留作练习。 (但是有一个错误!如果两个产品具有相同的最后更新日期和相同的ItemId会怎么样?

答案 1 :(得分:1)

提高可读性的第一步是为您的tblItem创建一个View,其中包含Price的奇特逻辑,例如:

查看[vwItemsWithAdjustedCost]

SELECT
    ProductID,
    TradeApproved,
    IsAccessory,
    Cost,
    ModelNumber,
    ItemID,
    IIf(
        ( SupplierDiscount / 100 ) <> 0,
        Cost - ( Cost * ( SupplierDiscount / 100 ) ),
        Cost
    ) AS AdjustedCost
FROM tblItems        

查看[vwItemsWithPrice]

SELECT
    ProductID,
    TradeApproved,
    IsAccessory,
    Cost,
    ModelNumber,
    ItemID,
    IIf(
        ( Markup / 100 ) <> 0,
        AdjustedCost * ( Markup / 100 ),
        0
    ) 
    + AdjustedCost
    IIf(
        TradeApproved,
        TradeApprovedCost,
        0
    )
    + ShippingCost AS Price
FROM vwItemsWithAdjustedCost

接下来,您必须确定从匹配相同ProductID的多个项目中挑选一个项目的条件是什么,如果3个项目具有相同的ID,您希望显示哪个项目?

正如Tom所说,一个简单的方法就是获得匹配的第一个(最低)ID,如下所示:

SELECT
    P.ProductID,
    P.CategoryCode,
    P.ScaleTitle,
    P.Picture,
    IP.Cost,
    IP.ModelNumber,
    IP.ItemID,
    IP.Price
FROM
    tblProducts P
    INNER JOIN (
        SELECT
            ProductID,
            MIN( ItemID ) AS MinItemID
        FROM tblItems I
        GROUP BY ProductID
    ) S
        ON S.ProductID = P.ProductID
    INNER JOIN vwItemsWithPrice IP
        ON IP.ItemID = S.MinItemID
WHERE
    P.CategoryCode = 'BS'
    AND IP.TradeApproved = 0
    AND IP.IsAccessory = false
ORDER BY IP.Price

这说明每个ProductID,从tblItems给我第一个(最低的)ItemID,并将该连接用于我的视图。

希望这有帮助!