求購事項如下:收總結:一個總結(帶SQL的哦,純中文的不要)給50~100分,諸如dawugui的“張三,李四交叉表”, roy88的去重復,有多少我收多少!收例子:一個例子給10~50分,諸如遞歸的例子,游標的例子,join的例子啊等等,有多少我收多少!其他:常見的錯誤啊,注意點啊,小技巧啊等等只要你覺得值得賣我就買!一個10分,有多少我收多少!
PS: 1.結果也分享給那些同樣愛SQL的同道中人
    2.我會另開N貼送分,只要你有貨,絕不少你一分,絕不像CCAV,governnent,更不是GCD
    3.鏈接的不要,Debug出錯的不算
    4.過年后過來結貼,2月5號左右
    5.張三、李四、去重復我自己來,大家就不要貼了
    6.純UP,JF,頂!的就不要貼了,先謝謝了!

解决方案 »

  1.   

    求购事项如下: 收总结:一个总结(带SQL的哦,纯中文的不要)给50~100分,诸如dawugui的“张三,李四交叉表”, roy88的去重复,有多少我收多少! 收例子:一个例子给10~50分,诸如递归的例子,游标的例子,join的例子啊等等,有多少我收多少! 其它:常见的错误啊,注意点啊,小技巧啊等等只要你觉得值得卖我就买!一个10分,有多少我收多少! 
    PS: 1.结果也分享给那些同样爱SQL的同道中人 
        2.我会另开N贴送分,只要你有货,绝不少你一分,绝不像CCAV,governnent,更不是GCD 
        3.链接的不要,Debug出错的不算 
        4.过年后过来结贴,2月5号左右 
        5.张三、李四、去重复我自己来,大家就不要贴了 
        6.纯UP,JF,顶!的就不要贴了,先谢谢了!
      

  2.   

    Sql Server2005 4个排名函数: RANK(),DENSE_RANK(),ROW_NUMBER(),NTILE() 
    下面是对这4个函数的解释:
    RANK() 
    返回结果集的分区内每行的排名。行的排名是相关行之前的排名数加一。
    如果两个或多个行与一个排名关联,则每个关联行将得到相同的排名。
    例如,如果两位销售员具有相同的SalesYTD值,则他们将并列第一。由于已有两行排名在前,所以具有下一个最大SalesYTD的销售人员将排名第三。
    因此,RANK 函数并不总返回连续整数。
    DENSE_RANK()
    返回结果集分区中行的排名,在排名中没有任何间断。行的排名等于所讨论行之前的所有排名数加一。
    如果有两个或多个行受同一个分区中排名的约束,则每个约束行将接收相同的排名。
    例如,如果两位顶尖销售员具有相同的 SalesYTD 值,则他们将并列第一。接下来 SalesYTD 最高的销售人员排名第二。该排名等于该行之前的所有行数加一。
    因此,DENSE_RANK 函数返回的数字没有间断,并且始终具有连续的排名。 
    ROW_NUMBER()
    回结果集分区内行的序列号,每个分区的第一行从 1 开始。
    ORDER BY 子句可确定在特定分区中为行分配唯一 ROW_NUMBER 的顺序。
    NTILE()
    将有序分区中的行分发到指定数目的组中。各个组有编号,编号从一开始。对于每一个行,NTILE 将返回此行所属的组的编号。
    如果分区的行数不能被 integer_expression 整除,则将导致一个成员有两种大小不同的组。按照 OVER 子句指定的顺序,较大的组排在较小的组前面。
    例如,如果总行数是 53,组数是 5,则前三个组每组包含 11 行,其余两个组每组包含 10 行。
    另一方面,如果总行数可被组数整除,则行数将在组之间平均分布。
    例如,如果总行数为 50,有五个组,则每组将包含 10 行。
    --演示例题,建一个table
    create table rankorder(
    orderid int,
    qty int
    )
    go
    --插入数据
    insert rankorder values(30,10)
    insert rankorder values(10,10)
    insert rankorder values(80,10)
    insert rankorder values(40,10)
    insert rankorder values(30,15)
    insert rankorder values(30,20)
    insert rankorder values(22,20)
    insert rankorder values(21,20)
    insert rankorder values(10,30)
    insert rankorder values(30,30)
    insert rankorder values(40,40)
    go
    --查询出各类排名
    SELECT orderid,qty,
      ROW_NUMBER() OVER(ORDER BY qty) AS rownumber,
      RANK()       OVER(ORDER BY qty) AS [rank],
      DENSE_RANK() OVER(ORDER BY qty) AS denserank ,
      NTILE(3) OVER(ORDER BY qty) AS [NTILE]
    FROM rankorder
    ORDER BY qty
    --结果
    --ROW_NUMBER()是按qty由小到大逐一排名,不并列,排名连续
    --RANK()是按qty由小到大逐一排名,并列,排名不连续
    --DENSE_RANK()是按qty由小到大逐一排名,并列,排名连续
    --NTILE()是按qty由小到大分成3组逐一排名,并列,排名连续
    orderid    qty    rownumber    rank    denserank    NTILE
    30        10    1            1        1            1
    10        10    2            1        1            1
    80        10    3            1        1            1
    40        10    4            1        1            1
    30        15    5            5        2            2
    30        20    6            6        3            2
    22        20    7            6        3            2
    21        20    8            6        3            2
    10        30    9            9        4            3
    30        30    10           9        4            3
    40        40    11           11       5            3
    sql 2005实现排名非常方便,但是用sql 2000实现排名就比较麻烦,下面是sql 2000的实现代码
    --RANK在sql 2000中的实现
    select orderid,qty,
        (select count(1)+1 from rankorder where qty<r.qty) as [rank]
    from rankorder r
    ORDER BY qty
    go
    --ROW_NUMBER在sql 2000中的实现
    --利用临时表和IDENTITY(函数)
    select identity(int,1,1) as [ROW_NUMBER],orderid,qty
    into #tem             
    from rankorder
    select orderid,qty,[ROW_NUMBER]
    from #tem
    drop table #tem
    go
    --DENSE_RANK在sql 2000中的实现
    select identity(int,1,1) as ids,  qty
    into #t
    from rankorder
    group by qty
    order by qty
    select r.orderid,r.qty,t.ids as [DENSE_RANK]
    from rankorder r join #t  t
    on r.qty=t.qty
    drop table #t
    go
    排名函数是与窗口函数OVER()配合一起使用的。
    如果借助OVER子句的参数PARTITION BY,就可以将结果集分为多个分区。排名函数将在每个分区内进行排名.
    --例题
    SELECT orderid,qty,
    DENSE_RANK() OVER(ORDER BY qty) AS a ,
    DENSE_RANK() OVER(PARTITION BY orderid ORDER BY qty) AS b     
    FROM rankorder
    ORDER BY qty
    --说明:
    --a列是在全部记录上进行的排名
    --b列是把orderid中的记录分成了10,21,22,30,40,80这6个区,再在每个区上进行的排名。
    orderid    qty    a    b
    10        10    1    1
    30        10    1    1
    40        10    1    1
    80        10    1    1
    30        15    2    2
    30        20    3    3
    21        20    3    1
    22        20    3    1
    10        30    4    2
    30        30    4    4
    40        40    5    2
    我们看到排名函数可以很简便的得到各种类型的排名
      

  3.   


    /*
    标题:普通行列转换(version 2.0)
    作者:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开)
    时间:2008-03-09
    地点:广东深圳
    说明:普通行列转换(version 1.0)仅针对sql server 2000提供静态和动态写法,version 2.0增加sql server 2005的有关写法。问题:假设有张学生成绩表(tb)如下:
    姓名 课程 分数
    张三 语文 74
    张三 数学 83
    张三 物理 93
    李四 语文 74
    李四 数学 84
    李四 物理 94
    想变成(得到如下结果): 
    姓名 语文 数学 物理 
    ---- ---- ---- ----
    李四 74   84   94
    张三 74   83   93
    -------------------
    */create table tb(姓名 varchar(10) , 课程 varchar(10) , 分数 int)
    insert into tb values('张三' , '语文' , 74)
    insert into tb values('张三' , '数学' , 83)
    insert into tb values('张三' , '物理' , 93)
    insert into tb values('李四' , '语文' , 74)
    insert into tb values('李四' , '数学' , 84)
    insert into tb values('李四' , '物理' , 94)
    go--SQL SERVER 2000 静态SQL,指课程只有语文、数学、物理这三门课程。(以下同)
    select 姓名 as 姓名 ,
      max(case 课程 when '语文' then 分数 else 0 end) 语文,
      max(case 课程 when '数学' then 分数 else 0 end) 数学,
      max(case 课程 when '物理' then 分数 else 0 end) 物理
    from tb
    group by 姓名--SQL SERVER 2000 动态SQL,指课程不止语文、数学、物理这三门课程。(以下同)
    declare @sql varchar(8000)
    set @sql = 'select 姓名 '
    select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
    from (select distinct 课程 from tb) as a
    set @sql = @sql + ' from tb group by 姓名'
    exec(@sql) --SQL SERVER 2005 静态SQL。
    select * from (select * from tb) a pivot (max(分数) for 课程 in (语文,数学,物理)) b--SQL SERVER 2005 动态SQL。
    declare @sql varchar(8000)
    select @sql = isnull(@sql + '],[' , '') + 课程 from tb group by 课程
    set @sql = '[' + @sql + ']'
    exec ('select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @sql + ')) b')---------------------------------/*
    问题:在上述结果的基础上加平均分,总分,得到如下结果:
    姓名 语文 数学 物理 平均分 总分 
    ---- ---- ---- ---- ------ ----
    李四 74   84   94   84.00  252
    张三 74   83   93   83.33  250
    */--SQL SERVER 2000 静态SQL。
    select 姓名 姓名,
      max(case 课程 when '语文' then 分数 else 0 end) 语文,
      max(case 课程 when '数学' then 分数 else 0 end) 数学,
      max(case 课程 when '物理' then 分数 else 0 end) 物理,
      cast(avg(分数*1.0) as decimal(18,2)) 平均分,
      sum(分数) 总分
    from tb
    group by 姓名--SQL SERVER 2000 动态SQL。
    declare @sql varchar(8000)
    set @sql = 'select 姓名 '
    select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
    from (select distinct 课程 from tb) as a
    set @sql = @sql + ' , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名'
    exec(@sql) --SQL SERVER 2005 静态SQL。
    select m.* , n.平均分 , n.总分 from
    (select * from (select * from tb) a pivot (max(分数) for 课程 in (语文,数学,物理)) b) m,
    (select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) n
    where m.姓名 = n.姓名--SQL SERVER 2005 动态SQL。
    declare @sql varchar(8000)
    select @sql = isnull(@sql + ',' , '') + 课程 from tb group by 课程
    exec ('select m.* , n.平均分 , n.总分 from
    (select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @sql + ')) b) m , 
    (select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) n
    where m.姓名 = n.姓名')drop table tb ------------------
    ------------------/*
    问题:如果上述两表互相换一下:即表结构和数据为:
    姓名 语文 数学 物理
    张三 74  83  93
    李四 74  84  94
    想变成(得到如下结果): 
    姓名 课程 分数 
    ---- ---- ----
    李四 语文 74
    李四 数学 84
    李四 物理 94
    张三 语文 74
    张三 数学 83
    张三 物理 93
    --------------
    */create table tb(姓名 varchar(10) , 语文 int , 数学 int , 物理 int)
    insert into tb values('张三',74,83,93)
    insert into tb values('李四',74,84,94)
    go--SQL SERVER 2000 静态SQL。
    select * from
    (
     select 姓名 , 课程 = '语文' , 分数 = 语文 from tb 
     union all
     select 姓名 , 课程 = '数学' , 分数 = 数学 from tb
     union all
     select 姓名 , 课程 = '物理' , 分数 = 物理 from tb
    ) t
    order by 姓名 , case 课程 when '语文' then 1 when '数学' then 2 when '物理' then 3 end--SQL SERVER 2000 动态SQL。
    --调用系统表动态生态。
    declare @sql varchar(8000)
    select @sql = isnull(@sql + ' union all ' , '' ) + ' select 姓名 , [课程] = ' + quotename(Name , '''') + ' , [分数] = ' + quotename(Name) + ' from tb'
    from syscolumns 
    where name! = N'姓名' and ID = object_id('tb') --表名tb,不包含列名为姓名的其它列
    order by colid asc
    exec(@sql + ' order by 姓名 ')--SQL SERVER 2005 动态SQL。
    select 姓名 , 课程 , 分数 from tb unpivot (分数 for 课程 in([语文] , [数学] , [物理])) t--SQL SERVER 2005 动态SQL,同SQL SERVER 2000 动态SQL。--------------------
    /*
    问题:在上述的结果上加个平均分,总分,得到如下结果:
    姓名 课程   分数
    ---- ------ ------
    李四 语文   74.00
    李四 数学   84.00
    李四 物理   94.00
    李四 平均分 84.00
    李四 总分   252.00
    张三 语文   74.00
    张三 数学   83.00
    张三 物理   93.00
    张三 平均分 83.33
    张三 总分   250.00
    ------------------
    */select * from
    (
     select 姓名 as 姓名 , 课程 = '语文' , 分数 = 语文 from tb 
     union all
     select 姓名 as 姓名 , 课程 = '数学' , 分数 = 数学 from tb
     union all
     select 姓名 as 姓名 , 课程 = '物理' , 分数 = 物理 from tb
     union all
     select 姓名 as 姓名 , 课程 = '平均分' , 分数 = cast((语文 + 数学 + 物理)*1.0/3 as decimal(18,2)) from tb
     union all
     select 姓名 as 姓名 , 课程 = '总分' , 分数 = 语文 + 数学 + 物理 from tb
    ) t
    order by 姓名 , case 课程 when '语文' then 1 when '数学' then 2 when '物理' then 3 when '平均分' then 4 when '总分' then 5 enddrop table tb
      

  4.   


    --按某一字段分组取最大(小)值所在行的数据
    --(爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开) 2007-10-23于浙江杭州)
    /*
    数据如下:
    name val memo
    a    2   a2(a的第二个值)
    a    1   a1--a的第一个值
    a    3   a3:a的第三个值
    b    1   b1--b的第一个值
    b    3   b3:b的第三个值
    b    2   b2b2b2b2
    b    4   b4b4
    b    5   b5b5b5b5b5
    */
    --创建表并插入数据:
    create table tb(name varchar(10),val int,memo varchar(20))
    insert into tb values('a',    2,   'a2(a的第二个值)')
    insert into tb values('a',    1,   'a1--a的第一个值')
    insert into tb values('a',    3,   'a3:a的第三个值')
    insert into tb values('b',    1,   'b1--b的第一个值')
    insert into tb values('b',    3,   'b3:b的第三个值')
    insert into tb values('b',    2,   'b2b2b2b2')
    insert into tb values('b',    4,   'b4b4')
    insert into tb values('b',    5,   'b5b5b5b5b5')
    go--一、按name分组取val最大的值所在行的数据。
    --方法1:
    select a.* from tb a where val = (select max(val) from tb where name = a.name) order by a.name
    --方法2:
    select a.* from tb a where not exists(select 1 from tb where name = a.name and val > a.val)
    --方法3:
    select a.* from tb a,(select name,max(val) val from tb group by name) b where a.name = b.name and a.val = b.val order by a.name
    --方法4:
    select a.* from tb a inner join (select name , max(val) val from tb group by name) b on a.name = b.name and a.val = b.val order by a.name
    --方法5
    select a.* from tb a where 1 > (select count(*) from tb where name = a.name and val > a.val ) order by a.name
    /*
    name       val         memo                 
    ---------- ----------- -------------------- 
    a          3           a3:a的第三个值
    b          5           b5b5b5b5b5
    */--二、按name分组取val最小的值所在行的数据。
    --方法1:
    select a.* from tb a where val = (select min(val) from tb where name = a.name) order by a.name
    --方法2:
    select a.* from tb a where not exists(select 1 from tb where name = a.name and val < a.val)
    --方法3:
    select a.* from tb a,(select name,min(val) val from tb group by name) b where a.name = b.name and a.val = b.val order by a.name
    --方法4:
    select a.* from tb a inner join (select name , min(val) val from tb group by name) b on a.name = b.name and a.val = b.val order by a.name
    --方法5
    select a.* from tb a where 1 > (select count(*) from tb where name = a.name and val < a.val) order by a.name
    /*
    name       val         memo                 
    ---------- ----------- -------------------- 
    a          1           a1--a的第一个值
    b          1           b1--b的第一个值
    */--三、按name分组取第一次出现的行所在的数据。
    select a.* from tb a where val = (select top 1 val from tb where name = a.name) order by a.name
    /*
    name       val         memo                 
    ---------- ----------- -------------------- 
    a          2           a2(a的第二个值)
    b          1           b1--b的第一个值
    */--四、按name分组随机取一条数据。
    select a.* from tb a where val = (select top 1 val from tb where name = a.name order by newid()) order by a.name
    /*
    name       val         memo                 
    ---------- ----------- -------------------- 
    a          1           a1--a的第一个值
    b          5           b5b5b5b5b5
    */--五、按name分组取最小的两个(N个)val
    select a.* from tb a where 2 > (select count(*) from tb where name = a.name and val < a.val ) order by a.name,a.val
    select a.* from tb a where val in (select top 2 val from tb where name=a.name order by val) order by a.name,a.val
    select a.* from tb a where exists (select count(*) from tb where name = a.name and val < a.val having Count(*) < 2) order by a.name,a.val
    /*
    name       val         memo                 
    ---------- ----------- -------------------- 
    a          1           a1--a的第一个值
    a          2           a2(a的第二个值)
    b          1           b1--b的第一个值
    b          2           b2b2b2b2
    */--六、按name分组取最大的两个(N个)val
    select a.* from tb a where 2 > (select count(*) from tb where name = a.name and val > a.val ) order by a.name,a.val
    select a.* from tb a where val in (select top 2 val from tb where name=a.name order by val desc) order by a.name,a.val
    select a.* from tb a where exists (select count(*) from tb where name = a.name and val > a.val having Count(*) < 2) order by a.name , a.val
    /*
    name       val         memo                 
    ---------- ----------- -------------------- 
    a          2           a2(a的第二个值)
    a          3           a3:a的第三个值
    b          4           b4b4
    b          5           b5b5b5b5b5
    */
    --七,如果整行数据有重复,所有的列都相同。
    /*
    数据如下:
    name val memo
    a    2   a2(a的第二个值)
    a    1   a1--a的第一个值
    a    1   a1--a的第一个值
    a    3   a3:a的第三个值
    a    3   a3:a的第三个值
    b    1   b1--b的第一个值
    b    3   b3:b的第三个值
    b    2   b2b2b2b2
    b    4   b4b4
    b    5   b5b5b5b5b5
    */
    --在sql server 2000中只能用一个临时表来解决,生成一个自增列,先对val取最大或最小,然后再通过自增列来取数据。
    --创建表并插入数据:
    create table tb(name varchar(10),val int,memo varchar(20))
    insert into tb values('a',    2,   'a2(a的第二个值)')
    insert into tb values('a',    1,   'a1--a的第一个值')
    insert into tb values('a',    1,   'a1--a的第一个值')
    insert into tb values('a',    3,   'a3:a的第三个值')
    insert into tb values('a',    3,   'a3:a的第三个值')
    insert into tb values('b',    1,   'b1--b的第一个值')
    insert into tb values('b',    3,   'b3:b的第三个值')
    insert into tb values('b',    2,   'b2b2b2b2')
    insert into tb values('b',    4,   'b4b4')
    insert into tb values('b',    5,   'b5b5b5b5b5')
    goselect * , px = identity(int,1,1) into tmp from tbselect m.name,m.val,m.memo from
    (
      select t.* from tmp t where val = (select min(val) from tmp where name = t.name)
    ) m where px = (select min(px) from
    (
      select t.* from tmp t where val = (select min(val) from tmp where name = t.name)
    ) n where n.name = m.name)drop table tb,tmp/*
    name       val         memo
    ---------- ----------- --------------------
    a          1           a1--a的第一个值
    b          1           b1--b的第一个值(2 行受影响)
    */
    --在sql server 2005中可以使用row_number函数,不需要使用临时表。
    --创建表并插入数据:
    create table tb(name varchar(10),val int,memo varchar(20))
    insert into tb values('a',    2,   'a2(a的第二个值)')
    insert into tb values('a',    1,   'a1--a的第一个值')
    insert into tb values('a',    1,   'a1--a的第一个值')
    insert into tb values('a',    3,   'a3:a的第三个值')
    insert into tb values('a',    3,   'a3:a的第三个值')
    insert into tb values('b',    1,   'b1--b的第一个值')
    insert into tb values('b',    3,   'b3:b的第三个值')
    insert into tb values('b',    2,   'b2b2b2b2')
    insert into tb values('b',    4,   'b4b4')
    insert into tb values('b',    5,   'b5b5b5b5b5')
    goselect m.name,m.val,m.memo from
    (
      select * , px = row_number() over(order by name , val) from tb
    ) m where px = (select min(px) from
    (
      select * , px = row_number() over(order by name , val) from tb
    ) n where n.name = m.name)drop table tb/*
    name       val         memo
    ---------- ----------- --------------------
    a          1           a1--a的第一个值
    b          1           b1--b的第一个值(2 行受影响)
    */
      

  5.   


    /*
    标题:查询指定节点及其所有子节点的函数
    作者:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开) 
    时间:2008-05-12
    地点:广东深圳
    */create table tb(id varchar(3) , pid varchar(3) , name varchar(10))
    insert into tb values('001' , null  , '广东省')
    insert into tb values('002' , '001' , '广州市')
    insert into tb values('003' , '001' , '深圳市')
    insert into tb values('004' , '002' , '天河区')
    insert into tb values('005' , '003' , '罗湖区')
    insert into tb values('006' , '003' , '福田区')
    insert into tb values('007' , '003' , '宝安区')
    insert into tb values('008' , '007' , '西乡镇')
    insert into tb values('009' , '007' , '龙华镇')
    insert into tb values('010' , '007' , '松岗镇')
    go--查询指定节点及其所有子节点的函数
    create function f_cid(@ID varchar(3)) returns @t_level table(id varchar(3) , level int)
    as
    begin
      declare @level int
      set @level = 1
      insert into @t_level select @id , @level
      while @@ROWCOUNT > 0
      begin
        set @level = @level + 1
        insert into @t_level select a.id , @level
        from tb a , @t_Level b
        where a.pid = b.id and b.level = @level - 1
      end
      return
    end
    go--调用函数查询001(广东省)及其所有子节点
    select a.* from tb a , f_cid('001') b where a.id = b.id order by a.id
    /*
    id   pid  name       
    ---- ---- ---------- 
    001  NULL 广东省
    002  001  广州市
    003  001  深圳市
    004  002  天河区
    005  003  罗湖区
    006  003  福田区
    007  003  宝安区
    008  007  西乡镇
    009  007  龙华镇
    010  007  松岗镇(所影响的行数为 10 行)
    */--调用函数查询002(广州市)及其所有子节点
    select a.* from tb a , f_cid('002') b where a.id = b.id order by a.id
    /*
    id   pid  name       
    ---- ---- ---------- 
    002  001  广州市
    004  002  天河区(所影响的行数为 2 行)
    */--调用函数查询003(深圳市)及其所有子节点
    select a.* from tb a , f_cid('003') b where a.id = b.id order by a.id
    /*
    id   pid  name       
    ---- ---- ---------- 
    003  001  深圳市
    005  003  罗湖区
    006  003  福田区
    007  003  宝安区
    008  007  西乡镇
    009  007  龙华镇
    010  007  松岗镇(所影响的行数为 7 行)
    */drop table tb
    drop function f_cid
      

  6.   


    /*
    标题:查询指定节点及其所有父节点的函数
    作者:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开) 
    时间:2008-05-12
    地点:广东深圳
    */create table tb(id varchar(3) , pid varchar(3) , name varchar(10))
    insert into tb values('001' , null  , '广东省')
    insert into tb values('002' , '001' , '广州市')
    insert into tb values('003' , '001' , '深圳市')
    insert into tb values('004' , '002' , '天河区')
    insert into tb values('005' , '003' , '罗湖区')
    insert into tb values('006' , '003' , '福田区')
    insert into tb values('007' , '003' , '宝安区')
    insert into tb values('008' , '007' , '西乡镇')
    insert into tb values('009' , '007' , '龙华镇')
    insert into tb values('010' , '007' , '松岗镇')
    go--查询指定节点及其所有父节点的函数
    create function f_pid(@id varchar(3)) returns @t_level table(id varchar(3))
    as
    begin
      insert into @t_level select @id
      select @id = pid from tb where id = @id and pid is not null
      while @@ROWCOUNT > 0
      begin
        insert into @t_level select @id select @id = pid from tb where id = @id and pid is not null
      end
      return
    end
    go--调用函数查询002(广州市)及其所有父节点
    select a.* from tb a , f_pid('002') b where a.id = b.id order by a.id
    /*
    id   pid  name       
    ---- ---- ---------- 
    001  NULL 广东省
    002  001  广州市(所影响的行数为 2 行)
    */--调用函数查询003(深圳市)及其所有父节点
    select a.* from tb a , f_pid('003') b where a.id = b.id order by a.id
    /*
    id   pid  name       
    ---- ---- ---------- 
    001  NULL 广东省
    003  001  深圳市(所影响的行数为 2 行)
    */--调用函数查询008(西乡镇)及其所有父节点
    select a.* from tb a , f_pid('008') b where a.id = b.id order by a.id
    /*
    id   pid  name       
    ---- ---- ---------- 
    001  NULL 广东省
    003  001  深圳市
    007  003  宝安区
    008  007  西乡镇(所影响的行数为 4 行)
    */drop table tb
    drop function f_pid
      

  7.   


    /*
    标题:分解字符串并查询相关数据
    作者:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开) 
    时间:2008-03-18
    地点:广东深圳
    说明:通过使用函数等方法分解字符串查询相关数据。问题:通过分解一个带某种符号分隔的字符串在数据库中查找相关数据。
    例如 @str = '1,2,3',查询下表得到记录1,4,5,6
    ID TypeID
    1  1,2,3,4,5,6,7,8,9,10,11,12
    2  2,3 
    3  3,7,8,9 
    4  2,6 
    5  4,5
    6  6,7 
    */
    -----------------------------
    create table tb (ID int , TypeID varchar(30)) 
    insert into tb values(1 , '1,2,3,4,5,6,7,8,9,10,11,12') 
    insert into tb values(2 , '2,3') 
    insert into tb values(3 , '3,7,8,9') 
    insert into tb values(4 , '2,6') 
    insert into tb values(5 , '4,5')
    insert into tb values(6 , '6,7')
    go
    -----------------------------
    --如果仅仅是一个,如@str = '1'.
    declare @str as varchar(30)
    set @str = '1'
    select * from tb where charindex(',' + @str + ',' , ',' + TypeID + ',') > 0
    select * from tb where ',' + TypeID + ',' like '%,' + @str + ',%'
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    (所影响的行数为 1 行)
    */-----------------------------
    --如果包含两个,如@str = '1,2'.
    declare @str as varchar(30)
    set @str = '1,2'
    select * from tb where charindex(',' + left(@str , charindex(',' , @str) - 1) + ',' , ',' + typeid + ',') > 0 or 
      charindex(',' + substring(@str , charindex(',' , @str) + 1 , len(@str)) + ',' , ',' + typeid + ',') > 0
    select * from tb where ',' + typeid + ',' like '%,' + left(@str , charindex(',' , @str) - 1) + ',%' or 
      ',' + typeid + ',' like '%,' + substring(@str , charindex(',' , @str) + 1 , len(@str)) + ',%'
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    4           2,6
    (所影响的行数为 3 行)
    */-------------------------------------------
    --如果包含三个或四个,用PARSENAME函数来处理.
    declare @str as varchar(30)
    set @str = '1,2,3,4'
    select * from tb where 
      charindex(',' + parsename(replace(@str , ',' , '.') , 4) + ',' , ',' + typeid + ',') > 0 or
      charindex(',' + parsename(replace(@str , ',' , '.') , 3) + ',' , ',' + typeid + ',') > 0 or
      charindex(',' + parsename(replace(@str , ',' , '.') , 2) + ',' , ',' + typeid + ',') > 0 or
      charindex(',' + parsename(replace(@str , ',' , '.') , 1) + ',' , ',' + typeid + ',') > 0 
    select * from tb where 
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 4) + ',%' or
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 3) + ',%' or
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 2) + ',%' or
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 1) + ',%'
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    3           3,7,8,9
    4           2,6
    5           4,5
    (所影响的行数为 5 行)
    */---------------------------------------
    --如果超过四个,则只能使用函数或动态SQL来分解并查询数据。
    /*
    名称:fn_split函数.
    功能:实现字符串分隔功能的函数
    */
    create function dbo.fn_split(@inputstr varchar(8000), @seprator varchar(10))
    returns @temp table (a varchar(200))
    as 
    begin
      declare @i int
      set @inputstr = rtrim(ltrim(@inputstr))
      set @i = charindex(@seprator , @inputstr)
      while @i >= 1
      begin
        insert @temp values(left(@inputstr , @i - 1))
        set @inputstr = substring(@inputstr , @i + 1 , len(@inputstr) - @i)
        set @i = charindex(@seprator , @inputstr)
      end
      if @inputstr <> '\'
      insert @temp values(@inputstr)
      return 
    end
    go--调用
    declare @str as varchar(30)
    set @str = '1,2,3,4,5'select distinct m.* from tb m,
    (select * from dbo.fn_split(@str,',')) n
    where charindex(',' + n.a + ',' , ',' + m.typeid + ',') > 0drop table tb
    drop function dbo.fn_split /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    3           3,7,8,9
    4           2,6
    5           4,5
    (所影响的行数为 5 行)
    */------------------------------------------
    --使用动态SQL的语句。
    declare @str varchar(200)
    declare @sql as varchar(1000)
    set @str = '1,2,3,4,5'
    set @sql = 'select ''' + replace(@str , ',' , ''' as id union all select ''')
    set @sql = @sql + ''''
    set @sql = 'select distinct a.* from tb a , (' + @sql + ') b where charindex(' + ''','' + b.id + ' + ''',''' + ' , ' + ''','' + a.typeid + ' + ''',''' + ') > 0 '
    exec (@sql)
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    3           3,7,8,9
    4           2,6
    5           4,5
    (所影响的行数为 5 行)
    */
      

  8.   

    经典短小代码收集,越短越好,但要经典 
    http://topic.csdn.net/u/20080920/15/61bf31bf-518c-41be-9e4a-b166c878dcaf.html
      

  9.   

    转一个
    几个简单的处理时间的例子1.一个月第一天的
    Select DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)2.本周的星期一
    Select DATEADD(wk, DATEDIFF(wk,0,getdate()), 0)3.一年的第一天
    Select DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)4.季度的第一天
    Select DATEADD(qq, DATEDIFF(qq,0,getdate()), 0)5.当天的半夜
    Select DATEADD(dd, DATEDIFF(dd,0,getdate()), 0)6.上个月的最后一天
    Select dateadd(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate()), 0))7.去年的最后一天
    Select dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0))8.本月的最后一天
    Select dateadd(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0))9.本年的最后一天
    Select dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate())+1, 0))10.本月的第一个星期一
    select DATEADD(wk, DATEDIFF(wk,0,dateadd(dd,6-datepart(day,getdate()),getdate())), 0) 
      

  10.   

    我来凑下热闹:
    select a.商品编号 as 材料编号,isnull(a.数量,0) as 出库数量,isnull(b.数量,0) as 入库数量,a.日期 
    from table1 a,table2 b
    where a.商品编号 *=b.商品编号 and a.日期 *= b.日期
    union
    select 商品编号 as 材料编号,0 as 出库数量,isnull(数量,0) as 入库数量,日期 
    from table2 
    where 商品编号+日期 not in (select 商品编号+日期 from table1)
      

  11.   

    别着急贴,
    1.結果也分享給那些同樣愛SQL的同道中人 
    怎么共享先说说
      

  12.   

    SQL2005中按列聚合(取N列中的最大最小等) create table [tb](ID int identity(1,1), a int, b int, c int, d int)insert [tb] select 1,2,3,4    -- max: 4
    union all select 5,2,8,3    -- max: 8
    union all select 9,7,6,5    -- max: 9
    union all select 0,9,2,2    -- max: 9-- Method 1, by dobear
    select ID,  Max_abcd=max([value]) 
    from tb 
    unpivot([value] for [abcd] in ([a], [b], [c], [d])) as U
    group by ID/*
    ID          Max_abcd
    ----------- -----------
    1           4
    2           8
    3           9
    4           9(4 行受影响)
    */--Method 2, by fcuandy
    select ID=cast(b.ID as varchar(8)), Max_abcd=cast(b.v as varchar(8))
    from (select x=cast((select * from tb for xml path('r')) as xml)) a
    cross apply
        (select ID=x.query('./ID/text()'),v=x.query('max(./*[local-name(.)!="ID"])') 
         from a.x.nodes('//r') as t(x)) b
    /*
    ID       Max_abcd
    -------- --------
    1        4
    2        8
    3        9
    4        9(4 行受影响)
    */drop table tb
      

  13.   

    人民币小写金额转大写-- ====================================================================
    -- Title: 人民币小写金额转大写
    -- Author: dobear        Mail(MSN): [email protected]
    -- Environment: Vista + SQL2005
    -- Date: 2008-06-12
    -- Re: dobear原创,转载请注明出处,有问题请发Mail告之
    -- ====================================================================
    IF OBJECT_ID('fn_GetFormatMoney', N'FN') IS NOT NULL
        DROP FUNCTION fn_GetFormatMoney GO
    CREATE FUNCTION dbo.fn_GetFormatMoney (@money numeric(14,2))
    RETURNS NVARCHAR(32) AS
    BEGIN
        DECLARE @money_num NVARCHAR(20)    --存储金额的字符形式
            , @money_chn NVARCHAR(32)    --存储金额的中文大写形式
            , @n_chn NVARCHAR(1), @i INT    --临时变量    SELECT @money_chn=CASE WHEN @money>=0 THEN '' ELSE '(负)' END
            , @money=ABS(@money)
            , @money_num=STUFF(STR(@money, 15, 2), 13, 1, '')    --加前置空格补齐到14位(去掉小数点)
            , @i=PATINDEX('%[1-9]%', @money_num)    --找到金额最高位    WHILE @i>=1 and @i<=14
        BEGIN
            SET @n_chn=SUBSTRING(@money_num, @i, 1)    
            IF @n_chn<>'0' or (SUBSTRING(@money_num,@i+1,1)<>'0' and @i not in(4, 8, 12, 14))    --转换阿拉伯数字为中文大写形式     
                SET @money_chn=@money_chn+SUBSTRING('零壹贰叁肆伍陆柒捌玖', @n_chn+1, 1)
            IF @n_chn<>'0' or @i in(4, 8, 12)    --添加中文单位
                SET @money_chn=@money_chn+SUBSTRING('仟佰拾亿仟佰拾万仟佰拾圆角分',@i,1)      
        
            SET @i=@i+1
        END    SET @money_chn=REPLACE(@money_chn, '亿万', '亿')    --当金额为X亿零万时去掉万
        IF @money=0 SET @money_chn='零圆整'    --当金额为零时返回'零圆整'
        IF @n_chn='0' SET @money_chn=@money_chn+'整'    --当金额末尾为零分时以'整'结尾    RETURN @money_chn    --返回大写金额END
    GO功能测试:GO
    CREATE TABLE tb_money(id INT IDENTITY(1,1) PRIMARY KEY, m NUMERIC(14,2))INSERT tb_money SELECT 0
    UNION ALL SELECT 0.01
    UNION ALL SELECT 0.2
    UNION ALL SELECT 0.35
    UNION ALL SELECT 230
    UNION ALL SELECT 10000.2
    UNION ALL SELECT 10020.3
    UNION ALL SELECT 10300.45
    UNION ALL SELECT -10304.07
    UNION ALL SELECT 30210020
    UNION ALL SELECT -3020000
    UNION ALL SELECT 3020400
    UNION ALL SELECT 302040000000
    UNION ALL SELECT 302004000000.1select m as '小写金额', dbo.fn_GetFormatMoney(m) as '大写金额' from tb_money
    /*
    小写金额                                    大写金额
    --------------------------------------- --------------------------------
    0.00                                    零圆整
    0.01                                    壹分
    0.20                                    贰角整
    0.35                                    叁角伍分
    230.00                                  贰佰叁拾圆整
    10000.20                                壹万圆贰角整
    10020.30                                壹万零贰拾圆叁角整
    10300.45                                壹万零叁佰圆肆角伍分
    -10304.07                               (负)壹万零叁佰零肆圆零柒分
    30210020.00                             叁仟零贰拾壹万零贰拾圆整
    -3020000.00                             (负)叁佰零贰万圆整
    3020400.00                              叁佰零贰万零肆佰圆整
    302040000000.00                         叁仟零贰拾亿肆仟万圆整
    302004000000.10                         叁仟零贰拾亿零肆佰万圆壹角整(14 row(s) affected)
    */DROP TABLE tb_money
      

  14.   

    根据日期计算当月有多少天--1.删除测试用表
    IF OBJECT_ID(N'Test', N'U') IS NOT NULL
        DROP TABLE Test--2.建立测试表,并填充测试数据
    SELECT * INTO Test 
    FROM
    (
        SELECT CONVERT(DATETIME, '2008-1-1', 120) AS dt UNION ALL SELECT '2008-1-15' UNION ALL SELECT '2008-1-31'
        UNION ALL SELECT '2008-2-1' UNION ALL SELECT '2008-2-15' UNION ALL SELECT '2008-2-29'
        UNION ALL SELECT '2007-2-1' UNION ALL SELECT '2007-2-15' UNION ALL SELECT '2007-2-28'
        UNION ALL SELECT '2007-4-1' UNION ALL SELECT '2007-4-15' UNION ALL SELECT '2007-4-30'
    ) T--3.根据日期计算当月有多少天
    SELECT *
        --当月天数=32-[(上月最后最后一天+32天)的日期值]
        --e.g. '2008-1':32-day('2008-2-1') '2008-2':32-day('2008-3-3')
        , ds1=32-DAY(dt-DAY(dt)+32)
        
        --当月天数=当月最后一天的日期值
        --e.g. '2008-1':day('2008-1-31') '2008-2':day('2008-2-29')
        , ds2=DAY(DATEADD(mm,1,dt)-DAY(DATEADD(mm,1,dt)))    
        , ds3=DAY(DATEADD(mm, MONTH(dt), dt-DATEPART(dy,dt)))    
        , ds4=DAY(DATEADD(d, -1, CONVERT(VARCHAR(8), DATEADD(m,1,dt), 120)+'01'))    --当月天数=本月一号到下月一号的天数差值
        --e.g. datediff(d, '2008-1-1', '2008-2-1')
        , ds5=DATEDIFF(d, DATEADD(dd,1-DAY(dt),dt), DATEADD(mm, 1, DATEADD(dd,1-DAY(dt),dt)))
        , ds6=DATEDIFF(d, DATEADD(m, DATEDIFF(m, 0, dt), 0), DATEADD(m, datediff(m, 0, dt)+1, 0))
        , ds7=DATEDIFF(d, CONVERT(VARCHAR(8), dt, 120)+'01', CONVERT(VARCHAR(8), DATEADD(m,1,dt), 120)+'01')        
    from Test/*
    dt                      ds1         ds2         ds3         ds4         ds5         ds6         ds7
    ----------------------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
    2008-01-01 00:00:00.000 31          31          31          31          31          31          31
    2008-01-15 00:00:00.000 31          31          31          31          31          31          31
    2008-01-31 00:00:00.000 31          31          31          31          31          31          31
    2008-02-01 00:00:00.000 29          29          29          29          29          29          29
    2008-02-15 00:00:00.000 29          29          29          29          29          29          29
    2008-02-29 00:00:00.000 29          29          29          29          29          29          29
    2007-02-01 00:00:00.000 28          28          28          28          28          28          28
    2007-02-15 00:00:00.000 28          28          28          28          28          28          28
    2007-02-28 00:00:00.000 28          28          28          28          28          28          28
    2007-04-01 00:00:00.000 30          30          30          30          30          30          30
    2007-04-15 00:00:00.000 30          30          30          30          30          30          30
    2007-04-30 00:00:00.000 30          30          30          30          30          30          30(12 row(s) affected)
    */--4.删除测试表
    DROP TABLE Test
      

  15.   

    SQL中合并多行记录的方法总汇-- =============================================================================
    -- Title: 在SQL中分类合并数据行
    -- Author: dobear        Mail(MSN): [email protected]
    -- Environment: Vista + SQL2005
    -- Date: 2008-04-22
    -- =============================================================================--1. 创建表,添加测试数据
    CREATE TABLE tb(id int, [value] varchar(10))
    INSERT tb SELECT 1, 'aa'
    UNION ALL SELECT 1, 'bb'
    UNION ALL SELECT 2, 'aaa'
    UNION ALL SELECT 2, 'bbb'
    UNION ALL SELECT 2, 'ccc'--SELECT * FROM tb
    /**//*
    id          value
    ----------- ----------
    1           aa
    1           bb
    2           aaa
    2           bbb
    2           ccc(5 row(s) affected)
    */
    --2 在SQL2000只能用自定义函数实现
    ----2.1 创建合并函数fn_strSum,根据id合并value值
    GO
    CREATE FUNCTION dbo.fn_strSum(@id int)
    RETURNS varchar(8000)
    AS
    BEGIN
        DECLARE @values varchar(8000)
        SET @values = ''
        SELECT @values = @values + ',' + value FROM tb WHERE id=@id
        RETURN STUFF(@values, 1, 1, '')
    END
    GO-- 调用函数
    SELECT id, VALUE = dbo.fn_strSum(id) FROM tb GROUP BY id
    DROP FUNCTION dbo.fn_strSum----2.2 创建合并函数fn_strSum2,根据id合并value值
    GO
    CREATE FUNCTION dbo.fn_strSum2(@id int)
    RETURNS varchar(8000)
    AS
    BEGIN
        DECLARE @values varchar(8000)    
        SELECT @values = isnull(@values + ',', '') + value FROM tb WHERE id=@id
        RETURN @values
    END
    GO-- 调用函数
    SELECT id, VALUE = dbo.fn_strSum2(id) FROM tb GROUP BY id
    DROP FUNCTION dbo.fn_strSum2
    --3 在SQL2005中的新解法
    ----3.1 使用OUTER APPLY
    SELECT * 
    FROM (SELECT DISTINCT id FROM tb) A OUTER APPLY(
            SELECT [values]= STUFF(REPLACE(REPLACE(
                (
                    SELECT value FROM tb N
                    WHERE id = A.id
                    FOR XML AUTO
                ), '<N value="', ','), '"/>', ''), 1, 1, '')
    )N----3.2 使用XML
    SELECT id, [values]=STUFF((SELECT ','+[value] FROM tb t WHERE id=tb.id FOR XML PATH('')), 1, 1, '')
    FROM tb
    GROUP BY id--4 删除测试表tb
    drop table tb/**//*
    id          values
    ----------- --------------------
    1           aa,bb
    2           aaa,bbb,ccc(2 row(s) affected)
    */
      

  16.   

    一个典型的Sql Server 触发器应用问题:
    有两个表:
    Users表(userid,username,userpwd,sex,departid)  //userid主键
    Departments表(departid,departname,membercount) //departid主键
    两表建立了外键约束
    membercount是部门人数,在插入一个User的时候相应部门的membercount需要加1,删除的时候需要减1,
    修改某个User的departid的时候需要在旧部门人数减1,新部门人数加1。
    想用触发器实现在更新Users表时自动更新Departments表的membercount。--触发器代码
    CREATE TRIGGER tr_Users ON Users
    FOR INSERT,UPDATE,DELETE
    AS
    BEGIN
        SET NOCOUNT ON
        UPDATE Departments
        SET membercount=Dep.membercount+b.membercount    --Tb.membercount是这次操作的增量,可能为负数
        FROM Departments, (
            SELECT departid, SUM(membercount) AS membercount    --增量由统计得到
            FROM (
                SELECT departid,  1 AS membercount FROM inserted    --插入(Insert操作)或者新部门(Update操作)人数+1
                UNION ALL
                SELECT departid, -1 AS membercount FROM deleted    --删除(Delete操作)或者旧部门(Update操作)人数-1
                ) AS Ta
            GROUP BY departid
            HAVING SUM(membercount)<>0    --只取<>0的数据减少更改的记录数
        ) AS Tb
        WHERE Departments.departid=Tb.departid    --连接条件
    END
    GO
      

  17.   

    事务回滚的例子
      --//创建测试表
    create table tb(   
    id int not null constraint PK_1 primary key,
    aa int)
        
      --//设置  
    SET XACT_ABORT on     --//事务处理   
    begin tran
     insert into tb values(1,1) 
     insert into tb values(1,1) 
     print @@error
     insert into tb values(2,1)
    commit tran
      

  18.   

    13楼的代码有意思
    Select dateadd(ms,-2,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0))
    与Select dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0))
    结果一样,而且除了-1与0是一样都是今年的第一天的之外其他的都是目标日期