mariadb 如何选择一列具有最小值而另一列具有给定值的记录?

enyaitl3  于 2023-05-29  发布在  其他
关注(0)|答案(2)|浏览(167)

我有一个数据库“库存”与食品项目与以下列:
指数|日期|类别|子范畴|代码|描述|启动|结束
其中“日期”是接收到库存的日期。我想为每个唯一的类别和子类别选择记录,其中“开始”为空,日期是最早的。
我最初的尝试看起来像这样:

SELECT MIN(date) as date, category, subcategory, description, code, inventory.index
    FROM inventory 
    WHERE start is null
    GROUP BY category, subcategory

它返回了我想要的每个唯一类别和子类别的记录,但有一些例外。如果稍后添加了一条日期较早的记录(因此,它的索引比日期较晚的记录高),则查询将正确地返回来自该记录的日期,但将返回来自另一条记录的其余列的值,从而创建表中不存在的混合行。这就像“日期”值被不断检查并在必要时更新,但是一旦值被加载到结果中,其他字段就不会改变。我希望有人能帮我弄明白这里发生了什么。
我尝试了其他几种方法:
How to select data where a field has a min value in MySQL?
吴宇森建议在WHERE子句中使用嵌套的SELECT子句。我的看起来像:

SELECT * 
                    FROM inventory
                    WHERE 
                    ( SELECT MIN(date) FROM inventory )
                    AND
                    start is null
                    GROUP BY category, subcategory

AND运算符似乎有问题,它只计算“start is null”条件,而忽略其他条件,不管我把它们放在哪个顺序。当我删除其中一个条件时,另一个条件的计算结果正确。
SQL query to select distinct row with minimum value
Ken Clark建议使用INNER JOIN,我将其修改为:

SELECT inv.*
FROM inventory inv
  INNER JOIN
  (
    SELECT MIN(date) AS date, category, subcategory, description, code, inventory.index
    FROM inventory
    WHERE start is null
    GROUP BY category, subcategory
  ) inv2
  ON inv2.index = inv.index
WHERE inv2.date = inv.date

这种方法返回的结果与我最初的尝试相同,只是省略了有问题的行(我猜是因为在计算最后一个WHERE子句时,日期不同)。
我会很感激任何和所有的建议,我可以了解在这些情况下发生了什么。谢谢你!

pkmbmrz7

pkmbmrz71#

SELECT MIN(date) as date, category, subcategory, description, code, inventory.index
FROM inventory 
WHERE start is null
GROUP BY category, subcategory

这三个查询(最初尝试,然后在WHERE子句或JOIN中使用子查询)都不是有效的标准SQL,因为GROUP BYSELECT子句中的列不一致;在MySQL中,它们只能在禁用ONLY_FULL_GROUP_BY模式下运行-这不是一个好做法。
如果我们要用一个子查询来解决它,我们会像这样将它与外部查询关联起来:

select * 
from inventory i
where i.index = (
    select i1.index 
    from inventory i1 
    where i1.category = i.category and i1.subcategory = i.subcategory and i1.start is null 
    order by i1.date, i1.index limit 1
)

子查询带来您正在查找的当前category/subcategory元组的行的索引,以便外部查询可以在相应的行中进行适当的筛选。
如果你运行的是MySQL 8.0(或MariaDB >= 10.2),我推荐使用窗口函数(这样查询就可以在一次表扫描中执行):

select *
from (
    select i.*, 
        row_number() over(partition by category, subcategory order by i.date, i.index) rn
    from inventory i
    where start is null
) t
where rn = 1
8wtpewkr

8wtpewkr2#

您可以使用字符串连接技巧来获得聚合函数MIN(date)的相关列index,并按类别和子类别分组。一旦你有了所选记录的这些index值,你就可以连接以获得整行:

SELECT inv.*
  FROM inventory inv
  INNER JOIN
  (
    SELECT SUBSTRING(MIN(CONCAT(`date`, `index`)), 11) AS "selectedIndex", `category`, `subcategory`
    FROM `inventory`
    WHERE `start` IS NULL
    GROUP BY `category`, `subcategory`
  ) inv2
  ON inv.`index` = inv2.`selectedIndex`

(假设date列是标准的MySQL日期)

相关问题