【问题标题】:What's the most efficient way to generate this report?生成此报告的最有效方法是什么?
【发布时间】:2012-01-21 15:04:39
【问题描述】:

给定一个表 (daily_sales),其中包含 100k 行以下数据/列:

id    rep   sales  date  
1     a     123    12/15/2011  
2     b     153    12/15/2011  
3     a      11    12/14/2011  
4     a     300    12/13/2011  
5     a     120    12/12/2011  
6     b     161    11/15/2011  
7     a       3    11/14/2011  
8     c      13    11/14/2011  
9     c      44    11/13/2011  

编写报告(完全在 SQL 中)显示每个名称的两个最新条目(rep、sales、date)的最有效方法是什么,因此输出将是:

a  123  12/15/2011  
a   11  12/14/2011  
b  153  12/15/2011  
b  161  11/15/2011  
c   13  11/14/2011  
c   44  11/13/2011  

谢谢!

【问题讨论】:

  • 我希望看到所有使用标准 SQL 或特定于供应商的答案,但可以说 mysql(如果可以的话,我也会将其作为标签添加到问题中)
  • 如果“名称”只有一个条目怎​​么办?
  • 你桌子上的主键是什么?我的第一个想法是使用 2 个查询之间的联合,一个选择最大值(直接向前)并将其联合到具有第二个最近日期的第二个查询。其次是更复杂的一点,您可以选择最大 trans_date 不在第一个查询中的 ID 列表中...这就是为什么我需要一个 ID 列
  • @daryn 当然,但“最有效”的解决方案将取决于可用的工具。
  • @Tewlfth 这绝对是一种方法。随意假设一个主键列“id”(我将编辑问题)。

标签: mysql sql postgresql greatest-n-per-group


【解决方案1】:

仅供参考,您的示例主要使用保留字,这让我们尝试对其进行编程感到很可怕。如果您有真正的表格列,请将其提供给我们。这是postgres:

select name,value, max(date)
from the_table_name_you_neglect_to_give_us
group by 1,2

这将为您提供一个包含名字、值、最大值(日期)的列表...不过我想问一下,如果示例中没有更改,为什么要给我们一个名为 value 的列?

假设您确实有一个 id 列...我们将与您的方案保持一致并将其称为“ID”...

 select b.id from
(select name,value, max(date) date
from the_table_name_you_neglect_to_give_us
group by 1,2) a
inner join the_table_name_you_neglect_to_give_us b on a.name=b.name and a.value=b.value and a.date = b.date

这给出了所有最大 ID 的列表...放在一起:

select name,value, max(date)
from the_table_name_you_neglect_to_give_us
group by 1,2

联合所有

select name,value, max(date)
from the_table_name_you_neglect_to_give_us
where id not in
(select b.id from
(select name,value, max(date) date
from the_table_name_you_neglect_to_give_us
group by 1,2) a
inner join the_table_name_you_neglect_to_give_us b on a.name=b.name and a.value=b.value      and a.date = b.date)

希望我的语法是正确的……无论如何都应该接近。我会在整个事情上加上一个括号,然后按名称从(上面的查询)中选择*...给你你想要的顺序。

【讨论】:

  • 感谢,并对错误的名称/缺少信息/误导性数据表示歉意。 “值”列是任意数字
【解决方案2】:

对于 MySQL,在 @Quassnoi's blog 中进行了解释,(name, date) 上的索引并使用此:

SELECT  t.*
FROM    (
        SELECT  name,
                COALESCE(
                (
                SELECT  date
                FROM    tableX ti
                WHERE   ti.name = dto.name
                ORDER BY
                        ti.name, ti.date DESC
                LIMIT 1 
                OFFSET 1                      --- this is set to 2-1 
                ), CAST('1000-01-01' AS DATE)) AS mdate
        FROM    (
                SELECT  DISTINCT name
                FROM    tableX dt
                ) dto
        ) tg
        , tableX t
WHERE   t.name >= tg.name
  AND   t.name <= tg.name
  AND   t.date >= tg.mdate

【讨论】:

  • 第-5行。将其重命名为 tg,因为 to 已保留。
  • 我只是瞎了眼!无论如何,重命名可能是个好主意;-)
【解决方案3】:

如果我明白你的意思.. 那么这可能会有所帮助:

SELECT main.name, main.value, main.date 
FROM tablename AS main
LEFT OUTER JOIN tablename AS ctr
    ON main.name = ctr.rname
    AND main.date <= ctr.rdate
GROUP BY main.name, main.date
HAVING COUNT(*) <= 2
ORDER BY main.name ASC, main.date DESC

我知道 SQL 比其他帖子短,但请先尝试一下..

【讨论】:

  • 对不起,我应该在里面放一些随机数。 “价值”并不意味着一致。
  • 你可以试试吗?我修改了我的帖子
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-12
  • 2012-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多