ChatGPT解决这个技术问题 Extra ChatGPT

从表中选择多个列,但按一个分组

表名是“OrderDetails”,列如下:

OrderDetailID || ProductID || ProductName || OrderQuantity

我正在尝试选择多个列并按 ProductID 分组,同时具有 OrderQuantity 的总和。

 Select ProductID,ProductName,OrderQuantity Sum(OrderQuantity)
 from OrderDetails Group By ProductID

但是,这段代码当然会出错。我必须添加其他列名来分组,但这不是我想要的,因为我的数据有很多项目,所以结果是出乎意料的。

样本数据查询:

来自 OrderDetails 的 ProductID、ProductName、OrderQuantity

结果如下:

 ProductID     ProductName    OrderQuantity
    1001          abc               5
    1002          abc               23    (ProductNames can be same)
    2002          xyz               8
    3004          ytp               15
    4001          aze               19
    1001          abc               7     (2nd row of same ProductID)

预期结果:

 ProductID     ProductName    OrderQuantity
    1001          abc               12    (group by productID while summing)
    1002          abc               23
    2002          xyz               8
    3004          ytp               15
    4001          aze               19

由于 ProductName 不是唯一的,如何选择多个列和 Group By ProductID 列?

在这样做的同时,还要得到 OrderQuantity 列的总和。

您可能想查看字符串的聚合。不幸的是,我没有这方面的经验。 stackoverflow.com/questions/13639262/…

D
Dan Swain

当我选择多列时,我使用此技巧按一列分组:

SELECT MAX(id) AS id,
    Nume,
    MAX(intrare) AS intrare,
    MAX(iesire) AS iesire,
    MAX(intrare-iesire) AS stoc,
    MAX(data) AS data
FROM Produse
GROUP BY Nume
ORDER BY Nume

这行得通。


精辟,谢谢!对于那些路过的人:您将 max() 放在每个未分组的列周围,放置 as ___ 以将其重命名为您希望它显示的内容,然后 group by 您想要区分且周围没有 max() 的列.
哈哈,欺骗 SQL 的好方法,但我想知道这是否适用于所有情况?
这没有意义,而且可能是错误的!如果您的数据中每个 column_A 有几个 column_B,那么如果您按 Column_A 分组并在选择中使用 MAX(Column_B) 绕过分组限制,那么它只是这些 column_B 值之一(这里是由最大限度)。这通常不是你想要的!如果您的数据中每个 column_A 没有不同的 column_B 值,那么您应该简单地将您的 column_B 添加到 GROUP BY 子句中,如其他答案所述。 @安德鲁
我同意@Andrew – S.Serpooshan 当我们在列中有不同的值时它不起作用
如果您的列类型是布尔值,这将不起作用
F
F. Müller

我只是想添加一种更有效、更通用的方法来解决这类问题。主要思想是关于使用子查询。

做你的分组,并在表的 ID 上加入同一个表。

您的情况更具体,因为您的 productId 不是唯一的,因此有两种方法可以解决此问题。

我将从更具体的解决方案开始:由于您的 productId 不是唯一的,我们需要一个额外的步骤,即在分组并执行如下子查询后选择 DISCTINCT 产品 ID:

WITH CTE_TEST AS (SELECT productId, SUM(OrderQuantity) Total
                    FROM OrderDetails
                    GROUP BY productId)
SELECT DISTINCT(OrderDetails.ProductID), OrderDetails.ProductName, CTE_TEST.Total
FROM OrderDetails 
INNER JOIN CTE_TEST ON CTE_TEST.ProductID = OrderDetails.ProductID

这完全返回了预期的结果

 ProductID     ProductName         Total
    1001          abc               12    
    1002          abc               23
    2002          xyz               8
    3004          ytp               15
    4001          aze               19

但是有一种更简洁的方法可以做到这一点。我猜 ProductId 是 products 表的外键,我猜这个表中应该有 OrderId primary key (唯一)。

在这种情况下,只需几个步骤即可在仅对一个进行分组时包含额外的列。这将是与以下相同的解决方案

我们以这个 t_Value 表为例:

https://i.stack.imgur.com/9SCl5.png

如果我想按描述分组并显示所有列。

我所要做的就是:

使用您的 GroupBy 列和 COUNT 条件创建 WITH CTE_Name 子查询 从值表中选择所有(或您要显示的任何内容),并从 CTE INNER JOIN 中选择总计,并在 ID(主键或唯一约束)列上使用 CTE

就是这样!

这是查询

WITH CTE_TEST AS (SELECT Description, MAX(Id) specID, COUNT(Description) quantity 
                    FROM sch_dta.t_value
                    GROUP BY Description)
SELECT sch_dta.t_Value.*, CTE_TEST.quantity 
FROM sch_dta.t_Value 
INNER JOIN CTE_TEST ON CTE_TEST.specID = sch_dta.t_Value.Id

结果如下:

https://i.stack.imgur.com/HtIlC.png


S
S.Serpooshan

您的数据

DECLARE @OrderDetails TABLE 
(ProductID INT,ProductName VARCHAR(10), OrderQuantity INT)

INSERT INTO @OrderDetails VALUES
(1001,'abc',5),(1002,'abc',23),(2002,'xyz',8),
(3004,'ytp',15),(4001,'aze',19),(1001,'abc',7)

询问

 Select ProductID, ProductName, Sum(OrderQuantity) AS Total
 from @OrderDetails 
 Group By ProductID, ProductName  ORDER BY ProductID

结果

╔═══════════╦═════════════╦═══════╗
║ ProductID ║ ProductName ║ Total ║
╠═══════════╬═════════════╬═══════╣
║      1001 ║ abc         ║    12 ║
║      1002 ║ abc         ║    23 ║
║      2002 ║ xyz         ║     8 ║
║      3004 ║ ytp         ║    15 ║
║      4001 ║ aze         ║    19 ║
╚═══════════╩═════════════╩═══════╝

但我说,我不想将其他列名添加到分组依据,它会产生意想不到的结果。
好吧,除非您有多个与同一个 ProductID 关联的产品名称,否则它不应该给您带来意外的结果。如果是这种情况并且您想避免这种情况,请参阅我的更新
我之前使用的查询确实提供了您在示例数据中显示的预期结果集。
@OzanAyten 我已将您的更新数据与相同的查询一起使用,它向我显示了预期结果集中显示的结果。
是的,但我的问题很清楚。如果我把它放在我的问题上,有太多的数据是无法理解的。所以这就是为什么我要求只选择多列而只按一列分组。
I
Ivar

mysql GROUP_CONCAT 函数可以帮助 https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_group-concat

SELECT ProductID, GROUP_CONCAT(DISTINCT ProductName) as Names, SUM(OrderQuantity)
FROM OrderDetails GROUP BY ProductID

这将返回:

ProductID     Names          OrderQuantity
1001          red            5
1002          red,black      6
1003          orange         8
1004          black,orange   15

与@Urs Marian 在这里发布的想法相似https://stackoverflow.com/a/38779277/906265


非常酷的功能 :) 看起来微软不久前终于有了类似的东西,database.guide/the-sql-server-equivalent-to-group_concat
V
Vikram
    WITH CTE_SUM AS (
      SELECT ProductID, Sum(OrderQuantity) AS TotalOrderQuantity 
      FROM OrderDetails GROUP BY ProductID
    )
    SELECT DISTINCT OrderDetails.ProductID, OrderDetails.ProductName, OrderDetails.OrderQuantity,CTE_SUM.TotalOrderQuantity 
    FROM 
    OrderDetails INNER JOIN CTE_SUM 
    ON OrderDetails.ProductID = CTE_SUM.ProductID

请检查这是否有效。


P
Peter Mortensen

你可以试试这个:

Select ProductID,ProductName,Sum(OrderQuantity) 
 from OrderDetails Group By ProductID, ProductName

您只需在 Select 子句中Group By 不附带聚合函数的列。因此,在这种情况下,您可以只使用 Group By ProductID 和 ProductName。


在这个答案上也是如此,我说,我不想将其他列名添加到分组依据,它会产生意想不到的结果。
一个 productId 只能有一个相关的 ProductName 不是吗?所以 Group By ProductId, ProductName 在这种情况下将给出与 Group By ProductId 相同的结果
ProductName 不是唯一的,只有 ProductID 是唯一的。另外,我知道您的回答是什么意思,但在我的问题中,我只要求按一列分组。
P
Peter Mortensen

您可以尝试以下查询。我假设您的所有数据都有一个表。

SELECT OD.ProductID, OD.ProductName, CalQ.OrderQuantity
FROM (SELECT DISTINCT ProductID, ProductName
      FROM OrderDetails) OD
INNER JOIN (SELECT ProductID, OrderQuantity SUM(OrderQuantity)
            FROM OrderDetails
            GROUP BY ProductID) CalQ
ON CalQ.ProductID = OD.ProductID

J
Jessica Pennell

在我看来,这是一个严重的语言缺陷,使 SQL 落后于其他语言数年。这是我令人难以置信的 hacky 解决方法。这是一个完全的kludge,但它总是有效的。

在此之前,我想提请注意@Peter Mortensen 的答案,我认为这是正确的答案。我这样做的唯一原因是因为大多数 SQL 实现的连接操作非常慢,并迫使你打破“不要重复自己”。我需要我的查询快速填充。

这也是一种古老的做事方式。 STRING_AGGSTRING_SPLIT 干净得多。我再次这样做,因为它总是有效。

-- remember Substring is 1 indexed, not 0 indexed
SELECT ProductId
  , SUBSTRING (
      MAX(enc.pnameANDoq), 1, CHARINDEX(';', MAX(enc.pnameANDoq)) - 1
    ) AS ProductName
  , SUM ( CAST ( SUBSTRING (
      MAX(enc.pnameAndoq), CHARINDEX(';', MAX(enc.pnameANDoq)) + 1, 9999
    ) AS INT ) ) AS OrderQuantity
FROM (
    SELECT CONCAT (ProductName, ';', CAST(OrderQuantity AS VARCHAR(10)))
      AS pnameANDoq, ProductID
    FROM OrderDetails
  ) enc
GROUP BY ProductId

或者用简单的语言:

将除一个字段之外的所有内容粘合到一个带有您知道不会使用的分隔符的字符串中

分组后使用子字符串提取数据

性能方面,我一直在使用字符串而不是 bigints 之类的东西时具有出色的性能。至少与 microsoft 和 oracle 的 substring 是一个快速的操作。

这避免了您在使用 MAX() 时遇到的问题,当您在多个字段上使用 MAX() 时,它们不再一致并且来自不同的行。在这种情况下,可以保证您的数据完全按照您要求的方式粘合在一起。

要访问第三个或第四个字段,您需要嵌套子字符串,“在第一个分号之后查找第二个”。这就是为什么 STRING_SPLIT 可用时更好的原因。

注意:虽然超出了您的问题范围,但当您处于相反的情况并且您正在对组合键进行分组但不希望显示所有可能的排列时,这尤其有用,即您想要公开 'foo' 和'bar' 作为组合键,但想按 'foo' 分组


J
Joe_DM

==编辑==

我再次检查了您的问题并得出结论,这是无法完成的。

ProductName 不是唯一的,它必须是 Group By 的一部分或从您的结果中排除。

例如,如果您 Group By 只有 ProductID,SQL 将如何向您呈现这些结果?

ProductID | ProductName | OrderQuantity 
---------------------------------------
1234      | abc         | 1
1234      | def         | 1
1234      | ghi         | 1
1234      | jkl         | 1

我正在使用 sql,第一个代码块给出了语法错误。另外,我不想将其他列添加到 Group By。
我附上了我能想到的唯一方法,而不用按两个项目分组。问题是如果您按数字分组,则无法选择相应的字符串而不对其进行一些聚合。 @har07 发布的答案看起来是最好的选择。例如,如果两个项目具有相同的 OrderQuantity 但具有不同的 ProductName,则服务器不知道要显示哪个 ProductName。希望这是有道理的。
我想合并和求和相同 ProductID 的行的 OrderQuantity :) 我也知道为什么这不起作用。这一切都说得通,但真的不可能吗?
我刚刚注意到这让你回到第一方......你得到的结果有什么问题?也许您的查询正是您想要的,只是格式错误?
对不起,但正如我在我的问题上所说的,我也需要其他专栏。我知道如何分组。我可以自己做,但我的问题不同。我已经编辑了我的问题,请阅读最后一个阶段
D
DubZ

我遇到了与 OP 类似的问题。然后我看到了@Urs Marian 的回答,这很有帮助。但另外我一直在寻找的是,当列中有多个值并且它们将被分组时,我如何获得最后提交的值(例如按日期/id 列排序)。

例子:

我们有以下表结构:

CREATE TABLE tablename(
    [msgid] [int] NOT NULL,
    [userid] [int] NOT NULL,
    [username] [varchar](70) NOT NULL,
    [message] [varchar](5000) NOT NULL
) 

现在表中至少有两个数据集:

+-------+--------+----------+---------+
| msgid | userid | username | message |
+-------+--------+----------+---------+
|     1 |      1 | userA    | hello   |
|     2 |      1 | userB    | world   |
+-------+--------+----------+---------+

因此,如果相同的用户 ID 具有不同的用户名值,以下 SQL 脚本确实可以对它进行分组(在 MSSQL 上检查)。在下面的示例中,将显示具有最高 msgid 的用户名:

SELECT m.userid, 
(select top 1 username from table where userid = m.userid order by msgid desc) as username,
count(*) as messages
FROM tablename m
GROUP BY m.userid
ORDER BY count(*) DESC

A
Amirkhm

获得所需结果的优雅方法是通过以下方式使用“over (partion by)” sql 子句:

SELECT ProductID,ProductName,OrderQuantity
    ,SUM(OrderQuantity)     OVER(PARTITION BY ProductID) AS 'Total'
    --,AVG(OrderQuantity)   OVER(PARTITION BY ProductID) AS 'Avg'
    --,COUNT(OrderQuantity) OVER(PARTITION BY ProductID) AS 'Count'
    --,MIN(OrderQuantity)   OVER(PARTITION BY ProductID) AS 'Min'
    --,MAX(OrderQuantity)   OVER(PARTITION BY ProductID) AS 'Max'
FROM OrderDetails

m
mrfournier

SELECT ProductID, ProductName, OrderQuantity, SUM(OrderQuantity) FROM OrderDetails WHERE(OrderQuantity) IN(SELECT SUM(OrderQuantity) FROM OrderDetails GROUP BY OrderDetails) GROUP BY ProductID, ProductName, OrderQuantity;

我用上面的方案解决了Oracle12c中类似的问题。


问题是如何在不使用所有列的情况下进行分组。