【问题标题】:Selecting min count('x') by year按年份选择最小计数('x')
【发布时间】:2019-04-09 22:28:06
【问题描述】:

我正在尝试创建一个表格来显示按年份播放最少的歌曲。

例如,如果 Song1 和 Song2 都只有 1 次播放,而 Song3 在 2018 年有 2 次播放,Song1 在 2017 年有 1 次播放,而 Song2 在 2017 年有 2 次播放,我想要一个返回 3 行的表格:

Song1 - 2018 - 1 场

Song2 - 2018 - 1 场

Song1 - 2017 - 1 次播放

有没有办法显示 min(count('x')) = count('x') 的歌曲。 我确定这不是正确的语法,但它本质上是我想要找到的。

SELECT * FROM music 
NATURAL JOIN (SELECT extract(year from date) AS yr, song_code, COUNT('x') 
FROM singles NATURAL JOIN plays 
GROUP BY extract(year from date), song_code
ORDER BY yr desc, COUNT('x') desc);

目前我将歌曲按一年的播放次数分组,但我不确定如何只显示播放次数最少的歌曲。

【问题讨论】:

  • HAVING MIN(COUNT(x)) = COUNT(x)
  • @Aganju - 当我尝试这样做时,我得到一个“组函数嵌套很深”的错误。
  • 不要使用natural join!它甚至没有使用正确声明的外键关系。 . .它可能会引入非常难以调试的错误。
  • 不相关,但是:您是否知道COUNT('x')count(*) 相比没有性能(或其他)优势?

标签: sql oracle


【解决方案1】:

-- 您可以更喜欢使用分析函数,例如dense_rank(),而不是连接或子查询。

with songs( id, year, play_id ) as
(
 select 1, 2018, 1 from dual union all    
 select 2, 2018, 1 from dual union all    
 select 3, 2018, 1 from dual union all
 select 3, 2018, 2 from dual union all
 select 1, 2017, 1 from dual union all 
 select 2, 2017, 1 from dual union all
 select 2, 2017, 2 from dual
)
select id, year, play_cnt
from
  (select s.*, dense_rank() over (partition by year order by play_cnt) dr
   from 
      (select id, year, count(play_id) as play_cnt
       from songs s
       group by id, year
      ) s
  )
where dr = 1;

        ID       YEAR   PLAY_CNT
---------- ---------- ----------
         1       2017          1
         2       2018          1
         1       2018          1

【讨论】:

    【解决方案2】:

    这应该可以。这也是为什么我们应该使用 WITH(子查询分解)而不是内联视图的一个很好的例子。使用 year、song_code 和 count 创建一个 song_count 子查询因式分解。

    另外,为了清楚起见,我会明确定义连接

    WITH song_count as 
        SELECT extract(year from date) AS song_year, song_code, count(*) as play_count
        FROM singles NATURAL JOIN plays
        group by extract(year from date),song_code
    select * from song_count
    where
     (song_year,play_count) in (select song_year,min(play_count) from song_count group by song_year)
    

    【讨论】:

    • 非常感谢!我让它完美地工作。不过,您的 select * song_count 中缺少一个“发件人”,我花了一秒钟才捕捉到,但之后一切正常。
    • 很高兴它有帮助。
    【解决方案3】:

    你可以试试 row_number():

    SELECT * 
    FROM music 
    NATURAL JOIN 
     (select yr, song_code, play_count
     from 
       (SELECT extract(year from date) AS yr, song_code, COUNT('x') play_count, row_number() over (partition by  extract(year from date), song_code order by COUNT('x')) rn
        FROM singles NATURAL JOIN plays 
        GROUP BY extract(year from date), song_code
       )
       where rn = 1;
    

    【讨论】:

    • 我相信当只有一个最小值时这会起作用,但在我的情况下可以有多个最小值。即几首歌曲一年只能播放一首,我想要每首歌曲的歌曲代码。
    猜你喜欢
    • 1970-01-01
    • 2017-10-13
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    相关资源
    最近更新 更多