【问题标题】:SQL SELECT - GROUP BYSQL 选择 - 分组依据
【发布时间】:2018-05-18 15:45:49
【问题描述】:

从 SQL 开始。

我正在尝试从几个表中收集数据以生成摘要,其中第一个表中的值按字段 Repcode 分组并总计。通过查找 Repcode 字段,在结果光标中将有从第二个表中获取的描述。

这是一个非常简化的测试程序

CREATE CURSOR Nomtot (tcode C(4), tRepcode C(2), tBalance N(9,2))
INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("A001", "12", 123.45)
INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("B003", "17", 555.45)
INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("B006", "19", 666.00)
INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("E008", "12", 810.00)

CREATE CURSOR RepLook (tRepcode C(2), tDesc C(30))
INSERT INTO Replook(tRepcode, tDesc) VALUES ("12", "Materials")
INSERT INTO Replook(tRepcode, tDesc) VALUES ("17", "Carriage")
INSERT INTO Replook(tRepcode, tDesc) VALUES ("19", "Dividends")

SELECT a.tRepcode, SUM(a.tBalance) AS tBalance, b.tDesc ;
  FROM Nomtot a, Replook b ;
  GROUP BY a.tRepcode ;
  WHERE a.tRepcode = b.tRepcode ;
  INTO CURSOR cResult

但这会产生错误:SQL GROUP BY 命令丢失或无效。 如果我然后将语句更改为 GROUP BY a.tRepcode, b.tDesc ; . . .该程序产生所需的结果。 为什么第二条是必要的?我这样做对吗

感谢指导。谢谢。

【问题讨论】:

  • 按照您编写的方式,您还需要按b.tDesc 分组。这是因为您必须按所有非聚合列进行分组。

标签: sql select group-by visual-foxpro


【解决方案1】:

原因是 SQL 需要聚合所有非计算的列。

在 SAS 等其他语言中,它不是必需的,但您的计算将仅基于 group by 的内容。换句话说,您的 SUM(a.tBalance) 对于所有 b.tDesc 将具有相同的值。在您的情况下,它可能是一对一的匹配,这并不重要,但在其他情况下,您的 b.Table 可能有多个匹配值并且应该有不同的总和...... 另一种无需在 group by 中包含 b.tDesc 的方法:
选择 a.*, b.tDesc 从 ( 选择 a.tRepcode,SUM(a.tBalance) 作为 tBalance 来自诺姆托特) 内部连接 ​​Replook b
a.tRepcode = b.tRepcode ;

【讨论】:

  • 非常感谢有线。我可以看到,在我的原始代码中,如果 tRepcode 在 Replook 表中不是唯一的(实际上它是唯一的),那么在确定从 RepLook 表中获取哪个 tDesc 值时就会出现问题。正如 Cetin 所说,我需要在“GROUP BY”子句中包含所有非聚合列。我还将检查您的 2 级 SELECT。
【解决方案2】:

您需要在 group by 中包含所有非聚合列。这就是原因。编写该查询的更好方法是:

CREATE CURSOR Nomtot (tcode C(4), tRepcode C(2), tBalance N(9,2))
INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("A001", "12", 123.45)
INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("B003", "17", 555.45)
INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("B006", "19", 666.00)
INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("E008", "12", 810.00)

CREATE CURSOR RepLook (tRepcode C(2), tDesc C(30))
INSERT INTO Replook(tRepcode, tDesc) VALUES ("12", "Materials")
INSERT INTO Replook(tRepcode, tDesc) VALUES ("17", "Carriage")
INSERT INTO Replook(tRepcode, tDesc) VALUES ("19", "Dividends")

SELECT a.tRepcode, a.tBalance, b.tDesc ;
  FROM ;
  (select tRepCode, sum(tBalance) as tBalance ;
   from nomtot ;
   group by tRepCode ) a ;
  inner join Replook b on a.tRepcode = b.tRepcode ;
  INTO CURSOR cResult ;
  nofilter

【讨论】:

    【解决方案3】:

    为所有未参与聚合函数的列添加分组依据 并将组前的 where 移动

    SELECT a.tRepcode, SUM(a.tBalance) AS tBalance, b.tDesc 
    FROM Nomtot a, Replook b 
    WHERE a.tRepcode = b.tRepcode 
    GROUP BY a.tRepcode, b.tDesc 
    

    或使用当前的连接样式(由 YogeshSharma 建议)

    SELECT a.tRepcode, SUM(a.tBalance) AS tBalance, b.tDesc 
    FROM Nomtot a
    INNER JOIN  Replook b ON a.tRepcode = b.tRepcode 
    GROUP BY a.tRepcode, b.tDesc 
    

    【讨论】:

    • 你为什么提到旧式的JOIN语法?
    • @YogeshSharma .. 正确 ..我只复制了 OP 代码 .. 答案也更新为当前连接样式
    • @YogeshSharma 感谢您的正确编辑 .. 点赞 .. 某处
    • @scaisEdge 问题被标记为 VFP。如果您删除 ; 将是错误的。同样移动 where before group by 也没有什么区别。
    【解决方案4】:

    假设您使用的是 vfp 8 或 9,那么您所要做的就是将这一行代码添加到程序的顶部。

    SET ENGINEBEHAVIOR 70
    

    使用你的例子。

    SET ENGINEBEHAVIOR 70
    
    CREATE CURSOR Nomtot (tcode C(4), tRepcode C(2), tBalance N(9,2))
    INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("A001", "12", 123.45)
    INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("B003", "17", 555.45)
    INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("B006", "19", 666.00)
    INSERT INTO nomtot (tCode, tRepcode, tBalance) VALUES ("E008", "12", 810.00)
    
    CREATE CURSOR RepLook (tRepcode C(2), tDesc C(30))
    INSERT INTO Replook(tRepcode, tDesc) VALUES ("12", "Materials")
    INSERT INTO Replook(tRepcode, tDesc) VALUES ("17", "Carriage")
    INSERT INTO Replook(tRepcode, tDesc) VALUES ("19", "Dividends")
    
    SELECT a.tRepcode, SUM(a.tBalance) AS tBalance, b.tDesc ;
      FROM Nomtot a, Replook b ;
      GROUP BY a.tRepcode ;
      WHERE a.tRepcode = b.tRepcode ;
      INTO CURSOR cResult
    

    当然,你可以用正确的方式重写查询,但这都是一样的。

    【讨论】:

    • 使用 SET ENGINEBEHAVIOR 70 是一个不好的习惯。它被改变的原因是在某些情况下旧的行为会给你错误的答案。最好编写查询,使其符合新规则。
    • 我想我那时有坏习惯。每天在 vFP 工作 20 年。我的查询从未遇到过问题。我猜是运气。我理解为什么我们以“正确的方式”编写查询并且必须在 Mysql/Isieries 和其他平台上进行。但是我在 vFP 被支持 10 年后仍然使用它的原因是因为它是我必须快速编写代码来处理模型大小数据(哦,那个 2GB)的最快工具。如果我必须开始学习新的、“正确”的做事方式,vFP 很快就会开始看起来和感觉上一样古老。
    • 查看旧表单问题的最简单方法是使用任何使用 MIN() 或 MAX() 的查询。
    【解决方案5】:

    Cetin Basoz 的答案是正确的,它应该被接受为答案,但我想再添加一件事,您可以使用 MAX() 或 MIN() 函数,而不是像这样的聚合字段

    SELECT MAX(a.tRepcode) AS tRepcode, SUM(a.tBalance) AS tBalance, MAX(b.tDesc) AS tDesc ;
      FROM Nomtot a, Replook b ;
      GROUP BY a.tRepcode ;
      WHERE a.tRepcode = b.tRepcode ;
      INTO CURSOR cResult
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-09
      • 1970-01-01
      • 1970-01-01
      • 2020-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-03
      相关资源
      最近更新 更多