Sql 寻找最长的连胜记录
我有以下格式的数据Sql 寻找最长的连胜记录,sql,oracle,oracle11gr2,Sql,Oracle,Oracle11gr2,我有以下格式的数据 match_id team_id won_ind ---------------------------- 37 Team1 N 67 Team1 Y 98 Team1 N 109 Team1 N 158 Team1 Y 162 Team1 Y 177 Team1 Y 188 Team1
match_id team_id won_ind
----------------------------
37 Team1 N
67 Team1 Y
98 Team1 N
109 Team1 N
158 Team1 Y
162 Team1 Y
177 Team1 Y
188 Team1 Y
198 Team1 N
207 Team1 Y
217 Team1 Y
10 Team2 N
13 Team2 N
24 Team2 N
39 Team2 Y
40 Team2 Y
51 Team2 Y
64 Team2 N
79 Team2 N
86 Team2 N
91 Team2 Y
101 Team2 N
这里的比赛ID是按时间顺序排列的,37是第一场比赛,217是第1队的最后一场比赛。获胜标志着该队是否赢得了比赛
因此,从上述数据来看,第一队输掉了第一场比赛,然后赢了一场比赛,然后输掉了两场比赛,然后连续赢了4场比赛,以此类推。现在我感兴趣的是为每支球队寻找最长的连胜记录
Team_id longest_streak
------------------------
Team1 4
Team2 3
我知道如何在plsql中找到它,但我想知道是否可以在纯SQL中计算它。我试着使用LEAD、LAG和其他几个函数,但没有成功
我已经创建了提琴样本。这应该可以工作,
在这里拉小提琴:
使用我发布的答案的变体
我在Teradata上也有类似的任务,将其修改为在Oracle上运行:
SELECT
team_id,
MAX(cnt)
FROM
(
SELECT
team_id,
COUNT(*) AS cnt
FROM
(
SELECT
team_id,
match_id,
won_ind,
SUM(CASE WHEN won_ind <> 'Y' THEN 1 END)
OVER (PARTITION BY team_id
ORDER BY match_id
ROWS UNBOUNDED PRECEDING) AS dummy
FROM matches
) dt
WHERE won_ind = 'Y'
GROUP BY team_id, dummy
) dt
GROUP BY team_id;
我没有时间复制writeup,但讨论了如何使用自连接和求和来实现这一点。只是一个问题,order by子句中的数字是什么意思?1=团队id,2=最长的序列,列select@Slartibartfast我认为在解码和求和函数中都需要按team_id进行分区。当我分别运行内部select语句时,new_group和group_noExcellent的计算存在一些差异。。虽然它与Slartibartfast的答案类似,但这很容易理解。为了与PostgreSQL和SQLite兼容,请将原始的_数据替换为查询:将原始的_数据match_id、team_id、won_id作为值37、'Team1','N',67、'Team1','Y'。。。美好的但是,如果最长条纹为1,则不会返回该值。将b.match\u id>a.match\u id更改为b.match\u id>=a.match\u id应该可以解决这个问题。结尾处还缺少右括号。很好。消除了对滞后函数的需要。
with original_data as (
select 37 match_id, 'Team1' team_id, 'N' won_id from dual union all
select 67 match_id, 'Team1' team_id, 'Y' won_id from dual union all
select 98 match_id, 'Team1' team_id, 'N' won_id from dual union all
select 109 match_id, 'Team1' team_id, 'N' won_id from dual union all
select 158 match_id, 'Team1' team_id, 'Y' won_id from dual union all
select 162 match_id, 'Team1' team_id, 'Y' won_id from dual union all
select 177 match_id, 'Team1' team_id, 'Y' won_id from dual union all
select 188 match_id, 'Team1' team_id, 'Y' won_id from dual union all
select 198 match_id, 'Team1' team_id, 'N' won_id from dual union all
select 207 match_id, 'Team1' team_id, 'Y' won_id from dual union all
select 217 match_id, 'Team1' team_id, 'Y' won_id from dual union all
select 10 match_id, 'Team2' team_id, 'N' won_id from dual union all
select 13 match_id, 'Team2' team_id, 'N' won_id from dual union all
select 24 match_id, 'Team2' team_id, 'N' won_id from dual union all
select 39 match_id, 'Team2' team_id, 'Y' won_id from dual union all
select 40 match_id, 'Team2' team_id, 'Y' won_id from dual union all
select 51 match_id, 'Team2' team_id, 'Y' won_id from dual union all
select 64 match_id, 'Team2' team_id, 'N' won_id from dual union all
select 79 match_id, 'Team2' team_id, 'N' won_id from dual union all
select 86 match_id, 'Team2' team_id, 'N' won_id from dual union all
select 91 match_id, 'Team2' team_id, 'Y' won_id from dual union all
select 101 match_id, 'Team2' team_id, 'N' won_id from dual
),
----------------------------------------------------------------------
new_streaks as (
--
-- Identifying new streaks.
-- ------------------------
--
select
match_id,
team_id,
won_id,
--
-- A new streak is identfied if
--
case when
--
-- a) won_id = 'Y' and
--
won_id = 'Y' and
--
-- b) the previous won_id = 'N':
--
lag(won_id) over (partition by team_id order by match_id) = 'N'
--
--
then 1
--
-- All other cases: no new streak:
else 0
--
end new_streak
from
original_data
),
-------------------------------
streak_no as (
--
-- Assigning a unique number to each streak.
-- -----------------------------------------
--
select
--
match_id,
team_id,
--
-- In order to be able to count the number of records
-- of a streak, we first need to assign a unique number
-- to each streak:
--
sum(new_streak) over (partition by team_id order by match_id) streak_no
--
from
new_streaks
where
-- We're only interested in «winning streaks»:
won_id = 'Y'
),
-----------------------------------------------
--
-- Counting the elements per streak
-- --------------------------------
--
records_per_streak as (
select
count(*) counter,
team_id,
streak_no
from
streak_no
group by
team_id,
streak_no
)
------------------------------------------------
--
-- Finally: we can find the «longest streak»
-- per team:
--
select
max(counter) longest_streak,
team_id
from
records_per_streak
group by team_id
;
select
team_id,
max(wins)
from
(
select
a.team_id,
a.match_id amatch,
b.match_id bmatch,
(select count(distinct match_id)
from matches matches_inner
where a.team_id = matches_inner.team_id
and matches_inner.match_id between a.match_id and b.match_id) wins
from
matches a
join matches b on a.team_id = b.team_id
and b.match_id > a.match_id
where
not exists
(select 'x'
from matches matches_inner
where a.team_id = matches_inner.team_id
and matches_inner.match_id between a.match_id and b.match_id
and matches_inner.won_ind = 'N')
group by team_id
SELECT
team_id,
MAX(cnt)
FROM
(
SELECT
team_id,
COUNT(*) AS cnt
FROM
(
SELECT
team_id,
match_id,
won_ind,
SUM(CASE WHEN won_ind <> 'Y' THEN 1 END)
OVER (PARTITION BY team_id
ORDER BY match_id
ROWS UNBOUNDED PRECEDING) AS dummy
FROM matches
) dt
WHERE won_ind = 'Y'
GROUP BY team_id, dummy
) dt
GROUP BY team_id;