SQL Server 一些使用小技巧

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介: 原文:SQL Server 一些使用小技巧1、查询的时候把某一个字段的值拼接成字符串 以下是演示数据。 第一种方式:使用自定义变量 DECLARE @Names NVARCHAR(128) SET @Names='' -- 需要先赋值为空字符串,不然结果会是 null ...
原文: SQL Server 一些使用小技巧

1、查询的时候把某一个字段的值拼接成字符串

以下是演示数据。

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

DECLARE @Names NVARCHAR(128)

SET @Names=''    -- 需要先赋值为空字符串,不然结果会是 null 

SELECT @Names=@Names+S_Name+','        -- S_Name 类型为字符串类型,如果不能隐示转换,就需要强制转换
FROM Student

SELECT @Names

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

 

第二种方式:转换为 XML 格式

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

使用这种方式有一个缺点就是,不能直接赋值给变量或插入表,适用于查看时使用。

 如果想要使之能够赋值给变量或插入表中,那就需要转换一下。如下:

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 

 

2、查询一个字段同时满足多个条件的方法

举个栗子:比如现在有一些订单,而每一个订单有多个产品,现在我要查出同时具有某几个产品的订单。

再拿学生和课程来举例,一个学生可以选择多门课程,而每一门课程也可以同时被多个学生所选择,那么我现在要查出选择了某几门课程的学生。

下面是演示数据。

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

  SELECT s.S_Id,s.S_No,s.S_Name 
  FROM Student s 
  INNER JOIN Student_Course_Relation r ON s.S_Id=r.S_Id
  INNER JOIN Course c ON r.C_Id=c.C_Id
  WHERE c.C_Name='C#' OR c.C_Name='SQL' 
  GROUP BY s.S_Id,s.S_No,s.S_Name 
  HAVING COUNT(1) >= '2'            -- 这个数字是根据 where 条件来定

 

3、SQL Server 实现多行转列

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

create table OrderDemo
(
    ID        int        not null identity(1,1) primary key,
    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 

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

 

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

set @strWhere=''

-- 用作转换之后的列头
select @strWhere = @strWhere+TitleCount+','+TitleAmount+','
from 
(
    select distinct '['+YearDate+''+MonthDate+''+'数量'+']' TitleCount,'['+YearDate+''+MonthDate+''+'金额'+']' TitleAmount
    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) 

结果如下:

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

create table OrderDemo
(
    ID        int        not null identity(1,1) primary key,
    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+''+'数量'+']' TitleCount,
    '['+YearDate+''+MonthDate+''+'金额'+']' TitleAmount,
    '['+YearDate+''+MonthDate+''+'产品数量'+']' TitleProduct 
    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

比如,我现在有这样一些数据。如下:

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

可以看见这样是有错误的,那么下面有两种解决办法。

第一种: 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 

第二种: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 

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

 

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
5月前
|
SQL IDE Java
Java连接SQL Server数据库的详细操作流程
Java连接SQL Server数据库的详细操作流程
|
2月前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
4月前
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
113 13
|
4月前
|
SQL
解锁 SQL Server 2022的时间序列数据功能
【7月更文挑战第14天】要解锁SQL Server 2022的时间序列数据功能,可使用`generate_series`函数生成整数序列,例如:`SELECT value FROM generate_series(1, 10)。此外,`date_bucket`函数能按指定间隔(如周)对日期时间值分组,这些工具结合窗口函数和其他时间日期函数,能高效处理和分析时间序列数据。更多信息请参考官方文档和技术资料。
|
4月前
|
SQL 存储 网络安全
关系数据库SQLserver 安装 SQL Server
【7月更文挑战第26天】
61 6
|
4月前
|
存储 SQL C++
对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型
【7月更文挑战7天】SQL Server 中的 VARCHAR(max) vs VARCHAR(n): - VARCHAR(n) 存储最多 n 个字符(1-8000),适合短文本。 - VARCHAR(max) 可存储约 21 亿个字符,适合大量文本。 - VARCHAR(n) 在处理小数据时性能更好,空间固定。 - VARCHAR(max) 对于大文本更合适,但可能影响性能。 - 选择取决于数据长度预期和业务需求。
373 1
|
3月前
|
SQL 安全 Java
驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client
驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client
475 0
|
4月前
|
SQL Oracle 关系型数据库
MySQL、SQL Server和Oracle数据库安装部署教程
数据库的安装部署教程因不同的数据库管理系统(DBMS)而异,以下将以MySQL、SQL Server和Oracle为例,分别概述其安装部署的基本步骤。请注意,由于软件版本和操作系统的不同,具体步骤可能会有所变化。
306 3
|
4月前
|
SQL 存储 安全
数据库数据恢复—SQL Server数据库出现逻辑错误的数据恢复案例
SQL Server数据库数据恢复环境: 某品牌服务器存储中有两组raid5磁盘阵列。操作系统层面跑着SQL Server数据库,SQL Server数据库存放在D盘分区中。 SQL Server数据库故障: 存放SQL Server数据库的D盘分区容量不足,管理员在E盘中生成了一个.ndf的文件并且将数据库路径指向E盘继续使用。数据库继续运行一段时间后出现故障并报错,连接失效,SqlServer数据库无法附加查询。管理员多次尝试恢复数据库数据但是没有成功。
|
4月前
|
SQL 存储 关系型数据库
关系型数据库SQL Server学习
【7月更文挑战第4天】
77 2