文章出處

ROWNUMBER() OVER( PARTITION BY COL1 ORDER BY COL2)用法

今天在使用多字段去重時,由于某些字段有多種可能性,只需根據部分字段進行去重,在網上看到了rownumber() over(partition by col1 order by col2)去重的方法,很不錯,在此記錄分享下:
  row_number() OVER ( PARTITION BY COL1 ORDER BY COL2) 表示根據COL1分組,在分組內部根據 COL2排序,而此函數計算的值就表示每組內部排序后的順序編號(組內連續的唯一的).
  與rownum的區別在于:使用rownum進行排序的時候是先對結果集加入偽列rownum然后再進行排序,而此函數在包含排序從句后是先排序再計算行號碼.


row_number()rownum差不多,功能更強一點(可以在各個分組內從1開時排序).
rank()是跳躍排序,有兩個第二名時接下來就是第四名(同樣是在各個分組內).
dense_rank()l是連續排序,有兩個第二名時仍然跟著第三名。相比之下row_number是沒有重復值的.
lag(arg1,arg2,arg3):
  arg1是從其他行返回的表達式
  arg2是希望檢索的當前行分區的偏移量。是一個正的偏移量,是一個往回檢索以前的行的數目。
  arg3是在arg2表示的數目超出了分組的范圍時返回的值。


函數語法:
OPAP函數語法四部分:
1.function 本身用于對窗口中的數據進行操作;
2.partitioning clause 用于將結果集分區;
3.order by clause 用于對分區中的數據進行排序;
4.windowing clause 用于定義function在其上操作的行的集合,即function所影響的范圍;


RANK()
dense_rank()
【語法】RANK ( ) OVER ( [query_partition_clause] order_by_clause )
dense_RANK ( ) OVER ( [query_partition_clause] order_by_clause )

【功能】聚合函數RANK 和 dense_rank 主要的功能是計算一組數值中的排序值。
【參數】dense_rank與rank()用法相當,
【區別】dence_rank在并列關系是,相關等級不會跳過。rank則跳過
rank()是跳躍排序,有兩個第二名時接下來就是第四名(同樣是在各個分組內)
dense_rank()l是連續排序,有兩個第二名時仍然跟著第三名。
【說明】Oracle分析函數


ROW_NUMBER()
【語法】ROW_NUMBER() OVER (PARTITION BY COL1 ORDER BY COL2)
【功能】表示根據COL1分組,在分組內部根據 COL2排序,而這個值就表示每組內部排序后的順序編號(組內連續的唯一的)
row_number() 返回的主要是“行”的信息,并沒有排名
【參數】
【說明】Oracle分析函數

主要功能:用于取前幾名,或者最后幾名等
sum(...) over ...
【功能】連續求和分析函數
【參數】具體參示例
【說明】Oracle分析函數


lag()lead()
【語法】
lag(EXPR,<OFFSET>,<DEFAULT>) OVER ( [query_partition_clause] order_by_clause )
LEAD(EXPR,<OFFSET>,<DEFAULT>) OVER ( [query_partition_clause] order_by_clause )
【功能】表示根據COL1分組,在分組內部根據 COL2排序,而這個值就表示每組內部排序后的順序編號(組內連續的唯一的)
lead () 下一個值 lag() 上一個值

【參數】
EXPR是從其他行返回的表達式
OFFSET是缺省為1 的正數,表示相對行數。希望檢索的當前行分區的偏移量
DEFAULT是在OFFSET表示的數目超出了分組的范圍時返回的值。
【說明】Oracle分析函數

---TEST FOR ROW_NUMBER() OVER(PARTITION BY COL1 ORDER BY COL2)
DROP TABLE TEST_Y
CREATE TABLE TEST_Y(
       ID VARCHAR2 (32) PRIMARY KEY ,
       NAME VARCHAR2 (20),
       AGE NUMBER(3 ),
       DETAILS VARCHAR2 (1000)
);
INSERT INTO TEST_Y VALUES(SYS_GUID(), '海子',20 ,'面朝大海,春暖花開');
INSERT INTO TEST_Y VALUES(SYS_GUID(), '海子',30 ,'面朝大海,春暖花開');
INSERT INTO TEST_Y VALUES(SYS_GUID(), '貝多芬',43 ,'致愛麗絲');
INSERT INTO TEST_Y VALUES(SYS_GUID(), '普希金',34 ,'假如生活欺騙了你');
INSERT INTO TEST_Y VALUES(SYS_GUID(), '楊過',23 ,'黯然銷魂掌');
INSERT INTO TEST_Y VALUES(SYS_GUID(), '小龍女',32 ,'神雕俠侶');
INSERT INTO TEST_Y VALUES(SYS_GUID(), '李清照',21 ,'尋尋覓覓、冷冷清清');
INSERT INTO TEST_Y VALUES(SYS_GUID(), '周芷若',18 ,'峨眉');
INSERT INTO TEST_Y VALUES(SYS_GUID(), '趙敏',18 ,'自由');
INSERT INTO TEST_Y VALUES(SYS_GUID(), '張無忌',20 ,'倚天屠龍記');
INSERT INTO TEST_Y VALUES(SYS_GUID(), '張無忌',30 ,'倚天屠龍記');

SELECT * FROM TEST_Y;


----1. ROW_NUMBER() OVER(PARTITION BY COL1 ORDER BY COL2)
---查詢所有姓名,如果同名,則按年齡降序
SELECT NAME ,AGE,DETAILS,ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY AGE DESC) FROM TEST_Y;

----通過上面的語句可知,ROW_NUMBER() OVER(PARTITION BY COL1 ORDER BY COL2)中是按照NAME字段分組,按AGE字段排序的。
----如果只需查詢出不重復的姓名即可,則可使用如下的語句
SELECT * FROM (SELECT NAME,AGE,DETAILS ,ROW_NUMBER() OVER( PARTITION BY NAME ORDER BY AGE DESC)RN FROM TEST_Y )WHERE RN= 1;

----由查詢結果可知,姓名相同年齡小的數據被過濾掉了;可以使用ROW_NUMBER() OVER(PARTITION BY COL1 ORDER BY COL2)對部分子彈進行去重處理


----2.RANK() OVER(PARTITION BY COL1 ORDER BY COL2)
----跳躍排序
SELECT NAME ,AGE,DETAILS , RANK() OVER (PARTITION BY NAME ORDER BY AGE DESC) FROM TEST_Y;

----由查詢結果可知,相同的并列,下一個則跳躍到并列所替的序列后:如有兩個并列1,那么下一個則直接排為3,跳過2;

----3.DENSE_RANK() OVER(PARTITION BY COL1 ORDER BY COL2)
----連續排序,當有多個并列時,下一個仍然連續有序

----由查詢結果可知,當兩個并列為1時,下一個仍連續有序為2,不跳躍到3

 Lag和Lead函數可以在一次查詢中取出同一字段的前N行的數據和后N行的值。這種操作可以使用對相同表的表連接來實現,不過使用LAG和LEAD有更高的效率.
  Lag和Lead偏移量函數,其用途是:可以查出同一字段下一個值或上一個值,并作為新列存在表中.
-----4.LAG(exp_str,offset,defval) OVER(PARTITION BY NAME ORDER BY AGE)
-----exp_str 返回顯示的字段;offset是exp_str字段的偏移量,默認是1,如offset=1表示返回當前exp_str的下一個exp_str;defval當該函數無值可用的情況下返回該值。
(1) SELECT NAME ,AGE,DETAILS, LAG(NAME ,1, 'sue') OVER (PARTITION BY NAME ORDER BY AGE DESC ) FROM TEST_

(2) SELECT NAME ,AGE,DETAILS, LAG(NAME ,2, 'sue') OVER (PARTITION BY NAME ORDER BY AGE DESC ) FROM TEST_Y

(3) SELECT NAME ,AGE,DETAILS, LAG(NAME ,2, 'sue') OVER (ORDER BY AGE DESC ) FROM TEST_Y;

----5.LEAD(EXP_STR,OFFSET,DEFVAL) OVER(PARTITION BY NAME ORDER BY AGE)
-----exp_str 返回顯示的字段;offset是exp_str字段的偏移量,默認是1,如offset=1表示返回當前exp_str的上一個exp_str;
-----defval當該函數無值可用的情況下返回該值。
(1)SELECT NAME ,AGE,DETAILS, LEAD(NAME ,1, 'sue') OVER (PARTITION BY NAME ORDER BY AGE DESC ) FROM 

(2) SELECT NAME ,AGE,DETAILS, LEAD(NAME ,2, 'sue') OVER (PARTITION BY NAME ORDER BY AGE DESC ) FROM TEST_Y

(3) SELECT NAME ,AGE,DETAILS, LEAD(NAME ,1, 'sue') OVER (ORDER BY AGE DESC ) FROM TEST_Y;

-----6.SUM(COL1) OVER([PARTITION BY COL2 ] [ORDER BY COL3])
(1) SELECT NAME ,AGE,DETAILS,ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY AGE DESC),SUM (AGE) OVER( PART

(2) SELECT NAME ,AGE,DETAILS,ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY AGE DESC),SUM (AGE) OVER( PAR

(3)SELECT NAME ,AGE,DETAILS,ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY AGE DESC),SUM (AGE) OVER( ORDE

(4) SELECT NAME ,AGE,DETAILS, SUM(AGE) OVER ()  FROM TEST_Y;

 

以上內容摘抄自:http://blog.csdn.net/yinshan33/article/details/18738229

 

sum(x) over( partition by y ORDER BY z ) 分析

 

之前用過row_number(),rank()等排序與over( partition by ... ORDER BY ...),這兩個比較好理解: 先分組,然后在組內排名。

今天突然碰到sum(...) over( partition by ... ORDER BY ... ),居然搞不清除怎么執行的,所以查了些資料,做了下實操。

1. 從最簡單的開始

  sum(...) over( ),對所有行求和

  sum(...) over( order by ... ),和 = 第一行 到 與當前行同序號行的最后一行的所有值求和,文字不太好理解,請看下圖的算法解析。

with aa as
( 
SELECT 1 a,1 b, 3 c FROM dual union
SELECT 2 a,2 b, 3 c FROM dual union
SELECT 3 a,3 b, 3 c FROM dual union
SELECT 4 a,4 b, 3 c FROM dual union
SELECT 5 a,5 b, 3 c FROM dual union
SELECT 6 a,5 b, 3 c FROM dual union
SELECT 7 a,2 b, 3 c FROM dual union
SELECT 8 a,2 b, 8 c FROM dual union
SELECT 9 a,3 b, 3 c FROM dual
)
SELECT a,b,c,
sum(c) over(order by b) sum1,--有排序,求和當前行所在順序號的C列所有值
sum(c) over() sum2--無排序,求和 C列所有值

sum() over()

2. 與 partition by 結合

  sum(...) over( partition by... ),同組內所行求和

  sum(...) over( partition by... order by ... ),同第1點中的排序求和原理,只是范圍限制在組內

with aa as
( 
SELECT 1 a,1 b, 3 c FROM dual union
SELECT 2 a,2 b, 3 c FROM dual union
SELECT 3 a,3 b, 3 c FROM dual union
SELECT 4 a,4 b, 3 c FROM dual union
SELECT 5 a,5 b, 3 c FROM dual union
SELECT 6 a,5 b, 3 c FROM dual union
SELECT 7 a,2 b, 3 c FROM dual union
SELECT 7 a,2 b, 8 c FROM dual union
SELECT 9 a,3 b, 3 c FROM dual
)
SELECT a,b,c,sum(c) over( partition by b ) partition_sum,
sum(c) over( partition by b order by a desc) partition_order_sum
  FROM aa;

view sql

 

以上內容摘抄自:http://www.cnblogs.com/luhe/p/4155612.html

 

案例:

有圈子表CMSocial,圈子成員表CMSocialMember,圈子審核表CMSocialCheck,其中圈子審核被拒絕的話,修改信息后可以再次提交審核,也就是說圈子可以生成多條圈子審核信息。

如果要查詢某用戶的全部圈子,同時獲取其中每條圈子對應的最近一條審核狀態?(假設某用戶MemberID=1 )

SQL語句可以這樣寫:

SELECT 
S.CMSocialID,
S.SocialName,
S.SocialDescription,
S.SocialLogo,
S.SocialAuthority,
S.Integral,
S.SocialState,
S.IsAvailable,
SC.CheckState,
SC.Notes,
SM.CMSocialMemberID,
SM.MemberID,
SM.MemberName,
SM.MemberIntegral,
SM.EnterTime,
SM.MemberState,
SM.MemberRank,
SM.IsRecommend
FROM (SELECT * FROM CMSocialMember WHERE MemberID=1 AND IsDelete<>1 AND IsAvailable=1) AS SM 
LEFT JOIN CMSocial AS S ON S.CMSocialID=SM.CMSocialID 
LEFT JOIN (
SELECT *
FROM ( 
    SELECT ROW_NUMBER() OVER (PARTITION BY CMSocialID ORDER BY CreateTime DESC) AS group_index ,*  /* 根據 CMSocialID 分組,CreateTime倒序,生成分組內部序號 */
    FROM CMSocialCheck WHERE IsDelete<>1
    ) AS SCsub WHERE SCsub.group_index=1 /*取每個分組內部序號=1 的信息*/
) AS SC ON SC.CMSocialID=S.CMSocialID

 

注意:

SELECT ROW_NUMBER() OVER (PARTITION BY CMSocialID ORDER BY CreateTime DESC) AS group_index ,*      /* 根據 CMSocialID 分組,CreateTime倒序,生成分組內部序號 */
FROM CMSocialCheck WHERE IsDelete<>1
) AS SCsub WHERE SCsub.group_index=1 /*取每個分組內部序號=1 的信息*/

 

sql根據某一個字段重復只取第一條數據
使用分析函數row_number() over (partiion by ... order by ...)來進行分組編號,然后取分組標號值為1的記錄即可。目前主流的數據庫都有支持分析函數,很好用。
其中,partition by 是指定按哪些字段進行分組,這些字段值相同的記錄將在一起編號;order by則是指定在同一組中進行編號時是按照怎樣的順序。
示例(SQL Server 2005或以上適用):

select s.*  
from ( 
    select *, row_number() over (partition by [手機號] order by [店鋪]) as group_idx  
    from table_name
) s
where s.group_idx = 1

 

主表1條數據,對應子表,附表多條數據,取唯一:

DECLARE @Status INT;
SET @Status=1;
SELECT  p.CFProjectID AS ID,pc.Status AS StatusID,* FROM dbo.CFProject p
LEFT JOIN (
    select s.*  
    from ( 
        select *, row_number() over (partition by [SourceProjectID] order by [CFProjectID]) as group_idx  
        from dbo.CFProjectToCrowdSpace WHERE [Status]=@Status OR @Status IS NULL
    ) s
    where s.group_idx = 1
) pc ON pc.SourceProjectID=p.CFProjectId
WHERE p.CreatorID=100273  AND p.Status=3  AND p.OrganizationID=180  ORDER  BY p.CreationTime DESC

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()