查找至少連續出現三次的所有數字/連續3天的日期【LeetCode】


編寫一個SQL查詢,查找至少連續出現三次的所有數字。
+----+-----+ | Id | Num | +----+-----+ | 1 | 1 | | 2 | 1 | | 3 | 1 | | 4 | 2 | | 5 | 1 | | 6 | 2 | | 7 | 2 | +----+-----+

【1】sql server優質解法:

【1.1】連續3次以上出現的數字

CREATE TABLE #A
(
    id INT IDENTITY(1,1),
    val INT 
)
INSERT INTO #A(val) VALUES(1),(1),(1),(1),(2),(2),(3),(4),(4),(4),(4),(4)
INSERT INTO #A(val) VALUES(1)
select * from #A
SELECT val,MIN(id) AS minid,MAX(id) AS maxid, COUNT(1) AS cmd FROM 
(
SELECT *,id-ROW_NUMBER() OVER( PARTITION BY val ORDER BY id )  AS idx FROM #A
 
) S GROUP BY val,idx

 

 
        

【1.2】連續出現的日期:(比如,想要查詢連續登錄超過3天的用戶)

CREATE TABLE #b
(
id INT IDENTITY(1,1),
userid INT,
login_time datetime
)
INSERT INTO #b(userid,login_time)VALUES(101,'20180801'),(102,'20180801')
INSERT INTO #b(userid,login_time)VALUES(102,'20180802')
INSERT INTO #b(userid,login_time)VALUES(101,'20180803'),(102,'20180803')
INSERT INTO #b(userid,login_time)VALUES(101,'20180804'),(102,'20180804')
INSERT INTO #b(userid,login_time)VALUES(101,'20180805'),(102,'20180805')
INSERT INTO #b(userid,login_time)VALUES(101,'20180806')
INSERT INTO #b(userid,login_time)VALUES(101,'20180807')
INSERT INTO #b(userid,login_time)VALUES(101,'20180809')

SELECT
* FROM #b ORDER BY userid ,login_time --解答 SELECT userid, MIN(login_time) AS StartDate, MAX(login_time) AS EndDate, COUNT(1) AS DayCount FROM ( SELECT userid ,login_time ,DATEADD(dd, -ROW_NUMBER() OVER ( PARTITION BY userid ORDER BY login_time), login_time) AS Grp FROM #b ) AS T GROUP BY userid, [Grp] ORDER BY 1


 【2】mysql辦法解決

【2.1】連續時間(比如,想要查詢連續登錄超過3天的用戶)

(8.0以前,8.0以后可以用上述sql server 辦法)

 
         

 測試代碼

-- 測試數據代碼
CREATE TABLE b
(
id INT primary key auto_increment,
userid INT,
login_time datetime
);
-- select * from b order by userid;
INSERT INTO b(userid,login_time) VALUES(101,'20180801'),(102,'20180801');
INSERT INTO b(userid,login_time) VALUES(101,'20180802'),(102,'20180802');
INSERT INTO b(userid,login_time) VALUES(101,'20180803'),(102,'20180803');
INSERT INTO b(userid,login_time) VALUES(101,'20180804'),(102,'20180804');
INSERT INTO b(userid,login_time) VALUES(101,'20180805'),(102,'20180805');
INSERT INTO b(userid,login_time) VALUES(101,'20180806');
INSERT INTO b(userid,login_time) VALUES(101,'20180807');
INSERT INTO b(userid,login_time) VALUES(101,'20180808');
INSERT INTO b(userid,login_time) VALUES(101,'20180809');
INSERT INTO b(userid,login_time) VALUES(101,'20180810');
INSERT INTO b(userid,login_time) VALUES(101,'20180731');
INSERT INTO b(userid,login_time) VALUES(102,'20180731');

插入后生成的測試表數據: 

    

實現代碼:

select userid,min(login_time) min_date,max(login_time) max_date,count(1) as day_count
from (
    select b.*,
    date_add(login_time,interval -if(@group_str=userid,@num:=@num+1,@num:=1) day) as login ,
    @group_str:=userid as temp  
    from b cross join (select @num:=0,@group_str=-1) t 
order by b.userid,login_time

) t
group by userid,login

結果:
 
         

 

 

【2.2】連續3次以上出現的數字

  強烈推薦解法三

編寫一個SQL查詢,查找至少連續出現三次的所有數字。
+----+-----+ | Id | Num | +----+-----+ | 1 | 1 | | 2 | 1 | | 3 | 1 | | 4 | 2 | | 5 | 1 | | 6 | 2 | | 7 | 2 | +----+-----+

 

-- 建表
create table  Logs(id int primary key auto_increment,num int);

-- 造數據
INSERT INTO Logs(num) VALUES(1),(1),(1),(1),(2),(2),(3),(4),(4),(4),(4),(4),(1);

 

mysql解法:

這道題給了我們一個Logs表,讓我們找Num列中連續出現相同數字三次的數字,那么由於需要找三次相同數字,所以我們需要建立三個表的實例.
我們可以用l1分別和l2, l3內交,l1和l2的Id下一個位置比,l1和l3的下兩個位置比,然后將Num都相同的數字返回即可:

解法一:

SELECT DISTINCT l1.Num FROM Logs l1
JOIN Logs l2 ON l1.Id = l2.Id - 1
JOIN Logs l3 ON l1.Id = l3.Id - 2
WHERE l1.Num = l2.Num AND l2.Num = l3.Num;

  

    

 

下面這種方法沒用用到Join,而是直接在三個表的實例中查找,然后把四個條件限定上,就可以返回正確結果了:

 

解法二:

SELECT DISTINCT l1.Num FROM Logs l1, Logs l2, Logs l3
WHERE l1.Id = l2.Id - 1 AND l2.Id = l3.Id - 1
AND l1.Num = l2.Num AND l2.Num = l3.Num;

 

  再來看一種畫風截然不同的方法,用到了變量count和pre,分別初始化為0和-1,然后需要注意的是用到了IF語句,MySQL里的IF語句和我們所熟知的其他語言的if不太一樣,相當於我們所熟悉的三元操作符a?b:c,若a真返回b,否則返回c,具體可看這個帖子。那么我們先來看對於Num列的第一個數字1,pre由於初始化是-1,和當前Num不同,所以此時count賦1,此時給pre賦為1,然后Num列的第二個1進來,此時的pre和Num相同了,count自增1,到Num列的第三個1進來,count增加到了3,此時滿足了where條件,t.n >= 3,所以1就被select出來了,以此類推遍歷完整個Num就可以得到最終結果:

 

解法三:

SELECT DISTINCT Num FROM (
SELECT Num, @count := IF(@pre = Num, @count + 1, 1) AS n, @pre := Num
FROM Logs, (SELECT @count := 0, @pre := -1) AS init
) AS t WHERE t.n >= 3;

  

 

 
        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM