【问题标题】:mysql select count of distinct rows based on newest date and insert into another tablemysql根据最新日期选择不同行的计数并插入到另一个表中
【发布时间】:2023-02-05 00:58:23
【问题描述】:

正如主题所述,我有一个每个用户有多行的表,我需要为每个用户获取所有行的计数,其中包含日期最早的行中的数据,然后插入一个新行,其中包含计数值另一张桌子。

我正在将出勤列表 CSV 文件导入到临时表中...工作正常。但是现在我需要将所有单独的记录处理成一个要添加到最终表中的汇总记录。

tempTable:
id   email      tDate        cValue  col4    col5   col6
==========================================================
1    a@a.com    2021-01-01    1      foo     bar    foobar
2    b@b.com    2021-01-02    1      bar     foo    barfoo      
3    a@a.com    2021-02-01    1      foo     bar    foobar
4    c@c.com    2021-01-15    1      bah     hab    bahhab
5    d@d.com    2021-02-15    1      hab     bah    habbah
5    b@b.com    2021-03-01    1      bar     foo    barfoo
6    a@a.com    2021-04-01    1      foo     bar    foobar
7    d@d.com    2021-03-01    1      hab     bah    habbah

newTable (with newest date)
id   email      tDate        cValue  col4    col5   col6
==========================================================
1    a@a.com    2021-04-01    3      foo     bar    foobar
2    b@b.com    2021-03-01    2      bar     foo    barfoo
3    c@c.com    2021-01-15    1      bah     hab    bahhab
4    d@d.com    2021-03-01    2      hab     bah    habbah

我认为下面的方法有效(我已经测试了 select 部分,但还没有测试完整的 insert),但我不知道如何根据 tDate 是最旧还是最新来处理 GROUP BY email。我还没有决定最旧或最新的数据应该在哪里作为最终记录——但我仍然需要知道如何在日期之前抓取。

INSERT INTO newTable (email,tDate,cValue,col4,col5,col6) 
SELECT 
   email,
   tDate,
   COUNT(*) as  tValue,
   col4,
   col5,
   col6 
FROM tempTable 
GROUP BY email ;

当我执行 ORDER BY tDate DESC 时 - 它只是对输出进行排序,而不是实际对 GROUP BY 之前的记录进行排序。

【问题讨论】:

  • 因为你只有GROUP BY email,MySQL 不知道要返回哪个tDate(我正在使用默认的 8.0x 安装)它应该返回 MIN(tDate)MAX(tDate) ,还是使用任何其他 aggregate function ? (这同样适用于 col4、col5 和 col6)(请参阅错误“SELECT 列表的表达式 #2 不在 GROUP BY 子句中并且包含非聚合列‘fiddle.tempTable.tDate’,它不是 ..... GROUP BY 子句; 这与 sql_mode=only_full_group_by 不兼容": DBFIDDLE)
  • @Luuk - 奇怪。我在我自己的数据库上运行查询并且它有效。我没有收到您的 DBFiddle 中列出的错误。我想知道为什么?这有效:INSERT INTO newTable (email,tDate,cValue,col4,col5,col6) SELECT email,MIN(tDate),COUNT(*) as tValue,col4,col5,col6 FROM tempTable GROUP BY email ;

标签: mysql group-by count sql-insert


【解决方案1】:

正如 Luuk 已经解释过的,这是一个非确定性查询,您应该阅读 MySQL Handling of GROUP BYONLY_FULL_GROUP_BY 是个好东西,应该启用。

这个想法是获取每封电子邮件的 MAX Date 和 COUNT,然后使用它来连接回原始表值 -

SELECT t1.email, t1.tDate, t2.cnt AS cValue, t1.col4, t1.col5, t1.col6
FROM tempTable t1
JOIN (
    SELECT email, MAX(tDate) AS maxDate, COUNT(*) as cnt
    FROM tempTable
    GROUP BY email
) t2 ON t1.email = t2.email AND t1.tDate = t2.maxDate;

或者,如果使用 MySQL 8,则可以使用 window functions,特别是 ROW_NUMBER() 为按 tDate 降序排列的每个分区分配行号,然后选择 where row_number = 1

SELECT email, tDate, cValue, col4, col5, col6
FROM (
    SELECT
        email,
        tDate,
        COUNT(*) OVER (PARTITION BY email) AS cValue,
        col4,
        col5,
        col6 ,
        ROW_NUMBER() OVER (PARTITION BY email ORDER BY tDate DESC) AS rn
    FROM tempTable
) t
WHERE t.rn = 1
ORDER BY email ASC;

【讨论】:

    【解决方案2】:

    感谢@nnichols 和@Luuk 提示我在查询中使用 MIN/MAX。我自己应该想到的,但是……好吧,没有。哈哈。

    仅使用 MINMAX 就给了我想要的东西....但有一个警告。请参阅下面的注意事项。但就我而言,我不必担心警告,所以只需在当前查询中执行 MIN/MAX 即可。

    INSERT INTO newTable (email,tDate,cValue,col4,col5,col6) 
    SELECT 
       email,
       MAX(tDate),
       COUNT(*) as  tValue,
       col4,
       col5,
       col6 
    FROM tempTable 
    GROUP BY email ;
    

    输出:

    newTable (with newest date)
    id   email      tDate        cValue  col4    col5   col6
    ==========================================================
    1    a@a.com    2021-04-01    3      foo     bar    foobar
    2    b@b.com    2021-03-01    2      bar     foo    barfoo
    3    c@c.com    2021-01-15    1      bah     hab    bahhab
    4    d@d.com    2021-03-01    2      hab     bah    habbah
    

    或者MIN

    newTable (with newest date)
    id   email      tDate        cValue  col4    col5   col6
    ==========================================================
    1    a@a.com    2021-01-01    3      foo     bar    foobar
    2    b@b.com    2021-01-02    2      bar     foo    barfoo
    3    c@c.com    2021-01-15    1      bah     hab    bahhab
    4    d@d.com    2021-02-15    2      hab     bah    habbah
    

    警告:被选中的MAX(tDate)并不意味着被选中的其余列也来自同一行。我看到如果同一电子邮件地址的 col4 具有不同值的实例,即使返回的 tDate 每次都不同,MIN/MAX(tDate) 也会返回相同的 col4 值。

    如果我真的需要来自同一 tDate 行(MIN 或 MAX)的所有数据,那么我将需要做更多的查询,就像@nnichols 回答的那样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-21
      • 2021-01-25
      • 2013-05-07
      • 1970-01-01
      • 2015-04-04
      • 2018-08-09
      相关资源
      最近更新 更多