編寫一個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;
