【问题标题】:Return first product from database where repeating data exists从存在重复数据的数据库中返回第一个产品
【发布时间】:2015-02-06 22:16:31
【问题描述】:

我正在创建一个电子商务网站,在“商店”页面上,我想显示数据库中每个唯一 productID 的最低产品价格。

所以我的数据如下:

产品表:

product ID (PK),
Product description,
yada yada

产品变体:

ID (PK),
product Price,
product Stock,  
Size ID (PK),

产品尺寸:

Size ID (Pk),
Size

在实践中,对于每个唯一 ID,我可能有 2 或 3 个产品价格(基于大小),所以当我执行时:

SELECT 
      ID, 
      productArtist, 
      productDescription, 
      ImageName, 
      ProductLP, 
      ProductPrice 
FROM tblProducts 
LEFT JOIN
tblProductVariant ON tblProducts.ID = tblProductVariant.productID
LEFT JOIN tblProductSize ON tblProductSize.szeID = tblProductVariant.sizeID

我得到相同的产品显示 2 或 3 次,对于每个单独的价格,我只想显示一个价格最低的产品结果,有人可以帮忙吗?

【问题讨论】:

    标签: sql sql-server sqldatasource


    【解决方案1】:

    尝试使用排名函数按价格对行进行排序,然后选择第一行。即使有平局,你也只会得到一排。此方法还使您能够通过按降序或升序排序并将 Row_Id 设置为所需的行数来选择顶部或底部 n 行。 (例如,其中 Row_Id

    SELECT  ID, 
            productArtist, 
            productDescription, 
            ImageName, 
            ProductLP, 
            ProductPrice 
    FROM (    SELECT 
                  ID, 
                  productArtist, 
                  productDescription, 
                  ImageName, 
                  ProductLP, 
                  ProductPrice 
                  Row_Id = ROW_Number() OVER (Partition By tblProducts.ProductId ORDER BY tblProducts.ProductId, ProductPrice asc) 
            FROM tblProducts 
            LEFT JOIN
            tblProductVariant ON tblProducts.ID = tblProductVariant.productID
            LEFT JOIN tblProductSize ON tblProductSize.szeID = tblProductVariant.sizeID
        ) QRY
    
    WHERE Row_Id = 1 
    

    【讨论】:

    • 正如我在最近的另一个非常相似的问题中所展示的,使用CROSS APPLY 比使用ROW_NUMBER 更有效。 stackoverflow.com/questions/28313651/select-top-x-of-each-id/…
    • 其实你应该ORDER BY ProductPrice asc, ProductVariant.ID而不是ORDER BY tblProducts.ProductId, ProductPrice asc。我们希望首先按价格订购,并且仅当产品的多个变体具有相同的价格时,然后通过使用 ProductVariant ID 或库存或尺寸或其他适当的东西来解决平局并产生一致的结果。
    【解决方案2】:

    您只想要产品的价格 = MIN(ProductPrice) 的行?

    SELECT ID, productArtist, productDescription, ImageName, ProductLP, ProductPrice
    FROM tblProducts 
    LEFT JOIN tblProductVariant as PV1 ON tblProducts.ID = tblProductVariant.productID
    LEFT JOIN tblProductSize ON tblProductSize.szeID = tblProductVariant.sizeID
    WHERE ProductPrice = (
        SELECT MIN(ProductPrice)
        FROM  tblProductVariant as PV2 
        LEFT JOIN tblProductSize ON tblProductSize.szeID = tblProductVariant.sizeID
        where PV2.productID = PV1.productID 
    )
    

    【讨论】:

    • 感谢@Turophile,我收到“无法绑定”错误。我删除了现在有效的 PV1 身份; SELECT ID, productArtist, productDescription, ImageName, ProductLP, ProductPrice FROM tblProducts LEFT JOIN tblProductVariant ON tblProducts.ID = tblProductVariant.productID LEFT JOIN tblProductSize ON tblProductSize.szeID = tblProductVariant.sizeID WHERE ProductPrice = ( SELECT MIN(ProductPrice) FROM tblProductVariant as PV2 LEFT JOIN tblProductSize ON tblProductSize.szeID = tblProductVariant.sizeID where PV2.productID = tblProductVariant.productID )
    • 是的,抱歉 - 我没有机会测试它,但认为它足够接近让您到达那里。
    • 这种方法将为您提供以最低价格存在的所有行,而不仅仅是一个。我认为 OP 只想看到一行。
    • @DataWriter 是的,但似乎合理的假设是,只有一种产品尺寸/变体价格最低。如果不是这种情况,则应修改问题以完全指定要求。您不能假设具有最低(或最高)rowid 的行是正确的。事实上,使用 rowid 可能会使结果显得“随机”。
    • 我同意这个问题有点含糊,但我不明白 Row_Id() 如何返回不正确或随机的行。 PARTITION BY 将每个 Product_Id 的行集排序为从 1 到 n 的系列。 ORDER BY Product_Id, Price asc 将这些集合中的价格从低到高排序。即使在平局的情况下,最低价格也是第 1 行。为什么您认为它会返回不正确或随机的结果?
    【解决方案3】:

    实际上,您自己已经非常接近答案了。

    select  P.ID, P.Artist, P.Description, P.Price, S.Size
    from    tblProducts  P
    join    tblProductVariant PV
        on  PV.ID = P.ID
    left join tblProductVariant PV2
        on  PV2.ID    = PV.ID
        end PV2.Price < PV.Price
    join    tblSize      S
        on  S.ID = PV.ID
    where   PV2.ID is null;
    

    请注意,只要有产品 id 匹配但没有价格低于 PV 行中的价格,左连接将导致 PV2 字段被清空。这些是您想要的,因为这是该产品的最低价格。所以在where 子句中,过滤掉所有其他的。因此,您的结果将仅是每个 ID 中价格最低的产品。

    我可以补充几条建议吗?谢谢你。首先,始终为您的表设置别名并在每个字段引用中使用该别名。如果表的字段名称对于该表来说是唯一的,则计算机不需要此操作,但在开发期间以及当您在数月或数年后处理查询时,为落后于您甚至您自己的开发人员执行此操作。这是一种提高代码可维护性的简单方法,而且绝对不会影响代码的执行。

    另外(你可能无法控制——对不起)不要在表和视图名称前加上“tbl”、“t_”或“vw_”或任何说“嘿,笨蛋!这是一张表,你这个笨蛋!”它可以作为用于说明的示例代码(如何查询,通常在不存在实际表的情况下),但对于现实生活中的数据库——无论是生产、测试​​、qa 还是其他)它都散发着臭味的业余性。它指出,数据库或其中的这一部分是由数据库程序员(当时的初级程序员)设计的,他们在一些教科书中看到了这种约定,而不是真正的数据架构师或建模师。这种做法不会增加可维护性或真正提供任何好处。然而,它确实打破了数据和使用该数据编写应用程序的开发人员之间可能建立的任何抽象墙。&lt;/soap_box&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-10
      • 1970-01-01
      • 1970-01-01
      • 2018-02-10
      • 2020-04-29
      • 1970-01-01
      • 1970-01-01
      • 2020-03-09
      相关资源
      最近更新 更多