SQL总结之DML(MSSQL)

(本文是基于mssql的总结的SQL)

一、基本的增、删、改、查

1、基本操作

INSERT

-- 插入单条数据
insert into table1(col1,col2,…) values(value1,value2,…)
-- 插入多条数据
insert into table1(col1,col2,…) values(value1,value2,…),(value1,value2,…),…
-- 插入来自select查询的数据
insert into table1(col1,col2,…) select col1,col2,… from table2 […left join …] [where …]
-- 插入来自存储过程返回的结果集
insert into table1(col1,col2,…) exec procedure1

SELECT

(1)一般使用语法

select [ * | col1,col2,… |[count(*)|sum(col3)|max(col4)...] ] 
from table1 
[…joinon …] 
[…joinon …] 
[where …] 
[group by col1,col2] 
[order by …]

注意:
①与Group by一起使用时,才能够使用count,sum,max,min,avg等函数,且在group by后不能指定text,ntext,image数据类型的字段分组。

②聚合函数(count,sum,max,min,avg)对NULL的处理:count(1)和count(*)结果一样,都包括对null的统计,只是执行效率有高低;count(column)不包括对null值的统计,可以用isnull函数进行转换,聚合函数avg、max、min、sum 都是忽略null值的,都须通过isnull转换。

③当跨数据库(或数据库服务器)时,有时会因为用于Join的两个表所在数据库的字符集不一致,在join… on后面直接用“t1.Name = t2.Title”会得不到预期的结果,而应该等号之前加“collate Chinese_PRC_CI_AS”,如“t1.Name collate Chinese_PRC_CI_AS = t2.Title”;

(2)Select嵌套使用

select * from (
    select [ * | col1,col2,…] from table1 
    […joinon …]
    […joinon …]
    [where …] 
    [group by …]) as t
[…joinon …] 
[…joinon …] 
[where …] 
[group by …] 
[order by …]

(3)返回取值(只用于调试时可用print取代)

select @name            -- @name是变量

(4)从表给变量赋值

select @name = col1 from table1 where id = 1    -- @name指定值

(5)给变量赋值(作用类似于set命令)

select @name = 'AAA'    -– 类似于set @name='AAA'

(6)复制表结构及数据

select * into b from table1     -- b是物理表,复制表结构与数据
select * into #b from table1    -- #b是内存表,复制表结构与数据
select * into #b from table1 where 1 <> 1 -- 只复制表结构

UPDATE
(1) 根据条件更新

update table1 set col1 = value1,col2 = value2,…  [where …] 

(2) 根据基它表条件更新

update table1 set col1 = t2.col1,col2 = t2.col2 from table2 as t2 [...joinon…] where t2.Id = t.Fid and

(3) 根据其它表条件更新

update table1 set col1 = t2.col1,col2 = t2.col2 from table1 as t left join table2 as t2 on t2.Id = t.Fid [where …]

DELETE(用法同UPDATE)
(1) 根据条件删除

delete [from] table1 [where…]

(2) 根据其它表条件删除

delete [from] table1 from table2 as t2 […joinon…] where t2.Id = t.Fid [and ...] 

delete [from] table1 from table1 as t 
left join table2 as t2 on t2.Id = t.Fid where


注:养成良好习惯,在对数据进行批量Update、Delete时谨慎操作,一定先把要更新的数据用select查询出现,在检查无误后,再写update/delete语句,然后从select查询语句中把查询条件(where)直接Copy过来使用!

2、常用查询条件

  • 普通运算符:=(等于),<>(不等于或用!=),>(大于),<(小于),>=(大于等于),<=(小于等于),between(介于A与B之间)
  • 包含运算:IN
select Id,Name,Info from table1 where Id IN (1,2,3)
select Id,Name,Info from table1 where Id IN (select Id from table2 ) 

【注】在IN之后使用的select子句时,一定要注意排除NULL值,否则会得到意外的结果!【见示例《SQL基本操作》】

  • 模糊运算:LIKE
  • 否运算:NOT
  • 条件组合关系:AND(且),OR(或)
  • 空判断:IS NULL | IS NOT NULL
  • 存在判断:Exists | NOT Exists

3、常用函数

判断是否空:ISNULL
日期计算:DATEDIFF,DATEADD,取日期部分Year()、Month()、Day()
字符串处理:STUFF,replace,LTRIM,RTRIM
数据类型转换:Cast,Convert

二、数据集运算

UNION 运算符

UNION 运算符通过组合其他两个结果表(例如 TABLE1 和 TABLE2)并消去表中任何重复行而派生出一个结果表。当 ALL 随 UNION 一起使用时(即 UNION ALL),不消除重复行。两种情况下,派生表的每一行不是来自 TABLE1 就是来自 TABLE2。

EXCEPT 运算符

EXCEPT 运算符通过包括所有在 TABLE1 中但不在 TABLE2 中的行并消除所有重复行而派生出一个结果表。当 ALL 随 EXCEPT 一起使用时 (EXCEPT ALL),不消除重复行。

INTERSECT 运算符

INTERSECT 运算符通过只包括 TABLE1 和 TABLE2 中都有的行并消除所有重复行而派生出一个结果表。当 ALL 随 INTERSECT 一起使用时 (INTERSECT ALL),不消除重复行。

注:使用运算词的几个查询结果行必须是一致的。

-- 从TableA取值,排除TableB、TableC中存在的记录
(select a from tableA ) except (select a from tableB) except (select a from tableC)

三、连接(Join)

1、inner Join内联接:根据条件联接,且条件中的字段在两个表都不为NULL
2、left [Outer] Join 左联接:在左表为中心,让右表(join之后指定的表)根据条件联接,当条件中引用左表字段值在右表中不存在时,自动用NULL填充。
3、right [Outer] Join 右联接:与左联接相反。
4、Full [Outer] Join 全联接:是left join与right join的全集


declare @oldTable table(Num int)
declare @newTable table(Num int)

-- ============= 1、比较union与union all的区别 =============
-- (1) union
insert into @oldTable
select '52003' union  
select '52004' union  
select '52004' union  
select '52005'
---- (2) union all
--select '52003' union all
--select '52004' union all
--select '52004' union all
--select '52005'

--select * from @oldTable

-- ============= 2、查找重复编码、多余编码 =============
insert into @oldTable
select '52003' union all 
select '52004' union all 
select '52005'

insert into @newTable
select '52004' union all 
select '52005' union all 
select '52006' union all
select '52007'

--select COUNT(*) from @oldTable
--select COUNT(*) from @newTable
--select * from @newTable where Num not in(select Num from @oldTable) 
--select * from @oldTable where Num not in(select Num from @newTable) 
--select * from(select Num,COUNT(*) count from @oldTable group by Num) t where t.count <> 1
--select * from(select Num,COUNT(*) count from @newTable group by Num) t where t.count <> 1

-- ============= 3、测试Join =============
-- (1) Inner Join
select * from @oldTable t1 inner join @newTable t2 on t2.Num = t1.Num
-- (1) Left [Outer] Join
select * from @oldTable t1 left join @newTable t2 on t2.Num = t1.Num
-- (1) Right [Outer] Join
select * from @oldTable t1 right join @newTable t2 on t2.Num = t1.Num
-- (1) Full [Outer] Join
select * from @oldTable t1 full join @newTable t2 on t2.Num = t1.Num

四、几种特性SQL

以下的几种特性常用于报表中。

1、行列转置Pivot

-- ========================= PIVOT 行列转置 ===========================
-- 1、【行列转置PIVOT】
declare @Score table(StuNo varchar(10), StuName varchar(50), CourseName varchar(50), Score int)
insert into @Score
    select '1', 'Tom', 'Math', 80 union all
    select '1', 'Tom', 'English', 82 union all
    select '1', 'Tom', 'Geography', 84 union all
    select '2', 'Jone', 'Math', 79 union all
    select '2', 'Jone', 'English', 88 union all
    select '2', 'Jone', 'Geography',86
select * from @Score

SELECT StuNo, StuName, Math, English, [Geography]
FROM @Score as t PIVOT (MAX(Score) FOR CourseName in (Math, English, [Geography])) AS ScoreList
ORDER BY StuNo

-- 用简单的替换语句实现?
select StuNo,StuName,
    MAX(CASE WHEN CourseName = 'Math' THEN Score ELSE NULL END) as [Math],
    MAX(CASE WHEN CourseName = 'English' THEN Score ELSE NULL END) as [English],
    MAX(CASE WHEN CourseName = 'Geography' THEN Score ELSE NULL END) as [English]
from @Score 
group by StuNo,StuName
-- 执行动态SQL解决行列转置时需要指定转置列的问题?
declare @expression nvarchar(200) = '@Score',
    @pvtCol nvarchar(50) = 'CourseName',
    @pvtValue nvarchar(50) = 'MAX([Score])',
    @keepCols nvarchar(200) = 'StuNo,StuName',
    @order nvarchar(50) = 'StuNo',
    @cols nvarchar(200) = '',
    @query nvarchar(4000)

if @cols = '' or @cols is null 
begin
    declare @colsql nvarchar(200) = 'set @a = STUFF((select distinct '',['' + ' 
        + @pvtCol + ' + '']'' from ' + @expression + ' for xml path('''')),1,1,'''')'
    exec sp_executesql @colsql,N'@a nvarchar(200) output',@cols output 
end

set @query = 'SELECT ' + @keepCols 
    + (case when LEN(@keepCols) > 0 then ',' else '' end)
    + @cols 
    +' FROM ' + @expression + ' as t PIVOT ('+ @pvtValue +' FOR ' + @pvtCol + ' in (' 
    + @cols + ')) AS pvt ORDER BY ' 
    + @order

exec(@query)

-- 2、【列行转置UNPIVOT】
declare @ScoreList table(StuNo varchar(10), StuName varchar(50), Math int, English int, [Geography] int)
insert into @ScoreList
    select '1', 'Tom', 80, 82, 84 union all
    select '2', 'Jone', 79, 88, 86  
select * from @ScoreList

SELECT StuNo, StuName, CourseName, Score
FROM @ScoreList UNPIVOT (Score FOR CourseName in (Math, English, [Geography]) ) AS ScorePvtTable
ORDER BY StuNo

2、递归取数CTE

-- ==================== Common Table Expression(CTE) ========================
declare @Object table(Id INT, ParentId INT, Name NVARCHAR(10)) 

INSERT INTO @Object
  SELECT 1 ,   0 , N'食品' UNION ALL 
  SELECT 2 ,   1 , N'水果' UNION ALL 
  SELECT 3 ,   1 , N'蔬菜' UNION ALL 
  SELECT 4 ,   2 , N'香蕉' UNION ALL 
  SELECT 5 ,   2 , N'苹果' UNION ALL 
  SELECT 6 ,   3 , N'青菜' UNION ALL 
  SELECT 11 ,  0 , N'计算机' UNION ALL 
  SELECT 12 , 11 , N'软件' UNION ALL 
  SELECT 13 , 11 , N'硬件' UNION ALL 
  SELECT 14 , 12 , N'Office' UNION ALL 
  SELECT 15 , 12 , N'Emeditor' UNION ALL 
  SELECT 16 , 13 , N'内存'  

select * from @Object 

-- 1、【得到所有水果】
;WITH cte AS
(  
    -- 起始条件
    SELECT Id,ParentId,Name FROM @Object as t WHERE id=2 
    UNION ALL  
    -- 递归条件
    SELECT a.Id,a.ParentId,a.Name FROM @Object a,cte b WHERE a.ParentId=b.Id
)
SELECT * FROM cte  
-- 限制递归次数(默认值100),超出时会报错!
OPTION(MAXRECURSION 100)

-- 2、【得到当前及所有父级】   
;WITH cte AS  
(   
    SELECT Id,ParentId,Name FROM @Object WHERE id=16   
    UNION ALL  
    SELECT a.Id,a.ParentId,a.Name FROM @Object a,cte b WHERE a.Id=b.ParentId   
)
SELECT * FROM cte   

-- 3、【得到所有路径】   
;WITH cte AS  
(   
    SELECT Id,ParentId,Name,[Path]=CAST(Name AS VARCHAR(MAX)) FROM @Object WHERE parentid=0   
    UNION ALL  
    SELECT a.Id,a.ParentId,a.Name,CAST(b.[Path] +'/'+a.Name AS VARCHAR(MAX)) FROM @Object a,cte b WHERE a.ParentId=b.Id   
)
SELECT * FROM cte
-- Id          ParentId    Name   Path   
-- ----------- ----------- ---------- -------------------------   
-- 1           0           食品         食品   
-- 11          0           计算机       计算机   
-- 12          11          软件         计算机/软件   
-- 13          11          硬件         计算机/硬件   
-- 16          13          内存         计算机/硬件/内存   
-- 14          12          Office       计算机/软件/Office   
-- 15          12          Emeditor     计算机/软件/Emeditor   
-- 2           1           水果         食品/水果   
-- 3           1           蔬菜         食品/蔬菜   
-- 6           3           青菜         食品/蔬菜/青菜   
-- 4           2           香蕉         食品/水果/香蕉   
-- 5           2           苹果         食品/水果/苹果   

3、汇总特性介绍

较少使用,请参考《SQL Server 2008中增强的汇总技巧》:http://blog.csdn.net/downmoon/article/details/7430645

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值