设为首页 收藏本站
查看: 1710|回复: 0

[经验分享] SQL Server 一些使用小技巧

[复制链接]

尚未签到

发表于 2017-12-13 18:17:20 | 显示全部楼层 |阅读模式
  1、查询的时候把某一个字段的值拼接成字符串
  以下是演示数据。
DSC0000.png

  第一种方式:使用自定义变量
  

DECLARE @Names NVARCHAR(128)  

  

SET @Names=''  

  
SELECT @Names=@Names+S_Name+','        
  
FROM Student
  

  
SELECT @Names
  

DSC0001.png

  这种方法有一个好处就是,拼接出来的字符串可以赋值给变量或直接插入表中指定字段,可以适用于存储过程之类的。
  第二种方式:转换为 XML 格式
  

SELECT t.S_Name + ','  
FROM
  
(
  SELECT S_Name
  FROM Student
  
) t
  
FOR XML PATH('')
  

DSC0002.png

  使用这种方式有一个缺点就是,不能直接赋值给变量或插入表,适用于查看时使用。
  如果想要使之能够赋值给变量或插入表中,那就需要转换一下。如下:
  

DECLARE @Names NVARCHAR(128)  

  

SET @Names=''  

  
SELECT @Names=
  
(
  SELECT t.S_Name + ','
  FROM
  (
  SELECT S_Name
  FROM Student
  ) t
  FOR XML PATH(''),TYPE
  
).value('.','NVARCHAR(128)')
  

  
SELECT @Names
  

DSC0003.png

  2、查询一个字段同时满足多个条件的方法
  举个栗子:比如现在有一些订单,而每一个订单有多个产品,现在我要查出同时具有某几个产品的订单。
  再拿学生和课程来举例,一个学生可以选择多门课程,而每一门课程也可以同时被多个学生所选择,那么我现在要查出选择了某几门课程的学生。
  下面是演示数据。
DSC0004.png

  现在我要查出同时选择了 C# 和 SQL 课程的学生信息。如下:
  

  SELECT s.S_Id,s.S_No,s.S_NameFROM Student sINNER JOIN Student_Course_Relation r ON s.S_Id=r.S_IdINNER JOIN Course c ON r.C_Id=c.C_IdWHERE c.C_Name='C#' OR c.C_Name='SQL'  GROUP BY s.S_Id,s.S_No,s.S_Name
  HAVING COUNT(1) >= '2'            
  

DSC0005.png

  3、SQL Server 实现多行转列
  之前也写过一篇博客,SQL Server 使用 Pivot 和 UnPivot 实现行列转换,但是之前都是相对于“单列”的转换,于是最近碰到一个需要两列的问题。最后在网上找了一些相关资料,得出了下面的解决方法。下面先建立一个表,插入一些模拟的数据。如下:
  

create table OrderDemo  
(
  ID        
int        not null>CustomerCode    nvarchar(16)    not null,  OrderCount   
int        not null default(0),  TotalAmount  
decimal(13,3)    not null default(0),  YearDate   
nvarchar(8)        null,  MonthDate   
nvarchar(8)        null  
)
  

  

insert into OrderDemo  
(
  CustomerCode,
  OrderCount,
  TotalAmount,
  YearDate,
  MonthDate
  
)
  

select 'A001','23','28.650','2017','1' union all  
select 'A001','67','123.123','2017','2' union all
  
select 'A002','12','28.320','2017','1' union all
  
select 'A002','37','51.221','2017','2' union all
  
select 'A003','89','452.200','2017','1' union all
  
select 'A003','134','523.210','2017','2' union all
  
select 'A004','78','230.220','2017','1' union all
  
select 'A004','95','180.567','2017','2' union all
  
select 'A005','128','230.789','2017','1' union all
  
select 'A005','256','340.450','2017','2'
  

  
select * from OrderDemo
  

DSC0006.png

  以上的数据是模拟的按客户、订单年份和订单月份统计的订单数量和金额,由于年月的时间段非固定的,所以这里使用的是动态sql,下面直接上代码:
  

declare @strSql nvarchar(1024)  

declare @strWhere nvarchar(1024)  

  

set @strWhere=''  

  

  
select @strWhere = @strWhere+TitleCount+','+TitleAmount+','
  
from
  
(
  select distinct '['+YearDate+'年'+MonthDate+'月'+'数量'+']'>  from OrderDemo
  
) t
  

  

  
if(CHARINDEX(',',REVERSE(@strWhere))=1)
  
begin
  set @strWhere=SUBSTRING(@strWhere,1,len(@strWhere)-1)
  
end
  

  
set @strSql='select *
  from
  (
  select CustomerCode,ComDate+ColumnName ComDate,CountAndAmount
  from  
  (
  select CustomerCode,YearDate+''年''+MonthDate+''月'' ComDate,
  cast(OrderCount as nvarchar) ''数量'',
  cast(TotalAmount as nvarchar) ''金额''
  from OrderDemo
  ) a
  UNPIVOT
  (
  CountAndAmount for ColumnName
  IN ([数量],[金额])
  ) b
  ) c
  pivot
  (
  max(CountAndAmount)
  for ComDate
  in ('+ @strWhere +')
  ) d '
  

  
exec (@strSql)
  

  结果如下:
DSC0007.png

  既然两列可以这么实现,那么如果在多一列呢,或者多很多列。这里我稍稍修改了一下,多增加了一列进行测试(多列同理),修改之后的代码如下:
  

create table OrderDemo  
(
  ID        
int        not null>CustomerCode   
nvarchar(16)    not null,  OrderCount   
int        not null default(0),  ProductCount
int  not null default(0),  TotalAmount  
decimal(13,3)    not null default(0),  YearDate   
nvarchar(8)        null,  MonthDate   
nvarchar(8)        null  
)
  

  

insert into OrderDemo  
(
  CustomerCode,
  OrderCount,
  ProductCount,
  TotalAmount,
  YearDate,
  MonthDate
  
)
  

select 'A001','23','35','28.650','2017','1' union all  
select 'A001','67','75','123.123','2017','2' union all
  
select 'A002','12','18','28.320','2017','1' union all
  
select 'A002','37','42','51.221','2017','2' union all
  
select 'A003','89','98','452.200','2017','1' union all
  
select 'A003','134','150','523.210','2017','2' union all
  
select 'A004','78','99','230.220','2017','1' union all
  
select 'A004','95','102','180.567','2017','2' union all
  
select 'A005','128','138','230.789','2017','1' union all
  
select 'A005','256','280','340.450','2017','2'
  

  
select * from OrderDemo
  

  
declare @strSql nvarchar(1024)
  
declare @strWhere nvarchar(1024)
  

  
set @strWhere=''
  

  

  
select @strWhere = @strWhere+TitleCount+','+TitleAmount+','+TitleProduct+','
  
from
  
(

  select distinct '['+YearDate+'年'+MonthDate+'月'+'数量'+']'>
  '['+YearDate+'年'+MonthDate+'月'+'金额'+']'>
  '['+YearDate+'年'+MonthDate+'月'+'产品数量'+']'>  from OrderDemo
  
) t
  

  

  
if(CHARINDEX(',',REVERSE(@strWhere))=1)
  
begin
  set @strWhere=SUBSTRING(@strWhere,1,len(@strWhere)-1)
  
end
  

  
set @strSql='select *
  from
  (
  select CustomerCode,ComDate+ColumnName ComDate,CountAndAmount
  from  
  (
  select CustomerCode,YearDate+''年''+MonthDate+''月'' ComDate,
  cast(OrderCount as nvarchar) ''数量'',
  cast(TotalAmount as nvarchar) ''金额'',
  cast(ProductCount as nvarchar) ''产品数量''
  from OrderDemo
  ) a
  UNPIVOT
  (
  CountAndAmount for ColumnName
  IN ([数量],[金额],[产品数量])
  ) b
  ) c
  pivot
  (
  max(CountAndAmount)
  for ComDate
  in ('+ @strWhere +')
  ) d '
  

  
exec (@strSql)
  

  PS:需要注意的是当需要转换的列的数据类型不同时需要转换为同一种类型,比如这里的 “数量、金额、产品数量”。
  4、在子查询中使用 Order By
  比如,我现在有这样一些数据。如下:
DSC0008.png

  我现在想要使用子查询按字段 “Stu_Age” 排序,那么就有了如下代码:
DSC0009.png

  可以看见这样是有错误的,那么下面有两种解决办法。
  第一种: row_number() over() 排名开窗函数
  

  select *  from
  (
  select [StudentID],Stu_FullName,Stu_Age,Stu_Address,Stu_Phone,
  ROW_NUMBER() over(order by Stu_Age) RowNum
  from Student
  ) t
  

DSC00010.png

  第二种:TOP 100 PERCENT,英语比较好的朋友就知道 percent 就是百分比的意思,结果显而易见。top 100 percent 就表示百分之百,即全部的数据。
  

  select *  from
  (
  select top 100 percent [StudentID],Stu_FullName,Stu_Age,Stu_Address,Stu_Phone
  from Student
  order by Stu_Age
  ) t
  

  其实我个人的话还是喜欢第一种方式,第二种也是偶尔看到的。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-423757-1-1.html 上篇帖子: 利用sql server直接创建日历 下篇帖子: SQL Server创建事务——锁
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表