MS-Access Select GROUP BY 查询中的 1 行

MS-Access Select 1 row from GROUP BY query

我总是很难理解 GROUP BY 功能,这个也不例外。

我有一个简单的连接查询

Select t1.g1, t1.g2, t2.id, t2.datetime, t3.name 
From ((table1 t1 Inner Join table2 t2 on t1.fld1=t2.fld1)
Inner Join table3 t3 on t1.fld2=t3.fld2)
Order By t2.datetime, t2.id

这 return 是我预期的数据。以下是一些示例行,它们说明了我尝试使用 Group By...

检索的内容
t1.g1 t2.g2 t2.id t2.datetime t3.name
726 4506 32 9/12/2021 nameA
726 4506 33 9/12/2021 nameB
726 4506 30 9/13/2021 nameC

我想 t1.g1, t1.g2.

每组的第一行

所以,我尝试以下操作:

Select t1.g1, t1.g2, FIRST(t2.id), FIRST(t2.datetime), FIRST(t3.name) 
From ((table1 t1 Inner Join table2 t2 on t1.fld1=t2.fld1)
Inner Join table3 t3 on t1.fld2=t3.fld2)
Group By t1.g1, t1.g2
Order By FIRST(t2.datetime), FIRST(t2.id)

对于上面的示例组,此 return 是以下记录...

t1.g1 t2.g2 t2.id t2.datetime t3.name
726 4506 30 9/13/2021 nameC

因此,Order By 在分组完成之后而不是之前进行操作。或者看起来是这样。也许是 SQL 关键字顺序的原因(Select,From,Where,Group By,Order By)。好的,如果我的假设是正确的,那是有道理的。我认为它在其他 726/4506 条记录之前发现 t2.id=30,因为 t2.id 是表 2 上的主键。

所以,现在我尝试嵌套查询,其中我上面的第一个查询 return 以正确的顺序排列数据,外部查询分组并获取第一条记录。

Select t1.g1, t1.g2, FIRST(t2.id), FIRST(t2.datetime), FIRST(t3.name) 
FROM (
Select t1.g1, t1.g2, t2.id, t2.datetime, t3.name 
From ((table1 t1 Inner Join table2 t2 on t1.fld1=t2.fld1)
Inner Join table3 t3 on t1.fld2=t3.fld2)
Order By t2.datetime, t2.id
)
Group By t1.g1, t1.g2
Order By FIRST(t2.datetime), FIRST(t2.id)

同样的结果!我不知道这是怎么发生的。因此,如果有人能阐明在这种情况下 Access SQL 的幕后运作顺序,我很想知道。在我的第二个查询(嵌套 Select)中,似乎我正在对目标数据进行排序,以便在对 FIRST() 聚合函数进行分组之后应该 select 在内部结果集中找到第一行。但这并没有发生。

当然,如果有人能告诉我如何 return 我想要的行...

t1.g1 t2.g2 t2.id t2.datetime t3.name
726 4506 32 9/12/2021 nameA

这就是我真正需要的。

I want to grab ONLY the first row in each Group of t1.g1, t1.g2.

您不需要聚合。您想要 过滤 数据。在这种情况下,相关子查询会执行您想要的操作:

Select t1.g1, t1.g2, t2.id, t2.datetime, t3.name 
From (table1 t1 Inner Join
      table2 t2
      on t1.fld1 = t2.fld1
     ) Inner Join
     table3 t3
     on t1.fld2 = t3.fld2
where t2.id = (select top 1 tt2.id
               from (table1 tt1 Inner Join
                     table2 tt2
                     on tt1.fld1 = tt2.fld1
                    ) Inner Join
                    table3 tt3
                    on tt1.fld2 = tt3.fld2
               where tt1.g1 = t1.g1 and tt1.g2 = t1.g2
               order by tt2.datetime, tt2.id
              );

这是一个很好扩展的解决方案(6s on 250k recs in t2)并且满足我的要求。

我无法获得 Gordon 在 Access 中工作的答案。似乎它应该有。我怀疑它在 t2 中使用 250k recs 时的表现如何。如果我能弄清楚如何让 Access 接受它,我很想测试像 Gordon 的解决方案。

请参阅问题描述以获取有关我要查找的确切记录的示例。我只需要结果集中的 t2.id。最初并未说明这一点,但我看不出这会如何改变问题陈述或解决方案。我在那里可能是错的。我仍然需要 t3.name,但稍后可以使用 t2.id.

检索它

但我仍然需要选择 GROUP'd BY t1.g1, t1.g2 在所有记录按 [= 排序时排在第一位的记录56=]、t2.id。或者换句话说,在具有相同 t1.g1+t1.g2 的所有记录中,当组按“t2.dateandtime、t2.id”排序时,我恰好需要第一条记录。

也许我在考虑这个问题的解决方案是完全错误的,并且有更好的方法可以解决这个问题SQL;如果是这样,我很想听听。

我似乎已经了解到 GROUP BY 确实根据 SQL 子句将记录分组在一起,但是这种分组此时失去了单个记录的任何概念;例如您只能使用聚合函数(MIN、MAX、SUM 等)提取其他字段,但是 - 重要的是 - FIRST 不会获得您可以预测的记录值,因为尚未执行 ORDER BY 子句.

综上所述,这是我的有效解决方案。

  1. 我删除了对 t3 上的加入的引用,就像 t2.id 我可以从中检索我需要的所有其他信息t3 之后,使用 t2.id.
  2. 不需要select't1.g1, t1.g2',那是多余的。我最初认为任何分组依据字段也必须在 Select 子句中指定。
  3. 我将 t2.dateandtime 和 t2.id 组合到一个文本字段中,并使用 MIN 来 Select 我在 GROUP'D BY 之后的 data/record。无需对我的结果集进行排序,因为 MIN 值为 t2.dateandtime 的记录,则 t2.id 已被选中!从而满足我的条件和select离子的正确记录。
  4. 由于我只需要 t2.id 返回以供进一步处理,因此我从 #3 中内置的 String 中提取 t2.id 并转换回 Long 数据类型。

这里是简短的查询:

Select 
 MIN(Format(t2.dateandtime, "yyyymmddhhmmss") & '_' & Format(t2.id, '000000')) as dt_id,  
 CLNG(MID(dt_id, INSTR(dt_id, '_') + 1)) as id
From 
 (table1 t1 Inner Join table2 t2 on t1.fld1=t2.fld1)
Group By
 t1.g1, t1.g2