分组取最值 select top n checksum binary_checksum

1、checksum

语法:CHECKSUM ( * | expression [ ,...n ] )
参数

*
指定对表的所有列进行计算。如果有任一列是非可比数据类型,则 CHECKSUM 返回错误。非可比数据类型有 text、ntext、image、XML 和 cursor,还包括以上述任一类型作为基类型的 sql_variant。 

expression
除非可比数据类型之外的任何类型的表达式。

返回值是int

返回按照对其参数列表计算出来的校验和的哈希值,可用于生成哈希索引。

它可用于对列进行等价搜索。  两个列表的相应元素具有相同类型

如果表达式列表中的某个值发生更改,则列表的校验和通常也会更改。但只在极少数情况下,校验和会保持不变。因此,我们不推荐使用 CHECKSUM 来检测值是否更改,除非应用程序可以容忍偶尔丢失更改。 

表达式的顺序影响 CHECKSUM 的结果值。

分组取最值

create table #test(areaid int, score int)

insert into #test
select 0,10
union all select 0,20
union all select 0,30
union all select 0,40
union all select 0,50
union all select 1,10
union all select 1,20
union all select 1,30
union all select 1,40
union all select 1,50
union all select 2,10
union all select 2,20
union all select 2,30
union all select 2,40
union all select 2,50

 

--查询每个area的前3名

select a.* from #test a where areaid + '' + score in (select top 3 areaid + '' + score from #test b where a.areaid=b.areaid order by score desc)
select a.* from #test a where checksum(*) in (select top 3 checksum(*) from #test b where a.areaid=b.areaid order by score desc)

--测试

select checksum('aaacccddd')  //一个比较大的整数

select checksum(20)                //原值20

checksum的最终目的就是以最快的方法为所有互异列置一个互异的整数。

测试如下:

select checksum(*) from test

结果:

10
20
30
40
50
10
20
30
40
50
42
52
62
8
18

你会看到前几列是和原值相同,但是后面开始checksum会为他们分配不同的值(虽然score值一样,但areaid不同了)

再做测试:

select checksum(score) from test

结果

10
20
30
40
50
10
20
30
40
50
10
20
30
40
50

由于指定了列“score”,所以score相同的行会得到相同的checksum结果。。

 

搜索一番:看到一个checksum的实际应用,大意如下:

 

在数据库设计中需要一列标注网页的URL地址,LINK NVARCHAR(1000)。在INSERT的时候需要判断之前有无同样的URL地址记录被插入。
也就是用select top 1 @ID=ID from Table where Link=@Link,然后判断@ID值是否大于0。

如果数据量过大,需要给LINK加为索引,但是这时会发现SQL SERVER的索引对那么大的NVARCHR是无法建立的,限制在200字符以内。

我在最早的时候解决这个问题是采用了对LINK进行MD5化,MD5的值只有几十个字符长,然后对MD5结果进行索引。但这样做性能其实一般,而且大字段的数据库索引同样会占用不少存储空间。

其实在SQL SERVER中可以设置计算字段,就是说该字段是可以是其他字段的计算结果。这样的话就用CHECKSUM来优化上述的索引问题。

做法范例:alter table tablename add csLink as CHECKSUM(Link)。

这样就建立一个csLink列,生成的CHECKSUM值是一个大的整数。对该列进行索引,相当于对BITINT型进行索引,索引存储空间也非常节约。这样在判别有无重复LINK的时候就使用:

select top 1 @ID=ID from Table where csLink=CHECKSUM(@Link) And Link=@Link

数据库会优先判断csLink索引字段,而实际测试100万条记录的CHECKSUM,无一重复,所以第一次匹配的返回条数是极少的,基本可以做到一批匹配,而考虑肯能会有重复记录,因此再加上And Link=@Link,这样是在小的数据集中再次做无索引匹配,这样性能损耗几乎没有感觉。

计算字段给我感觉就好像视图,计算字段的灵活度除了简化查找SELECT语句之外,对索引优化的作用是非常大的。CHECKSUM的用法只是发现之一,在今后一定会发现更多的有用的TIPS。

最后:CheckSum不同于Sql2005中的BINARY_CHECKSUM

 

2、BINARY_CHECKSUM

返回对表中的行或表达式列表计算的二进制校验值。BINARY_CHECKSUM 可用于检测表中行的更改。

语法

BINARY_CHECKSUM ( * | expression [ ,...n ] )

参数

*

指定对表中的所有列进行计算。BINARY_CHECKSUM 在计算中忽略具有不可比数据类型的列。不可比数据类型是 textntextimagecursor 以及基本类型为前 4 个数据类型之一的 sql_variant

expression

任何类型的表达式。BINARY_CHECKSUM 在计算中忽略具有不可比数据类型的表达式。

注释

在表中任一行上计算的 BINARY_CHECKSUM(*) 返回相同的值,只要随后没有修改行。BINARY_CHECKSUM(*) 将为大多数(但不是全部)行更改返回不同的值,并可用于检测大多数行修改。

BINARY_CHECKSUM 可应用在表达式列表上,并为给定的列表返回相同的值。如果任意两个表达式列表的对应元素具有相同的类型和字节表示法,则在这两个列表上应用的 BINARY_CHECKSUM 将返回相同的值。对于此定义,特定类型的 NULL 值被认为具有相同的字节表示法。

BINARY_CHECKSUM 和 CHECKSUM 具有相似的功能:它们可用于计算表达式列表上的校验值,且表达式的顺序将影响结果值。BINARY_CHECKSUM(*) 使用的列顺序是表或视图定义中指定的列顺序,包括计算列。

CHECKSUM 和 BINARY_CHECKSUM 仅为字符串数据类型返回不同的值,这类字符串的区域设置可能导致具有不同表示法的字符串进行等值比较。字符串数据类型为 char、varchar、nchar、nvarcharsql_variant(如果 sql_variant 的基本类型是字符串数据类型)。例如,字符串"McCavity"和"Mccavity"的 BINARY_CHECKSUM 值不同。反之,在不区分大小写的服务器中,上述字符串的 CHECKSUM 返回相同的校验值。CHECKSUM 值不应与 BINARY_CHECKSUM 值进行比较。

示例A.使用 BINARY_CHECKSUM 检测表中一行的改变。

create table cha(col1 int identity(1,1),col2 varchar(10))---基表
go
insert into cha values('a')
insert into cha values('b')
insert into cha values('c')
insert into cha values('d')
insert into cha values('e')
insert into cha values('f')
insert into cha values('g')
insert into cha values('h')
go
select *
from cha
go
create table tx(col int identity(1,1), chsum int)---验证表
go
set identity_insert tx on
insert into tx(col,chsum)
select col1,binary_checksum(*)
from cha
go
select *  --- 查看验证表
from tx 
select *
from cha
go
----更新基表,对第一行和第三行记录进行更新---
update cha
set col2='a1'
where col1=1
go
update cha
set col2='c1'
where col1=3
go
----查看基表哪些行改变了---
SELECT    col
FROM       tx
WHERE    EXISTS    (
       SELECT    col1
       FROM       cha
       WHERE       cha.col1 = tx.col
       AND    BINARY_CHECKSUM(*) <> tx.chsum)

 

 

你可能感兴趣的:(SQL)