1. 程式人生 > >在論壇中出現的比較難的sql問題:31(row_number函式+子查詢 月環比計算)

在論壇中出現的比較難的sql問題:31(row_number函式+子查詢 月環比計算)

最近,在論壇中,遇到了不少比較難的sql問題,雖然自己都能解決,但發現過幾天后,就記不起來了,也忘記解決的方法了。

所以,覺得有必要記錄下來,這樣以後再次碰到這類問題,也能從中獲取解答的思路。

1、同一表兩條記錄同一欄位做比較的問題
一張sql表中的最新兩條記錄裡的兩個數字型別欄位對比,最後一條比上一條的值大則輸出上升,一樣大輸出持平 比上一條小則輸出下降 這個資料查詢怎麼寫?

if object_id('[tb]') is not null drop table [tb]
go 
create table [tb]([Id] int,[Name] varchar(3),[Result] int,[Date] datetime)
insert [tb]
select 1,'001',90,'2013-11-10' union all
select 2,'002',85,'2013-11-10' union all
select 3,'003',87,'2013-11-10' union all
select 4,'001',95,'2013-11-15' union all
select 5,'002',83,'2013-11-15' union all
select 6,'003',89,'2013-11-15' union all
select 7,'001',92,'2013-11-20' union ALL
select 8,'002',83,'2013-11-20' union all
select 9,'003',88,'2013-11-20'
go


;with t
as
(
select *,
       ROW_NUMBER() over(partition by [Name] order by [Date] desc) rownum
from tb
)

select t1.Name,t1.Result,
       case when t1.[Result] > t2.[Result] then '上升'
            when t1.[Result] = t2.[Result] then '持平'
            when t1.[Result] < t2.[Result] then '下降'
       end flag
from t t1
left join t t2
       on t1.Name = t2.Name and t1.rownum = t2.rownum - 1
          and t2.rownum = 2
where t1.rownum = 1 
/*
Name	Result	flag
001	92	下降
002	83	持平
003	88	下降
*/

2、求sql,看似簡單。

http://bbs.csdn.net/topics/390620423

No             FLAG  

1         Z         
2         Z         
3         Z         
4         L         
5         Z         
6         L         
7         L         
8         L   
SQL2000資料庫,查詢結果
FLAG-Z   FLAG-L
1          4
2          6
3          7
4          8


我的解法,最關鍵的是如何生成行號,分別對不同的資料產生行號,由於是2000資料庫,稍微有點麻煩:
drop table t

create table t(No int,FLAG varchar(10));

insert into t
select 1        , 	'Z' union all     
select 2        , 	'Z' union all         
select 3        , 	'Z' union all
select 4        , 	'L' union all         
select 5        , 	'Z' union all         
select 6        , 	'L' union all         
select 7        ,	'L' union all         
select 8        , 	'L'

select z.no,L.no
from 
(
select *,
       (select count(*) from t t2 where t2.no <= t1.no and t2.flag = 'z') as rownum
from t t1
where flag = 'z'
)z
inner join 
(
select *,
       (select count(*) from t t2 where t2.no <= t1.no and t2.flag = 'L') as rownum
from t t1
where flag = 'L'
)L
 on z.rownum = L.rownum
/*
no	no
1	4
2	6
3	7
5	8
*/

如果是2005資料庫,那麼就簡單多了:
drop table t

create table t(No int,FLAG varchar(10));

insert into t
select 1        , 	'Z' union all     
select 2        , 	'Z' union all         
select 3        , 	'Z' union all
select 4        , 	'L' union all         
select 5        , 	'Z' union all         
select 6        , 	'L' union all         
select 7        ,	'L' union all         
select 8        , 	'L'

select t1.no,t2.no
from 
(
select *,
       row_number() over(partition by flag order by no) as rownum 
from t
)t1
inner join 
(
select *,
       row_number() over(partition by flag order by no) as rownum 
from t
)t2
on t1.rownum = t2.rownum
   and t1.flag = 'z'
   and t2.flag = 'L'

/*
no	no
1	4
2	6
3	7
5	8
*/