如何在SQL(Oracle)中OVER子句的PARTITION BY之后添加条件?

g6ll5ycj  于 2022-11-22  发布在  Oracle
关注(0)|答案(2)|浏览(450)

在下面的例子中,我只想计算长度为正负5分钟的每一类电影(分别为当前长度LEN)?我如何将此条件添加到PARTITION BY语句后面?

SELECT film_id, title, category_name, length AS LEN, 
       Count(film_id) OVER (PARTITION BY category_name)  
FROM film INNER JOIN film_category USING (film_id) 
          INNER JOIN category USING (category_id)
ORDER BY name, length;

我试过使用RANGE,但它没有达到我想要的效果。

SELECT film_id, title, category_name, length AS LEN, 
       Count(film_id) OVER (PARTITION BY category_name)  
FROM film INNER JOIN film_category USING (film_id) 
          INNER JOIN category USING (category_id)
ORDER BY name, length;
jobtbby3

jobtbby31#

使用RANGE窗口中的解析函数:

SELECT film_id,
       title,
       category_name,
       length AS LEN, 
       Count(film_id) OVER (
         PARTITION BY category_id
         ORDER BY length
         RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING
       ) AS count_similar
FROM   film
       INNER JOIN film_category USING (film_id) 
       INNER JOIN category USING (category_id)
ORDER BY title, length;

其中,对于示例数据:

CREATE TABLE film ( film_id, title, length ) AS
  SELECT LEVEL,
         CASE WHEN LEVEL <= 26 THEN CHR(64+LEVEL) ELSE CHR(70+LEVEL) END,
         LEVEL
  FROM   DUAL
  CONNECT BY LEVEL <= 52;

CREATE TABLE film_category ( film_id, category_id ) AS
  SELECT film_id, CEIL(film_id/26) FROM film;

CREATE TABLE category (category_id, category_name) AS
  SELECT LEVEL, CHR(64+LEVEL) FROM DUAL CONNECT BY LEVEL <= 2;

输出:
| 胶片标识|标题|类别名称|长度|类似计数|
| - -|- -|- -|- -|- -|
| 一个|A级|A级|一个|六个|
| 2个|B| A级|2个|七个|
| 三个|C语言|A级|三个|八个|
| 四个|D级|A级|四个|九个|
| 五个|E级|A级|五个|10个|
| 六个|F级|A级|六个|十一|
| 七个|G级|A级|七个|十一|
| 八个|高|A级|八个|十一|
| 九个|一个|A级|九个|十一|
| 10个|J型|A级|10个|十一|
| 十一|K值|A级|十一|十一|
| 十二|左|A级|十二|十一|
| 十三|米|A级|十三|十一|
| 十四|不|A级|十四|十一|
| 十五|O型|A级|十五|十一|
| 十六|P值|A级|十六|十一|
| 十七岁|Q值|A级|十七岁|十一|
| 十八|右|A级|十八|十一|
| 十九|标准|A级|十九|十一|
| 二十个|T形|A级|二十个|十一|
| 二十一个|U形|A级|二十一个|十一|
| 二十二个|第五章|A级|二十二个|10个|
| 二十三个|W型|A级|二十三个|九个|
| 二十四|X轴|A级|二十四|八个|
| 二十五个|Y型|A级|二十五个|七个|
| 二十六人|Z轴|A级|二十六人|六个|
| 二十七人|一种|B|二十七人|六个|
| 二十八人|B| B|二十八人|七个|
| 二十九人|C语言|B|二十九人|八个|
| 三十|日|B|三十|九个|
| 三十一个|电子|B|三十一个|10个|
| 三十二|关闭|B|三十二|十一|
| 三十三人|克|B|三十三人|十一|
| 三十四|小时|B|三十四|十一|
| 三十五|我|B|三十五|十一|
| 三十六|j型|B|三十六|十一|
| 三十七|k型|B|三十七|十一|
| 三十八|升|B|三十八|十一|
| 三十九|米|B|三十九|十一|
| 四十|n个|B|四十|十一|
| 四十一|不|B|四十一|十一|
| 四十二|有害物|B|四十二|十一|
| 四十三|q值|B|四十三|十一|
| 四十四|剩余|B|四十四|十一|
| 四十五|的|B|四十五|十一|
| 四十六|测试|B|四十六|十一|
| 四十七|U形|B|四十七|十一|
| 四十八|v型|B|四十八|10个|
| 四十九|w型|B|四十九|九个|
| 五十个|X射线|B|五十个|八个|
| 五十一个|Y形|B|五十一个|七个|
| 五十二|Z轴|B|五十二|六个|
fiddle

siotufzp

siotufzp2#

恐怕简单的窗口函数无法完成您要做的事情。相反,我会将基本查询放入通用表表达式(CTE)中,然后跨每个类别的所有电影,这样您就可以轻松地比较每个电影的长度。

With basequery AS (
    SELECT film_id, title, category_name, length AS LEN, 
    FROM film INNER JOIN film_category USING (film_id) 
      INNER JOIN category USING (category_id)
)
Select film_id, title, category_name, count(*) as nbr_similar
From basequery A Inner Join basequery B
    On A.category_name=B.category_name
      AND B.LEN between A.LEN-5 and A.LEN+5
Group By film_id, title, category_name
Order By A.category_name, A.Len

请注意,这会将影片本身计入符合间隔的影片计数中。

AND A.film_id<>B.film_id

相关问题