1. 程式人生 > >ASP.Net MVC_WPF_WCF_WinForm_SQL

ASP.Net MVC_WPF_WCF_WinForm_SQL

查詢以AdventureWorks2008 資料庫為例子:

一、子查詢

1、單值Select語句巢狀查詢(巢狀在裡面的查詢只返回一個值,如:首次銷售時間)

--第一天出售的所有產品ProductID
select distinct soh.OrderDate,sod.ProductID from Sales.SalesOrderHeader soh
join Sales.SalesOrderDetail sod
on soh.SalesOrderID=sod.SalesOrderID
where soh.OrderDate=(select MIN(OrderDate) from Sales.SalesOrderHeader)--獲首次銷售時間

2、多值Select語句巢狀查詢

--應聘公司另一職位的所有僱員列表
select e.BusinessEntityID,pp.FirstName,pp.LastName from HumanResources.Employee e
join Person.Person pp
on e.BusinessEntityID=pp.BusinessEntityID
where e.BusinessEntityID in
(select distinct BusinessEntityID from HumanResources.JobCandidate) --獲得求職者的ID


注意:也可以使用連表查詢實現



3、使用巢狀找到孤立資料 not in

--沒有應聘公司其他職位的僱員
select e.BusinessEntityID,pp.FirstName,pp.LastName from HumanResources.Employee e
join Person.Person pp
on e.BusinessEntityID=pp.BusinessEntityID
where e.BusinessEntityID not in
(select distinct BusinessEntityID from HumanResources.JobCandidate --獲得求職者的ID
	where BusinessEntityID is not null)




4、ANY、SOME和ALL運算子


二、相關子查詢

1、相關子查詢的工作方式
      (1)外部查詢獲得一條記錄並將其傳入內部查詢;
      (2)基於傳入的值執行內部查詢;
      (3)內部查詢將自己返回的結果值傳給外部查詢,外部查詢利用這些值完成自己的處理。
2、Where子句中的相關子查詢

--顧客第1次下訂單的訂單ID,訂單時間
select o1.CustomerID,o1.SalesOrderID,o1.OrderDate 
from Sales.SalesOrderHeader o1
where o1.OrderDate=(select MIN(o2.OrderDate) 
                    from Sales.SalesOrderHeader o2
                    where o2.CustomerID=o1.CustomerID)
order by o1.CustomerID


3、Select 列表中的相關子查詢
--查詢客戶的名字以及首次訂購日期
select pp.FirstName,pp.LastName,
(select MIN(OrderDate) from Sales.SalesOrderHeader o 
                       where o.CustomerID=c.CustomerID) as "order date"
from Person.Person pp
join Sales.Customer c
on pp.BusinessEntityID=c.PersonID



四、派生表

--查詢購買迷你香水和棒球帽的客戶
select distinct pp.FirstName,pp.LastName from Person.Person pp
join
(select sc.PersonID from Sales.Customer sc
join Sales.SalesOrderHeader soh on sc.CustomerID=soh.CustomerID
join Sales.SalesOrderDetail sod on soh.SalesOrderID=sod.SalesOrderID
join Production.Product p on sod.ProductID=p.ProductID
where p.Name='Minipump') pumps  --括號內的查詢派生表
on pp.BusinessEntityID=pumps.PersonID


join
(select sc.PersonID from Sales.Customer sc
join Sales.SalesOrderHeader soh on sc.CustomerID=soh.CustomerID
join Sales.SalesOrderDetail sod on soh.SalesOrderID=sod.SalesOrderID
join Production.Product p on sod.ProductID=p.ProductID
where p.Name='AWC Logo Cap') caps
on pp.BusinessEntityID=caps.PersonID

要記住,派生表並不能解決所有的問題。

例如:當結果相當龐大而且有大量的記錄要聯結時,可以考慮使用臨時表,並在其上構建索引(派生表沒有索引)

五、Exists 運算子

--應聘公司另一職位的僱員列表
select e.BusinessEntityID,pp.FirstName,pp.LastName from HumanResources.Employee e
join Person.Person pp
on e.BusinessEntityID=pp.BusinessEntityID
where exists   --存在JobCandidate表中的員工
(select BusinessEntityID 
from HumanResources.JobCandidate jc 
where e.BusinessEntityID=jc.BusinessEntityID)


--資料庫是否存在
use master
go
if not exists(select 'True' from sys.databases where name='DBCreateTest')
begin
	create database DBCreateTest
end 
else 
begin
	print 'DBCreateTest資料庫已經存在'
end 
go



六、Except 除外 、Intersect 交叉


set nocount on;
create table UnionTest1
(
idco1 int identity,
col2 char(3)
);
create table UnionTest2
(
idco1 int identity,
col4 char(3)
);

insert into UnionTest1
values
('AAA'),
('BBB'),
('CCC');

insert into UnionTest2
values
('CCC'),
('DDD'),
('EEE');


-- except:返回'AAA' 'BBB' 不包含'CCC'
select col2 from UnionTest1
except
select col4 from UnionTest2;

--通過not exists實現except效果
select col2 from UnionTest1 ut1
where not exists
(select col4 from UnionTest2 where col4=ut1.col2);



--intersect:返回'ccc' 為兩個結果集交叉的
select col2 from UnionTest1
intersect
select col4 from UnionTest2;

--通過exists實現intersect效果
select col2 from UnionTest1 ut1
where exists
(select col4 from UnionTest2 where col4=ut1.col2);



drop table UnionTest1;
drop table UnionTest2;
set nocount off;

注意:Except成本是 not exists 成本的兩倍

七、通用表表達式(Common Table Expression,CTE)

通過With提供一種方法按姓名引用臨時結果集,並當做表來使用

with pumps2(BusinessEntityID)
as 
(select sc.PersonID from Sales.Customer sc
join Sales.SalesOrderHeader soh on sc.CustomerID=soh.CustomerID
join Sales.SalesOrderDetail sod on soh.SalesOrderID=sod.SalesOrderID
join Production.Product p on sod.ProductID=p.ProductID
where p.Name='Minipump')

select distinct pp.FirstName,pp.LastName from Person.Person as pp
join pumps2
on pp.BusinessEntityID=pumps2.BusinessEntityID;

--CTE中不能使用某些結構,其中包括
--Computer和ComputeBy
--Order By
--Into
--For Xml、For Browse和Option查詢子句


--注意:使用遞迴查詢時離不開CTE

八、遞迴查詢

1、hierarchyid資料型別學習

hierarchyid 層次關係,必須用/開始和結束


與hierarchyid有關的一些函式主要有
GetAncestor :取得某一個級別的祖先
GetDescendant :取得某一個級別的子代
GetLevel :取得級別
GetRoot :取得根
IsDescendantOf :判斷某個節點是否為某個節點的子代
Parse :將字串轉換為hierarchyid。該字串的格式通常都是/1/這樣的
Read :
Read 從傳入的 BinaryReader 讀取 SqlHierarchyId 的二進位制表示形式,並將 SqlHierarchyId 物件設定為該值。不能使用 Transact-SQL 呼叫 Read。請改為使用 CAST 或 CONVERT。


GetReparentedValue :可以用來移動節點(或者子樹)
ToString :將hierarchyid轉換為字串,與parse正好相反
Write
Write 將 SqlHierarchyId 的二進位制表示形式寫出到傳入的 BinaryWriter 中。無法通過使用 Transact-SQL 來呼叫 Write。請改為使用 CAST 或 CONVERT。

2、基礎資料準備

Employee 表結構:

生成後的Employee

create table HumanResources.Employee2
(
	BusinessEntityID int not null primary key,
	ManagerID int null,
	JobTitle nvarchar(50) null
);

insert into HumanResources.Employee2
select hre.BusinessEntityID,
(select BusinessEntityID 
from HumanResources.Employee hre2
where hre.OrganizationNode.GetAncestor(1)=hre2.OrganizationNode
),
JobTitle 
from HumanResources.Employee hre;

select * from HumanResources.Employee2

3、建立CTE,遞推查詢

--我們可以使用一個遞迴查詢來沿著這條鏈前進。

--with 為遞迴建立CTE
with Reports(ManagerID,BusinessEntityID,JobTitle,DepartmentID,level)
as 
(
	--查詢根節點(執行長)
	select 
	hre.ManagerID,
	hre.BusinessEntityID,
	hre.JobTitle,
	hredh.DepartmentID,
	0 as level
	from HumanResources.Employee2 hre
	join HumanResources.EmployeeDepartmentHistory as hredh
	on hre.BusinessEntityID=hredh.BusinessEntityID
	and hredh.EndDate is null
	where hre.ManagerID is null

union all
    --向根節點彙報的那些員工,隨後沿著樹向下遞推,直至到達底部為止。
	select 
	hre.ManagerID,
	hre.BusinessEntityID,
	hre.JobTitle,
	hredh.DepartmentID,
	r.level+1 as level
	from HumanResources.Employee2 hre
	join HumanResources.EmployeeDepartmentHistory as hredh
	on hre.BusinessEntityID=hredh.BusinessEntityID
	and hredh.EndDate is null
	join Reports as r
	on hre.ManagerID=r.BusinessEntityID
)
select ManagerID,BusinessEntityID,JobTitle,level
from Reports r
join HumanResources.Department as dp
on r.DepartmentID=dp.DepartmentID
where dp.GroupName like '%Admin%'
order by level,ManagerID,JobTitle
go

結果如下:


九、Merge 合併

     有了Merge,我們可以在一個整體操作中併入多條DML操作語句(Insert,update和delete),改進效能(他們可以共享許多相同的物理操作)並簡化事務。Merge使用有點類似CTE的特殊Using子句。

例項:月銷售額累計

--建立月累計表(某個產品月總銷售額)
create table Sales.MonthlyRollup
(
	Year smallint Not null,
	Month tinyint not null,
	
	ProductID int not null
	--外來鍵 引用
	Foreign key
		references Production.product(productID),
				
	QtySold int not null,
	
	--約束 主鍵
	Constraint PKYearMonthProductID
	Primary Key
	(Year,Month,ProductID)
);

--Merge 合併
merge Sales.MonthlyRollup as smr
using
(
select soh.OrderDate,sod.ProductID,SUM(sod.OrderQty) as QtySold from Sales.SalesOrderHeader soh
join Sales.SalesOrderDetail sod
on soh.SalesOrderID=sod.SalesOrderID
where soh.OrderDate>='2003-08-01'
and soh.OrderDate<'2003-08-02'
group by soh.OrderDate,sod.ProductID
)as s
on s.ProductID=smr.ProductID
when matched then  --匹配到,只累加金額
	update set smr.QtySold=smr.QtySold+s.QtySold
when not matched then--沒匹配到,插入新記錄
	insert (Year,Month,ProductID,QtySold)
	values(datepart(yy,s.orderdate),datepart(m,s.orderdate),s.ProductID,s.QtySold)
;


select * from Sales.MonthlyRollup

十、利用外部呼叫完成複雜操作

十一、效能考慮

使用聯結、子查詢或其他方法

1、預查詢(傳引數,儲存過程)

2、在聯表前,先對記錄進行一次篩選

3、慎用派生表,執行後,會駐紮記憶體中