【问题标题】:Can't query due to aggregated data, why?聚合数据无法查询,为什么?
【发布时间】:2022-12-03 01:07:41
【问题描述】:

我们有一个 3 家书店的数据库,所有书店都附有库存和随机库存的书籍。查询应该显示每个书店,所以 3 行,然后是数量(X 书店中哪本书的值最高,用 MAX(INV.UnitsInStock) 计算得出),最后是显示相应书名的第三列。

SELECT BS.Name, B.Title, MAX(UnitsInStock) AS 'Quantity'
FROM Inventories AS INV
JOIN BookShops AS BS ON BS.Id = INV.ShopId
JOIN Books AS B ON B.Id = INV.BookId
GROUP BY BS.Name

这给了我以下错误:

列“Books.Title”在选择列表中无效,因为它未包含在聚合函数或 GROUP BY 子句中。

我也试过这个:

SELECT BS.Name, MAX(UnitsInStock) AS 'Quantity'
FROM Inventories AS INV
JOIN BookShops AS BS ON BS.Id = INV.ShopId
JOIN Books AS B ON B.Id = INV.BookId
GROUP BY BS.Name

这显示了到目前为止正确的数据,但没有书名。

我试过临时表,string_agg()(正确显示每一本书),在找出确切的哪本书等之后尝试对每本书进行硬编码。

我怎样才能解决这个问题?

【问题讨论】:

标签: sql-server ssms


【解决方案1】:

错误信息是对的。你不能那样做。

想象一下,我们仍然按 BS.Name 分组,但不在 SELECT 列表中包含 MAX(UnitsInStock),而只包含 B.Title。假设每个商店都有很多书,每一行应该展示哪一本?

现在请记住,SELECT is 列表中的每个项目都是独立于其他项目的。有没有什么MAX(UnitsInStock) 条目与书名相关联。更重要的是,您可以在选择列表中同时包含MAX(UnitsInStock)MIN(UnitsInStock)。那么应该显示哪个书名?

相反,要解决这个问题,您有三个选择。我会按照从最坏到最好的顺序列出它们。

选项 1 是两个 JOIN。第一个连接是一个看起来很像原始的子查询。它会转换每本书的商店 ID 和 MAX(Qty)。第二个 JOIN 是另一个查看数量的子查询全部book,并在 ON 子句中包含一个条件,因此只有与前一个 JOIN 具有相同值的行才会匹配。这已经够糟糕的了,我什至不打算展示代码,但这就是我们在 2012 年(或者 2019 年,如果你使用 MySQL)之前必须做的事情。

选项 2 使用 APPLY 操作(也称为 LATERAL JOIN)。它看起来像这样:

SELECT BS.Name, B.Title, INV.UnitsInStock As Quantity
FROM BookShops BS
OUTER APPLY (
    SELECT TOP 1 BookId, UnitsInStock
    FROM Inventories i
    WHERE i.ShopId = BS.Id
    ORDER BY UnitsInStock DESC
) INV
INNER JOIN Books b ON b.Id = INV.BookId

最终(最好!)选项使用row_number() 窗口函数:

SELECT Name, Title, UnitsInStock As Quantity 
FROM (
    SELECT BS.Name, B.Title inv.UnitsInStock,
       row_number() over (PARTITION BY BS.Id ORDER BY inv.UnitsInStock DESC) rn
    FROM BookShops bs
    INNER JOIN Inventories inv ON inv.ShopId = bs.Id
    INNER JOIN Books b on b.Id = inv.BookId
) t
WHERE rn = 1

【讨论】:

    【解决方案2】:

    我认为您需要将 B.Title 添加到 GROUP BY:

    SELECT BS.Name,B.Title, MAX(UnitsInStock) AS 'Quantity'
    FROM Inventories AS INV
    JOIN BookShops AS BS ON BS.Id = INV.ShopId
    JOIN Books AS B ON B.Id = INV.BookId
    GROUP BY BS.Name, B.Title
    

    【讨论】:

    • 这行不通,因为那样他的行数就会太多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    • 2019-11-10
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 2017-09-21
    相关资源
    最近更新 更多