【问题标题】:How to find 2 lowest values for each item in an SQL table, order by attribute如何为 SQL 表中的每个项目找到 2 个最小值,按属性排序
【发布时间】:2019-09-17 16:53:13
【问题描述】:

我有3张表如下:

  1. 产品:(product_id,product_description)
  2. 卖家:(seller_id,seller_name)
  3. 关联:(seller_id、product_id、价格)

许多卖家销售许多产品。我需要为每种产品(按递增价格排序)及其相应的供应商找到两个最便宜的价格。理想的列输出是:

product_id, product_description, seller_id, seller_name, price

p01, milk, s04, walmart, 1.50

p01, milk, s02, target, 2.25

p02, rice, s05, safeway, 1.30

p02, rice, s03, dillons, 1.75

这是我在 SQL 服务器上尝试过的;这是迈向答案的中间步骤。我触发了一个错误,但不明白为什么:

SELECT TOP 2 *
FROM

    (SELECT A.seller_id, A.product_id, min(price) AS A.price
    FROM Association A
    GROUP BY A.seller_ID, A.product_id)

    ORDER BY A.price ASC

还有错误:

Msg 102, Level 15, State 1, Line 8
Incorrect syntax near '.'.

编辑:我使用了本杰明提出的解决方案;它几乎是正确的。这是查询输出:

seller_id, product_id, price, m
1   1   7.89    1
3   1   8.00    1
6   1   8.50    1
1   2   12.05   1
6   2   12.50   1
1   3   13.67   1
6   3   15.00   1
1   4   7.66    1
3   4   7.50    1
6   4   8.24    1

值得注意的是,一些 product_id 值,例如 1 和 4,出现了 3 次,我只需要两个最低价格,而不是第三个(或更高)。所以我相信这段代码是按价格排序,但不是删除价格高于第二低的条目。

【问题讨论】:

    标签: sql-server group-by sql-order-by


    【解决方案1】:

    使用 CTE 更容易做到:

    with min1 as (
    SELECT A.seller_id, A.product_id,  A.price,
    row_number() over (partition by  A.seller_id, A.product_id order by a.price   asc) as rn
        FROM Association A
        )
    select * from min1 
       where rn <3 
       order by   seller_id,  product_id, price;
    

    【讨论】:

    • 我认为这几乎是我需要它来执行的。查询输出一列“m”,这是我没想到的。此外,我认为它按价格准确排序,但不会删除第二低价格之后的行(即 product_id = 1、4 显示第三低)
    【解决方案2】:

    要回答您的问题,您的查询中有一个派生表(有些人可能称之为子查询)。它必须有一个别名 - 所以给它一个。

    在用于形成派生表的查询中,您使用了不正确的语法。您不应该尝试为聚合列提供 a.price 的名称(并且您应该与您的名称及其拼写保持一致 - 有一天这种不一致会咬您一口)。为什么?好吧,首先它是你错误的根源。如果您希望将列命名为“a.price”,则需要对其进行定界,因为它违反了常规标识符的规则。但不要 - 句点(或点)具有特定的含义/用法,并且在列名中使用它非常非常具有误导性。所以只需给它一个没有句号的别名。

    ... (select A.seller_id, A.product_id, min(A.price) as minprice 
    from ... ) as MinAssoc 
    

    正如您在这个 sn-p 中看到的,我为派生表指定了别名“MinAssoc”——这是我提到的第一件事。如果你忽略它,如果你只是修复列别名问题,你会遇到错误。

    接下来,停止使用单字母别名。那只是懒惰。当然,这是一个简短的示例,很容易看到您的代码现在做了什么。但是您正在建立和加强对您没有好处的习惯,并且当其他人看到它并需要破译更复杂的查询时,它对您的工作的影响很差(因为单个字母对理解“事物”没有任何帮助)代表)。

    这些将修复您的错误,但您需要使用不同的方法来实现您的目标 - 正如已经建议的那样。

    【讨论】:

    • 单字母别名非常普遍,被许多公认的 TSQL 专家广泛使用。我希望看到您制定一个完整的解决方案作为子查询。在 CTE 之前,我们必须使用子查询,但由于 CTE,我的解决方案是更常见的解决方案。
    【解决方案3】:

    您可以在 SUB-QUERY 或 CTE 中使用ROW_NUMBER () OVER clause 将其归档,以下是子查询示例:

    以及由于AS A.price 而导致的错误,在您的示例中应该是AS price

    SELECT *
    FROM
        (SELECT A.seller_id, 
                A.product_id, 
                price,
                ROW_NUMBER() OVER (PARTITION BY  A.seller_id, A.product_id order by a.price) as RN
        FROM  Association A
       ) as T
    Where T.RN <=2
    ORDER BY price ASC
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-27
      • 1970-01-01
      • 2019-01-12
      • 2018-03-04
      • 2020-08-07
      • 1970-01-01
      • 2019-09-19
      • 2017-08-01
      相关资源
      最近更新 更多