【问题标题】:Use of MIN() to select just one record per code (MySQL) [duplicate]使用 MIN() 每个代码只选择一条记录(MySQL)[重复]
【发布时间】:2017-05-21 13:49:33
【问题描述】:

[强迫症前言 -1] 我知道这个问题已经被回答了至少十亿次,但问题是我无法为我想要获得的答案建模.我不是 SQL 专家,这是肯定的;我对 SELECT、UPDATE、DELETE、ecc 等经典命令很有信心。所以我要感谢任何愿意帮助我的人。

说了这么多,假设我有一张这样的桌子:

|----|--------|------------|----|----------|---------|---------|------|
| id |  code  |  category  | mq |  weight  |  weave  |  price  | show |
|----|--------|------------|----|----------|---------|---------|------|
| 1  | DT450R |   carbon   |  1 |   450    |  plain  |    90   |   1  |
| 2  | DT450R |   carbon   |  2 |   450    |  plain  |    40   |   1  |
| 3  | DT450R |   carbon   |  5 |   450    |  plain  |    75   |   1  |

| 4  | ZX300R |   carbon   |  1 |   300    |  plain  |    12   |   0  |
| 5  | ZX300R |   carbon   | 15 |   300    |  plain  |   128   |   1  |
| 6  | ZX300R |   carbon   | 30 |   300    |  plain  |    92   |   1  |

| 7  | PP120Q |   carbon   |  3 |   120    |  twill  |    28   |   1  |
| 8  | PP120Q |   carbon   |  7 |   120    |  twill  |    65   |   1  |
| 9  | PP120Q |   carbon   |  9 |   120    |  twill  |    49   |   1  |

我希望我的查询为每个代码选择最低价格的行:

| 2  | DT450R |   carbon   |  2 |   450    |  plain  |    40   |   1  |
| 4  | ZX300R |   carbon   |  1 |   300    |  plain  |    12   |   0  |
| 7  | PP120Q |   carbon   |  3 |   120    |  twill  |    28   |   1  |

第一次尝试(基于 MySQL documentation 中对 MIN() 的解释,或者至少基于我所理解的它):

$sql = 'SELECT code, weight, weave, MIN(price)
        FROM products
        WHERE category="carbon" AND show="1"
        GROUP BY code
        ORDER BY weight ASC';

第二次尝试(基于this answer 这里的 SO):

$sql = 'SELECT a.code, a.weight, a.price, a.weave
        FROM   products a
        INNER JOIN
        (
            SELECT   code, weight, MIN(price) AS minprice, weave
            FROM     products
            GROUP BY code
        ) 
       b ON a.code = b.code AND a.weave = b.weave AND a.price = b.minprice AND AND a.weight = b.weight
       WHERE category="carbon" AND show="1"
       ORDER BY a.weight ASC';

第三次尝试(基于this other answer 这里的 SO):

$sql = 'SELECT code, weight, weave, price
        FROM products
        INNER JOIN 
        (
             SELECT MIN(price) price, code, weight, weave
             FROM products
             GROUP BY code
        ) 
        AS MIN ON MIN.code = products.code AND MIN.weight = products.weight AND MIN.weave = products.weave
        WHERE category="carbon" AND show="1"
        ORDER BY a.weight ASC';

说这些尝试都没有产生预期的结果可能是没有用的;只有第三种方法输出一些东西,而其他两种方法返回0 matches。我知道在第 2 和第 3 方法中,我将查询嵌套到查询中,但我不知道为什么它们不起作用。

【问题讨论】:

  • 家庭作业,但至少你在努力。第三次尝试是正确的路径,但是除了派生表中的代码和 min(price) 之外,您不需要任何东西,然后您可以将其加入原始表中的代码和 WHERE price = derived.price
  • 其实第二次尝试最接近。但是从子查询和ON中去掉weaveweight
  • 为什么你的结果包含id = 4?您的查询显示AND show = "1",而不是该行有show = "0"

标签: php mysql


【解决方案1】:

您的第二次尝试已接近尾声。但您应该加入的唯一列是codepriceweightweave 然后来自此连接条件选择的行。

SELECT a.code, a.weight, a.price, a.weave
FROM   products a
INNER JOIN
(
    SELECT   code, MIN(price) AS minprice
    FROM     products
    GROUP BY code
) 
b ON a.code = b.code AND a.price = b.minprice
WHERE category="carbon" AND show="1"
ORDER BY a.weight ASC

这与您链接到的问题中的答案相同。他们都没有建议在ON 子句中添加其他列,所以我不确定这是从哪里来的。

【讨论】:

  • 现在,@brigo,请解释一下为什么这是正确的答案...只要你走开理解,我不介意帮助你做作业。
  • 不,子查询对整个表进行操作。然后将 JOIN 与主查询结合起来。
  • 第一次尝试不起作用,因为当您选择像 weight 这样的其他列时,它只是从组中的任意行中获取,而不是与 MIN(price) 相同的行. JOIN 为其他列选择特定行。
  • 子查询为您提供第二组(派生表),仅包含代码和最低价格。源表和派生表之间的内部连接表示“给我第三个子集,其中只有条件为真的行”或基本上 C = 条件(A 交集 B)。您的列列表确定 A 或 B 中的哪些字段将在新集合 C 中返回。
  • 没错。 Min、Max、Count、Sum,这些是聚合函数,它们将根据分组条件从整个值集中返回单个值。分组依据确定您何时“重置”该聚合并生成新行。
猜你喜欢
  • 2020-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多