sql溫習筆記


--查詢所有數據庫

use master

select * from sysdatabases where dbid>4;--系統自帶的數據庫分別是master->1,model->3,msdb->4,tempdb->2

--查詢數據庫中所有數據庫(存儲過程)

exec sp_helpdb;

--查詢指定數據庫中的表

use master

select * from sysobjects where xtype='u' ;

if object_id('#test1'is not null

drop table #test1

go

create table #test1

(

  id int not null primary key,

  name nvarchar default('haha')

)

drop table #test1

set nocount off

select name from sysobjects where xtype='u'--讀數據庫中表名

select name from syscolumns where id=(select max(id) from sysobjects where xtype='u' and name='表名')--讀取某表的列名

--exec調用保存在變量中的批處理代碼

declare @sql as varchar(100);

set @sql='print''this is a message......;'';';

exec(@sql)

----------------------------------------

--DDL--數據定義語言

--DML--數據操作語言

--數據庫定期備份

if day(current_timestamp)=9

 begin

   print '今天是一個月的第一天,數據庫備份'

   print '開始完全備份'

   backup database dbtest to disk='E:\backup\backup_dbtest_full.bak' with init;

   print '完全備份成功'

 end

else

 begin

   print '今天是一個月的最後一天,數據庫備份'

   print '開始差異備份'

   backup database dbtest to disk='E:\backup\backup_dbtest_diff.bak' with differential;

   print '差異備份成功'

 end

------------------------------------------------------------

use tempdb;

if object_id('dbo.Orders','u'is not null drop table dbo.Orders;

create table dbo.Orders

(

orderid int not null

constraint pk_order  primary key,

orderdate datetime not null

constraint def_orderdate default(current_timestamp)

)

----------------子查詢--------------------------------------------

--子查詢分爲1-獨立子查詢2-相關子查詢

--返回結果可以是一個單獨的值(標量)或者多個值或者整個表變量

declare @maxid as int = (select max(orderid) from Sales.Orders);

select orderid,orderdate,empid,custid

from Sales.Orders

where orderid=@maxid;

--sql2005

select orderid,orderdate,empid,custid

from Sales.Orders

where orderid=(select max(orderid) from Sales.Orders);

--對於有效的標量子查詢,它的返回值不能超過一個,如果標量子查詢返回了多個值,在運行時可能會失敗。

--比如

select orderid

from Sales.Orders

where empid=(select E.empid from HR.Employees as E where E.lastname like N'B%')

select E.lastname from HR.Employees as E

--因爲恰巧該表中只有一個人的名字是以B開頭的所以,sql會認爲右邊子查詢是標量值

--假如右邊表達式沒有返回任何值,那麼兩者比較得出的結果是NULL,而與NULL比較的結果都爲UNKNOW,所以不會返回任何值

--當然上面的查詢還可以用聯結查詢

select O.orderid

from HR.Employees as E

join Sales.Orders as O

on E.empid=O.empid

where E.lastname like N'D%'

--獨立多值子查詢IN------

--<標量表達式> IN <多值子查詢>

--用某表的偶數行數據填充tempdb

use tempdb

select * 

into dbo.tempdb

from TSQLFundamentals2008.Sales.Orders

where orderid%2=0;

select * from tempdb;

--返回tempdb中介於min(orderid)max(orderid)並且不在表中的orderid

select n

from tempdb

where n between (select min(O.orderid) from tempdb as O) and (select max(E.orderid) from tempdb as E)

and n not in(select orderid from tempdb); 

-------------------------遊標使用-------------------------------------------

--遊標通常步驟

--1.在某個查詢的基礎上聲明遊標

--2.打開遊標

--3.從第一個遊標記錄中把列值提取到指定的變量

--4.當還沒有超出遊標最後一行時,(@@fetch_status函數返回值爲0),循環遍歷遊標記錄,在每一次遍歷中,從當前遊標記錄把列

--值提取到指定的變量,再爲當前執行相應的處理

--5.關閉遊標

--6.釋放遊標

use TSQLFundamentals2008

declare @result table

(

 custid int,

 ordermonth datetime,

 qty int,

 runqty int,

 primary key(custid,ordermonth)

);

declare 

  @custid as int,

  @prvcustid as int,

  @ordermonth as datetime,

  @qty as int,

  @runqty as int;

declare c cursor fast_forward for

 select custid,ordermonth,qty

 from Sales.CustOrders

 order by custid,ordermonth;

open c

fetch next from c into @custid,@ordermonth,@qty;

select @prvcustid=@custid,@runqty=0;

while @@fetch_status=0

 begin

   if @custid<>@prvcustid

     set @runqty=@runqty+@qty;

     insert into @result values(@custid,@ordermonth,@qty,@runqty);

     fetch next from c into @custid,@ordermonth,@qty

 end

close c;

deallocate c;

select custid,convert(varchar(7),ordermonth,121as ordermonth,qty,runqty

from @result

order by custid,ordermonth;

-------------------------------------------

--1)接受數據導入的表已經存在。  

     insert into t1 select * from  OPENROWSET('MICROSOFT.JET.OLEDB.4.0'  ,

    'Excel 5.0;HDR=YES;DATABASE=c:\\test.xls',sheet1$); 

--2)導入數據並生成表。 

     select * into t1 from  OPENROWSET('MICROSOFT.JET.OLEDB.4.0',

     'Excel 5.0;HDR=YES;DATABASE=c:\\test.xls',sheet1$);

--

--3) 導入Excel中指定的列到數據庫表中指定的列。

     INSERT INTO t1(a1,a2,a3) SELECT a1,a2,a3 FROM OPENROWSET 'MICROSOFT.JET.OLEDB.4.0' ,'Excel5.0; HDR=YES; DATABASE=c:\\test.xls',sheet1$);

--

--需要注意的地方。

--1)外圍應用配置器的設置。

--    功能外圍應用配置器中選擇啓動 OPENROWSET 和 OPENDATASOURCE 支持選項。

--2)關閉Excel表。

--     如果在導入時要導入的Excel表格處於打開狀態,會提示:

--   “無法初始化鏈接服務器 "(null)" 的 OLE DB 訪問接口 "microsoft.jet.oledb.4.0" 的數據源對象。

--3)導入數據時,Excel的首行會作爲表頭,若導入到已存在的數據庫表,則忽略首行。

--------------------------------------直接從數據庫將表導出到EXCEL-------------------------------------------------------------

EXEC master..xp_cmdshell 'bcp master.dbo.t2 out d:\Temp.xls -c -q -S"127.0.0.1" -U"sa" -P"123456"'

--參數:SQL服務器名;U是用戶;P是密碼

--查詢優化------------------------------------------

set nocount on;

use master;

if db_id('performance'is null

 create database performance;

go

 use performance;

go

--創建填充的數字輔助表

set nocount on;

if object_id('dbo.nums','u'is not null

  drop table nums;

create table dbo.nums(n int not null primary key);

declare @max as int,@rc as int;

set @max=1000;

set @rc=1;

insert  into dbo.nums(n) values(1);

while @rc*2<=@max

 begin

  insert into dbo.nums(n) select n+@rc from dbo.nums;

  set @rc=@rc*2;

 end

insert into dbo.nums(n) select n+@rc from dbo.nums where n+@rc<=@max;

go

--如果數據表存在,則先刪除

------------------------------------------------------------

use insideTSQL2008;

set nocount off;

select orderid,custid

from sales.orders

where orderid=(select max(orderid) from sales.orders );--取出orderid最大的訂單信息(標量子查詢)

-------相關子查詢,返回每個客戶最大的訂單信息

select orderid,custid

from sales.orders as T1

where orderid=(select max(orderid) from sales.orders as T2 where T1.custid=T2.custid)

order by custid;

---在期待多個值的地方可以使用多值子查詢,返回下過訂單的客戶

select custid,companyname

from sales.customers

where custid not in (select custid from sales.orders);

--在期待表的地方還可以使用 表值子查詢 或 表表達式

--查詢每個訂單年份返回最大的訂單ID

select * from sales.orders;

select * from sales.customers;

select order_year,max(orderid) as max_orderid 

from (select orderid,year(orderdate) as order_year from sales.orders) as T1

group by order_year;

--子查詢可以按兩種方式進行分類,按期望值的數量可以分爲標量子查詢,多值子查詢

--按子查詢對外部的依賴,分爲獨立子查詢,相關子查詢,標量子查詢和多值子查詢既可以是獨立子查詢,也可以是相關子查詢

--查詢由每個美國僱員至少爲其處理過的一個訂單的所有客戶

--假設知道美國僱員的empid12348

--(1)

select custid

from sales.orders

where empid in(1,2,3,4,8)

group by custid

having countdistinct empid)=5;

--(2)

select custid

from sales.orders

where empid in (select empid from hr.employees where country='usa')

group by custid

having count(distinct empid)=5

--返回每個月最後實際訂單日期發生的訂單

select orderid,custid,empid,orderdate

from sales.orders

where orderdate in(

select max(orderdate)

from sales.orders

group by year(orderdate),month(orderdate));

--相關子查詢,是引用了在外部查詢中出現的列的子查詢,從邏輯上講,子查詢會爲外部查詢的每一行進行一次計算。

--決勝屬性(tiebreaker,是一個屬性或屬性列表,可以惟一的對元素進行排名

--先創建2張表

use master;

if db_id('DbTest'is not null drop database DbTest;

create database DbTest;

go

use DbTest;

go

--創建Customers

create table Customers

(

  custid       INT          NOT NULL IDENTITY,

  companyname  NVARCHAR(40NOT NULL,

  country      NVARCHAR(15NOT NULL,

  constraint pk_customer primary key(custid)

);

--創建Orders

CREATE TABLE Orders

(

  orderid        INT          NOT NULL IDENTITY,

  custid         INT          NULL,

 

  CONSTRAINT PK_Orders PRIMARY KEY(orderid),

  CONSTRAINT FK_Orders_Customers FOREIGN KEY(custid)

  REFERENCES Customers(custid),

 

);

  set identity_insert Customers on;

  INSERT INTO Customers(custid, companyname,country)

  VALUES(1, N'大衆', N'中國');

  INSERT INTO Customers(custid, companyname,country)

  VALUES(2, N'寶馬', N'美國');

  INSERT INTO Customers(custid, companyname,country)

  VALUES(3, N'奔馳', N'中國');

  INSERT INTO Customers(custid, companyname,country)

  VALUES(4, N'奇瑞', N'德國');

  INSERT INTO Customers(custid, companyname,country)

  VALUES(5, N'福特', N'美國');

  

  set identity_insert Customers off;

  set identity_insert Orders on;

--custid代表員工號

  INSERT INTO Orders(orderid, custid)

  VALUES(1,1);

  INSERT INTO Orders(orderid, custid)

  VALUES(2,2);

  INSERT INTO Orders(orderid, custid)

  VALUES(3,3);

  INSERT INTO Orders(orderid, custid)

  VALUES(4,4);

  INSERT INTO Orders(orderid, custid)

  VALUES(5,5);

--查看錶的數據

select custid,companyname,country from Customers;

select orderid,custid from Orders;

--插入數據成功

--咱們回到正題,比較Existsin,not exists與 not in

--查詢來自中國,而且下過訂單的所有客戶

select custid,companyname

from Customers as C

where country=N'中國'

and exists (select * from Orders as O where O.custid=C.custid);

--返回

--custid    companyname

--1            大衆

--3            奔馳

--外部查詢返回來自中國的客戶信息,對於這個客戶,exists謂詞在Orders表查找是否至少存在一個與外部客戶行信息相同的custid訂單行

--IN查詢剛剛的需求

select custid,companyname

from Customers as C

where country=N'中國'

and custid in(select custid from Orders);

--結果跟上面的返回一樣的值

--下面的知識點我們需要認識到:

--當列表中有NULL時,in實際會產生一個UNKNOWN的結果,例如 a in(d,b,null)的結果是UNKNOWN,a not in (d,b,null)返回的是not unknowd仍然是unknowd

--not innot exists則結果會很不同,例如a in(a,b,null)返回的是TRUE,a not in(a,b,null)返回的肯定是not true即爲false

--有了上面的認識,好繼續開工了....

--我們現在向Orders表插入一行數據(6,null

set identity_insert Orders on;

insert into Orders(orderid,custid) values(6,null);

set identity_insert Orders off;

set identity_insert Customers on;

insert into Customers(custid,companyname,country) values(7,N'雷克薩斯',N'美國');

set identity_insert Customers off;

select * from Orders;

select * from Customers;

--合併字符串

select ','+companyname from Customers where country=N'中國' 

for xml path('')

--假設現在要返回來自美國且沒有訂單的客戶

select custid,companyname

from Customers as C

where country=N'美國'

and not exists (select * from Orders as O where O.custid=C.custid );

--返回

--custid    companyname

--7            雷克薩斯

--我們再用IN方法

select custid,companyname 

from Customers as C

where country=N'美國'

and custid not in(select custid from Orders); 

--返回的結果爲空!!!

--爲什麼呢??

--因爲還記得我們剛插入的一行數據中custidnull麼,這就是問題所在

--not in (select custid from Orders)返回的實際是unknown,所以返回結果集爲空,除非你顯示的規定custid不能爲空

--下面是正確的解決方法

select custid,companyname

from Customers as C

where country=N'美國'

and custid not in (select custid from Orders where custid is not null);

--返回

--custid    companyname

--7            雷克薩斯

--所以在含有NULL值的列的時候,就要小心了,not existsnot in在邏輯上是不等價的

use tempdb

go

if object_id('dbo.sales'is not null

drop table dbo.sales;

go

--無法綁定由多個部分組成的標識符 "dbo.sales"?

create table sales

(

empid  varchar(10not null  primary key,

mgrid varchar(10not null,

qty int not null

)

delete from sales;

insert into sales(empid,mgrid,qty) 

select

'B','X','300'

union

select 

'C','Z','300'

union

select 

'D','X','200'

union

select 

'E','Z','300'

union

select 

'F','Y','150'

union

select 

'G','Y','300'

union

select 

'H','Z','240'

union

select 

'I','Y','300'

union

select 

'J','Z','350'

union

select 

'K','Z','300'

select * from sales;

--row_number()函數編號

select empid,qty,mgrid,

row_number() over ( partition by mgrid order by qty) as rowrank 

from sales

order by qty;

--用基本方法計算行號(列的值不爲NULL)

select empid,(select count(*from sales s where s.empid<ss.empid)+1 as rowrank from sales ss order by empid;

--更新某列的值爲null

update sales set empid=null where empid=N'F'

--select 字段 into 表 from 

use tempdb;

if object_id('tempdb..#myshippers'is not null

drop table #myshippers;

select shipperid,companyname,phone

into #myshippers

from InsideTSQL2008.sales.shippers;

--如果需要爲某個表創建應急的空副本,使用select into 很容易就可以得到它,只需提交以下語句

select * into target_table from source_table where 1=2;

--創建名爲MyOrders的表

select * 

into MyOrders

from InsideTSQL2008.sales.orders

where 1=2;

--OUTPUT子句

--支持output子句有INSERT,DELETE,UPDATE,MERGE,可以引用特殊的inserteddeleted

--SCOPE_IDENTITY()函數可以返回當前範圍內會話最後生成的標識值

--@@IDENTITY 中包含語句生成的最後一個標識值,如果語句未影響任何包含標識列的表,則 @@IDENTITY 返回 NULL

--

use tempdb;

if object_id('CustomersDim'is not null drop table CustomersDim;

go

create table CustomersDim

(

  keycol int not null identity primary key,

  custid int not null,

  companyname nvarchar(40not null

)

--@@rowcount返回受上一語句影響的行數。 如果行數大於 20 億,請使用 ROWCOUNT_BIG

--聲明一個表變量

declare @NewCusts table

(

  custid int not null primary key,

  keycol int not null unique

)

insert into CustomersDim(Custid,companyname)

output inserted.custid,inserted.keycol

into @NewCusts--表變量

--output inserted.custid,inserted.keycol

select custid,companyname

from InsideTSQL2008.Sales.Customers

where country=N'UK';

select * from @NewCusts;

select @@identity ;

--謹慎使用,現在我們想下,假設上面表 和表 都有IDENTITY自增域,那麼我們在表 插入一條數據後,

--使用了 SELECT @@IDENTITY 輸出時,輸出的到底是 還是 的自增域的值呢?

--答案很明顯,是誰最後插入就輸出誰,那麼就是 了。

--於是,我本意是想得到 的自增域值,結果得到了 的自增域值,一隻 BUG 隨之誕生,搞不好還會影響到整個系統數據的混亂。

--因此,對於這種情況,建議大家慎用 @@IDENTITY,而儘量採用 SCOPE_IDENTITY() 函數替換之。SCOPE_IDENTITY() 也是得到最後一條自增域的值,

--但是它是僅限在一個操作範圍之內,而@@IDENTITY 是取全局操作的最後一步操作所產生的自增域的值的。

select scope_identity();

--從表中刪除大量數據,並避免日誌爆炸式增長和鎖升級

--假如要刪除2006年之前所有訂單

--那我們採取分批方法,每次刪除5000

while 1=1

 begin

   delete top(5000from LargeOrders where orderdate<'20060101';

   if(@@rowcount<5000break;--如果沒有5000行,則循環一次就跳出循環

 end;

--返回一個隨機的數

--select N'隨機'+right('000000000'+cast(1+ abs(checksum(newid())) as varchar(10)),10) as 隨機值;

--5分鐘內向某表隨機插入值

use tempdb;

if object_id('randtable'is not null drop table randtable;

go

create table randtable

(

  ID int not null identity primary key,

  msg varchar(maxnot null

)

declare @msg as varchar(max);

declare @now as datetime;

set @now=current_timestamp;

 while 1=1 and datediff(second,@now,current_timestamp)<300

   begin

     set @msg=N'隨機'+right('000000000'+cast(1+ abs(checksum(newid())) as varchar(10)),10);

     insert into randtable(msg) values (@msg);

   end

--select @@rowcount--返回影響行數

select * from randtable;

select (max(ID)-min(ID)) as N'總行數' from randtable;

select max(ID)as N'最大ID' from randtable;--

select min(ID) as N'最小ID'from randtable;--

--比較幾種刪除數據的執行效率

--我們一分鐘內隨機插入數據

delete  from randtable;--用這種直接刪除數據方式,刪除415850條數據       用時52秒:

                                              

                                               --刪除5686094條數據      用時29;

                                               --刪除7679924條數據      用時19;

                                               --刪除11248379條數據      用時2;

                                               --刪除10803495條數據      用時2;

--下面我們採取另一種方式刪除,即分批刪除

while 1=1

 begin

   delete top(5000from randtable --where ID<19061681;

   --if(@@rowcount<5000) break;--如果沒有5000行,則循環一次就跳出循環

 end;

--比較現在時間與之後之間的差值

datediff(second,@now,current_timestamp);

--更新表結構

alter table tablename 

  add constraint pk_name primary key(columnname);

--將空值轉換爲實際值

--coalesce(comm,0)

--COALESCE(expression1,...n) 的功能與以下 CASE 表達式相同:

--

--CASE

--

--   WHEN (expression1 IS NOT NULL) THEN expression1

--

--   WHEN (expression2 IS NOT NULL) THEN expression2

--

--   ...

--

--   ELSE expressionN

--

--END 類似

--利用case指定order by的列動態排序

select ename,sal,job,comm 

case when job='saleman' then comm else sal end as ordered

from emp

order by 5;

--UNION ALL(包括重複行)

--將多個來源的行組合起來,放到一個結果集,所有select列表的項目數

--和對應項目的數據類型必須要匹配

--UNION(不包括重複行)

--創建數字輔助表(Nums)

if object_id('Nums'is not null drop table Nums;

go

create table Nums(n int not null primary key);

declare

  @max as int,

  @rc as int;

 set @max=10000;

 set @rc=1;

insert into Nums values(1);

while @rc*2<=@max

  begin

     insert into Nums select n+@rc from Nums;

     set @rc=@rc*2;

  end 

insert into Nums

  select n+@rc from Nums where n+@rc<=@max;

-- 創建一個表,把Customers表與Employees表生成僱員-客戶-每天組合

select custid,empid,dateadd(day,n-1,'20090101'as orderdate ,row_number() over (order by (select 0))as orderid

from sales.customers

cross join HR.employees

cross join Nums

where n<31;

--對於每個訂單,計算訂單價格佔總價格的百分比,以及它與所有訂單平均價格的差額

drop table Myordervalues

select * into MyorderValues

from sales.Ordervalues;

alter table myordervalues

add constraint pk_myordervalues primary key (orderid);

create index idx_val on myordervalues(val);

select orderid,custid,val ,cast(val/(select sum(val) from myordervalues)*100 as numeric(5,2)) as pct,

cast(val-(select avg(val) from  myordervalues)*100 as numeric(12,2)) as diff

from myordervalues;

--內聯結(inner

--關於ONwhere,如果一個查詢既包含ON,又要包含where字句,邏輯上他們會依次應用,除了一個

--外,在Inner Joinon字句中指定邏輯表達式,還是在where字句中指定邏輯表達式,沒有任何區別,因爲

--兩個步驟沒有中間步驟會添加外部行。

--這個例外,就是當指定了group by all選項時,group by all會把where字句過濾掉的組再添加到結果集

--但不會添加ON字句過濾掉的組。

--如何規範的去放置邏輯條件呢?

--參考:把表之間匹配屬性的篩選器應該位於ON字句中,而只對一個表的屬性進行篩選的篩選器應該位於在where字句中

--例如:

select c.custid,companyname,orderid from sales.customers as c,sales.orders as o on c.custid=o.custid and country=N'USA';

--外聯接(OUTER

--外聯接用於返回兩個表中按一定條件匹配的行,以及保留表中不能被匹配的行

--可以用left,right,full,關鍵字保留表,left把座標標記爲保留表,right把右表標記爲保留表,full把兩個表都標記爲保留表

--外聯接有三個階段:笛卡爾積-ON篩選器-》添加外部行,對於保留表中未找到匹配的行,將作爲外部行添加到結果集,並用

--null作爲相應非保留表屬性的取值

--以下查詢返回客戶及其訂單ID

select c.custid,o.orderid into #tb

from sales.Customers as c 

left outer join sales.orders as o

on c.custid=o.custid;

--返回訂單是NULL的客戶行

select* from #tb where orderid is null;

--關鍵字outer是可選的,因爲使用left,right,full就隱含着這是一個外聯接,通常使用

--內聯接不加關鍵字inner,而使用外聯接通常加上關鍵字outer

--其他聯接

--自聯接(是在同一個表的兩個實例之間進行的聯接)

--以下是一個簡單的自聯接例子,對Employees表的兩個實例進行聯接,一個代表僱員(E),另一個代表經理(M)

--當聯接同一個表的兩個實例時,必須至少爲其中一個表應用別名,爲每一個實例,提供惟一的一個名稱

select E.firstname,E.lastname as emp,

M.firstname,M.lastname as mgr

from HR.Employees as E left outer join HR.Employees as M

on E.mgrid=M.empid;

--不等聯接

--等值聯接是聯接條件基於等號(=)運算符的聯接,不等聯接的聯接條件中包含的是除等號以外的其他運算符

--存儲過程

--o(∩_∩)o ,終於到存儲過程這一環節了,不容易啊....

--存儲過程是把一個或多個T-SQL語句組合到一個邏輯單元,在sqls中保存爲一個對象,當首次執行時,sqlserver創建執行計劃

--並把它存在計劃內緩存中,然後進行重用,重用計劃使得存儲過程提供了可靠的性能

--優點:

--1)提升應用程序的可支持性

--2)減少網絡流量

--3)促進代碼可複用性

--4)淡化數據的獲取方式

--5)查詢時間比較穩定

--6)有效防止SQL Injection

--7)能作爲控制層,控制一定的權限

--基本語法

--沒有參數的存儲過程

--create procedure [schema_name.] procedure_name--是架構和存儲過程的名字

--as {<sql_statement>[...n]}--主體

--創建一個查詢master數據庫的存儲過程

use master

go

create procedure select_master

as 

select * from spt_values;

go

--執行存儲過程

exec  select_master;--不需要加exec procedure proc_name

--go關鍵字用於標記存儲過程結束

--在創建存儲過程的時候,會檢查sql語法的正確性,不會去檢查引用表是否存在,這意味着你可能引用了不存在

--的表,並且直到運行的時候才報錯,這叫做延遲名稱解析

--創建帶參數的存儲過程,一個存儲過程可以傳入2100個參數

--語法如下

--create {proc|procedure} [schema_name] procedure_name[;number]

--[{@parameter[type_shacema_name.]data_type}[varying][=default][out|output][readonly]][,...n]

--[with <procedure_option>[,...n]]

--[for replaction]

--as {<sql_statement>[;][...n]|<method_specifier>}

--參數以@爲前綴後面是參數的數據類型和可選的默認值

--

create procedure shoppingitem

(@shoppingcartid nvarchar(50),

@quantity int =1,

@productid int)

as

if exists(select * from Sales.ShoppingCartItem 

where shoopingcartid=@shoppingcartid 

and productid=@productid)

begin 

  update sale.shoppingcartitem 

  set quantity=@quantity

  where shoppingcartid=@shoppingcartid and productid=@productid 

  print'updated....'

end

else

  begin

    insert sale.shoppingcartitem(shoppingcartid,productid,quantity)values (@shoppingcartid,@productid,@quantity)

    print 'inserted.....'

  end

go

--執行,傳入三個參數

exec shoppingitem '1000',2,316

--output參數

--該參數是把信息返回給存儲過程調用者,無論是另外的存儲過程或即席調用(嵌入程序中sql語句)

--例子

--創建一個返回某個組的部門列表

create procedure seldepartment

@groupname nvarchar(50),

@deptcount int putput

as

 select [name] 

 from hr.department

 where groupname=@groupname

 order by [name]

select @deptcount=@@rowcount

go

--執行

declare @deptcount int

exec deldepartment 'hr',@deptcount output

--更新存儲過程

alter procedure ....

--刪除存儲過程

drop procedure ....

--創建自動執行的存儲過程

--每當重啓sql時,自動向一張表中插入重啓的時間

use master

go

create table sqlstartlog

(

startid int identity(1,1primary key not null,

startdatetime datetime not null 

)

go

--創建一個存儲過程向表中插入值

create procedure insertstartlog

as

 insert sqlstartlog(startdatetime) values(getdate())

go

--設置自動執行的存儲過程

exec sp_procoption @ProcName='insertstartlog',@OptionName='startup',@OptionValue='true';

--重啓後,查看insertstartlog

select * from sqlstartlog;

--如果需要禁用

exec sp_procoption @ProcName='insertstartlog',@OptionName='startup',@OptionValue='false';

--在這個更總sql server啓動的例子中,存儲過程必須創建在master數據庫中

--加密

--只需要在創建存儲過程的名字後面加入with encryption

--查看存過程

alter procedure sampleencryption

with encryption

as

set nocount on--使不提示受T-SQL語句影響的行數,@@rowcount不受其影響

 select * from sqlstartlog

go

--

exec sp_helptext sampleencryption;

--使用execute as來指定過程的安全上下文

--with execute as 關鍵字允許你指定存儲過程執行所在的安全上下文,覆蓋存儲過程調用者的默認安全

--概念:權鏈

--當創建一個對象(例如存儲過程,或者視圖),並將其用來對另外一個數據庫對象進行Insert,Delete,Select,Update對象的時候

--就出現了所有權鏈,如果存儲過程對象的架構和它引用對象的架構一樣,sqlserver只會檢查存儲過程調用者是否有對存儲過程execute

--權限

--重新編譯與緩存

--存儲過程的性能優勢主要是在重用計劃

--當存儲過程的計劃自動或先是重建的時候就會發生重新編譯,當存儲過程中引用的基礎表或其他對象

--發生變化後,存儲過程就會在其執行期間自動重新編譯。計劃使用的索引發生變動或者存儲過程引用的表鍵發生了大量的更新也可能引起重新編譯

--sql server存儲過程使用的是語句級別的重新編譯,能夠減小負載。

--查詢緩存數量

select count(*'CachedPlansBefore'

from sys.dm_exec_cached_plans;

--清空緩存

dbcc freeproccache;

--注意事項

--不能在一個存儲過程中刪除另一個存儲過程,只能調用另一個存儲過程

--存儲過程常用命令

--顯示所有存儲過程的基本信息

show procedure status;

-- 顯示使用的時間

declare @BeginDate datetime

set @BeginDate=getdate();

begin 

    

end

SELECT BeginDate = @dt, EndDate = GETDATE(),

 Second = DATEDIFF(Second, @dtGETDATE());

--生成多少萬條不重複的n位數字

use tempdb

go

--創建測試表

create table testtable(id char(8) );

--創建用於自動過濾重複值的唯一索引

create unique index ui_tb on testtable(id)

with IGNORE_DUP_KEY

go

--測試數據插入的時間

declare @dt datetime

set @dt=getdate()

set nocount on;

declare @row int

set @row=100000

while @row>0

begin

  raiserror('need %d rows',10,1,@rowwith nowait

 set rowcount @row

 insert testtable select id=right(100000000+convert(bigint,abs(checksum(newid()))),8)

from syscolumns c1,syscolumns c2--syscolumns爲每個表和視圖中的每列返回一行,併爲數據庫中的存儲過程的每個參數返回一行。

set @row=@row-@@rowcount;

end

select BeginDate=@dt,EndDate=getdate(),Second=datediff(Second,@dt,getdate())

go

drop table testtable;

---------------------------------------------------

use tempdb

go

--我寫的這種只有5秒左右時間,而上面卻有40幾秒

--創建測試表

create table testtable(id int identity(1,1not null,num char(8)  );

--創建用於自動過濾重複值的唯一索引

create unique index ui_tb on testtable(num)

with IGNORE_DUP_KEY

go

--測試數據插入的時間

declare @dt datetime

set @dt=getdate()

set nocount on;

declare @row int

set @row=100000

declare @xx char(8)

while @row>0

begin

 set @xx=right(100000000+convert(bigint,abs(checksum(newid()))),8);

 --print @xx;

 insert testtable(num) values(@xx)

set @row=@row-@@rowcount;

end

select BeginDate=@dt,EndDate=getdate(),Second=datediff(Second,@dt,getdate())

select count(*from testtable;

go

drop table testtable;

select * from dbo.testtable

--這是第二次溫習not inexists not exists

use tempdb;

go

if object_id(N'test'is not null

drop table test

create table test

(

  ID int not null identity(1,1primary key,

   depno char(10)

)

insert into test(depno) values(20);

insert into test(depno) values (10);

insert into test(depno) values(40);

insert into test(depno) values (30);

insert into test(depno) values (null);

create table test2

(

  ID int not null identity(1,1primary key,

  depno char(10)

)

insert into test2(depno) values(10);

insert into test2(depno) values (100);

insert into test2(depno) values (20);

select * from test;

select * from test2;

select t.depno from test t where t.depno not in  (select t2.depno from test2 t2 )

--下面查詢查不到任何值,因爲子查詢中depno含有null值,並且是用not in判斷

select t2.depno from test2 t2 where t2.depno not in  (select t.depno from test t )

--採用exists

select t2.depno from test2 t2 where  not exists (select null from test t where t.depno=t2.depno )

ESCAPE

--如果要以文本的形式搜索,而不是被sql解釋爲通配符,可以使用escape關鍵字

where description like '%/%%' escape '/'--搜索與“%”匹配的

create   table   a   (name   varchar(10))  

  go  

  insert   into   a   select   '11%22'  

  union   all   select   '11%33'  

  union   all   select   '12%33'  

  go  

  select   *   from   a     WHERE   name   LIKE   '%/%33'   ESCAPE   '/'   --指定用'/'符號來說明跟在其後面的通配符字符爲普能字符。(第二個%是字符不是通配符來的)  

  go  

  drop   table   a

--結果爲:  

-- name                

  ----------    

-- 11%33  

-- 12%33   

--再來一個

SELECT * FROM finances WHERE description LIKE 'gs_' ESCAPE 's'

--意思就是: 比如,我們要搜索一個字符串 "g_" ,如果直接 like "g_",那麼 "_"的作用就是通配符,而不是字符,結果,我們會查到比如 "ga","gb","gc",而不是我們需要的 "g_". 用 LIKE 'gs_' ESCAPE 'S' 's'表示特殊用法標誌

--聲明變量

--sql2005不允許聲明變量後緊接着就賦值

--而在sql2008可以省略set關鍵字直接賦值

use InsideTSQL2008

go

select top 10percent * from MyorderValues;--返回10%的行

--建議

--避免使用不兼容的數據類型。例如floatintcharvarcharbinary

--varbinary是不兼容的

--避免使用不兼容的數據類型。例如floatintcharvarcharbinary

--varbinary是不兼容的。數據類型的不兼容可能使優化器無法執行一些本來可以進

--行的優化操作。例如:

SELECT name FROM employee WHERE salary >60000

--在這條語句中,salary字段是money型的,則優化器很難對其進行優化,因爲60000

--是個整型數。我們應當在編程時將整型轉化成爲貨幣型,而不要等到運行時轉化。 

--儘量避免在WHERE子句中對字段進行函數或表達式操作,這將導致引擎放棄

--使用索引而進行全表掃描。如:

SELECT * FROM T1 WHERE F1/2=100

--應改爲:

SELECT * FROM T1 WHERE F1=100*2

SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)=5378

--應改爲:

SELECT * FROM RECORD WHERE CARD_NO LIKE ‘5378%

SELECT member_number, first_name, last_name  FROM members

WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21

--應改爲:

SELECT member_number, first_name, last_name  FROM members

WHERE dateofbirth < DATEADD(yy,-21,GETDATE())

--即:任何對列的操作都將導致表掃描,它包括數據庫函數、計算表達式等等,查詢

--時要儘可能將操作移至等號右邊。

--儘量使用數字型字段,一部分開發人員和數據庫管理人員喜歡把包含數值信

--息的字段

--設計爲字符型,這會降低查詢和連接的性能,並會增加存儲開銷。這是因爲引擎在

--處理查詢和連接回逐個比較字符串中每一個字符,而對於數字型而言只需要比較一

--次就夠了。

--創建用','分隔的列表

select * from nums

declare @splitstring nvarchar(50)

set @splitstring='';

select @splitstring=@splitstring+convert(char(2),n)+','--因爲n是數值型,需要轉換,不然就是求和了

from Nums

where n<15;

select @splitstring;

--select into到臨時表

select n into #tempdb

from nums;

select * from #tempdb;

--在頻繁執行的查詢中,發生隱式轉換,將會非常影響性能例如nchar轉爲char

--複習索引

--索引是在表上創建的數據庫對象,它可以提供到數據更快的訪問,並且可以使查詢執行更快

--sql中,存儲單位最小的是頁,頁是不可再分的,換句話說,要麼整個讀取,要麼不讀

--如果表上沒有索引,那麼就是存放在堆Heap中,即使你想找的數據就是第一項,那麼sql引擎也需要進行全表掃描

--對於數據庫檢索來說,對於磁盤的IO是最消耗時間的

--測試sql IO次數

use tempdb

go

create table testio

(

id int,

c1 int,

c2 int,

c3 int,

c4 char(2)

)

insert into testio values(1,1,1,'a');

insert into testio values(2,2,2,'a');

insert into testio values(3,3,3,'a');

insert into testio values(4,4,4,'a');

insert into testio values(5,5,5,'a');

insert into testio values(6,6,6,'a');

insert into testio values(7,7,7,'a');

insert into testio values(8,8,8,'a');

insert into testio values(9,9,9,'a');

insert into testio values(10,10,10,'a');

insert into testio values(11,11,11,'a');

insert into testio values(12,12,12,'a');

insert into testio values(13,13,13,'a');

insert into testio values(14,14,14,'a');

insert into testio values(15,15,15,'a');

insert into testio values(16,16,16,'a');

insert into testio values(170,170,170,'a');

--開啓IO數量

set statistics io on;

select * from testio where c1=170;

--建立索引

create index idx_testio on testio(c1);

select * from testio where c1=170;

use HR

go

select top 10(ID) from Talent_Big;

select  * from Talent_Big where ID=480000;

--建立索引

drop index idx_talent_big on Talent_Big;

--理解聚集和聚集索引

--

--   SQL Server中,最主要的兩類索引時聚集索引和非聚集索引。可以看到,這兩個分類都是圍繞聚集這個關鍵字進行的,那麼首先理解什麼是聚集。

--

--   聚集在索引中的定義:

--

--   爲了提高某個屬性(或屬性組)的查詢速度,把這個或這些屬性(成爲聚集碼)上具有相同值的元組集合中存放在連續的物理塊成爲聚集。

--

--非聚集索引

--

--    因爲每個表只能有一個聚集索引,如果我們對一個表的查詢不僅僅限於聚集索引上的字段。我們又對聚集索引列之外還有索引的要求,那麼就需要非聚集索引了。

--

--    非聚集索引,本質上來說也是聚集索引的一種,非聚集索引並不改變其所在表的物理結構,而是額外生成一個聚集索引的B樹結構,但葉節點是對於其所在表的引用,

--這個引用分爲兩種,如果其所在表上沒有聚集索引,則引用行號;如果其所在表上已經有了聚集索引,則引用聚集索引的頁,從而實現更大限度的使用。

--隨着數據量的增長,產生了索引碎片,很多存儲的數據進行了不適當的跨頁,會造成碎片

--這時我們可以通過重建索引來提高速度:

ALTER INDEX idx_text_tb2_EmployeeID ON test_tb2 REBUILD

--

--還有一種情況是,當隨着表數據量的增大,有時候需要更新表上的統計信息,讓查詢分析器根據這些信息選擇路徑,使用:

--

--UPDATE STATISTICS 表名

--

--那麼什麼時候知道需要更新這些統計信息呢,就是當執行計劃中估計行數和實際表的行數有出入時:

--  當然索引的使用也是要付出代價的:

--

--  1、通過聚集索引的原理我們知道,當表建立索引後,就可以B樹來存儲數據,所以當對其進行更新插入刪除,就需要頁在物理上移動以調整B樹,因此當更新插入刪除數據時,會帶來性能的下降。

--而對於非聚集索引,當更新表後,非聚集索引需要進行更新,相當於多更新了N(N=非聚集索引數量)個表。因此也下降了性能。

--

--  2、通過上面對非聚集索引原理的介紹,可以看到,非聚集索引需要額外的磁盤空間。

--

--  3、前文提過,不恰當的非聚集索引反而會減低性能。

--

-- 所以使用索引需要根據實際情況進行權衡.通常我都會將非聚集索引全部放到另外一個獨立硬盤上,這樣可以分散IO,從而使查詢並行.

--視圖

--sql中分爲3種視圖

--普通視圖,在數據庫中不保存實際數據,只是視圖定義

--索引視圖,保存了真實的索引數據

--分佈式分區視圖,可以用UNION ALL來把多個跨兩個以上sql實例的較小的表組合成一個虛擬表

--select語句允許一個視圖定義1024個列,然而,不可以在視圖定義中使用某些select元素,包括intooption,compute,compute by 或者對

--表變量或臨時表的引用。除非使用了top關鍵字,否則也不可以使用order by

--創建視圖

create view view_somedefin

as

select * from testio

go

--查看某個視圖的定義

select definition from sys.sql_modules

where object_id=object_id('view_somedefin');

--刪除視圖

drop view view_somedefin;

--視圖加密

create view view_somedefinencrypt

with encryption

as 

select * from testio;

go

--此時通過sys.sql_modules系統目錄視圖來查看該視圖的definitionnull     

--使用視圖修改數據

--可以像普通表一樣對視圖進行插入,更新,刪除,但是這些操作只能引用一個表中的列,而且,這些操作中引用列不能進行

--衍生,例如它們不能基於聚合函數被計算或受group by ,distinct having子句

--例子

create view view_production

as

select ID,proname,proprice,num,num*prpprice totalcost

from production

go

--以上創建了一個視圖,現在向其中插入一條數據

insert view_production (proname,proprice,num,totalcost) values ('可樂',2,10,20);

--發生錯誤

--對視圖或函數’view_production‘的更新或插入失敗、因其包含派生域或常量域

--其實問題是出生在’totalcost‘中,它引用了兩列,只要去掉插入該列的值即可

--創建索引視圖

use InsideTSQL2008

go

create view view_Employees

with schemabinding

as

select E.empid ,E.lastname,E.firstname,E.title,E.address,E.city,O.orderdate,O.shipname

from HR.Employees E

join

Sales.Orders O

on O.empid=E.empid ;

go

--drop view view_Employees;

set statistics io on;

select  * from view_Employees

--查詢完畢後,我們發現empid這列是無序的,並且Orders表的邏輯讀取次數爲21次,Employees的邏輯讀取次數2

--因爲empid爲主鍵與外鍵,所以已經有了聚集索引,而一個表中只能有一個聚集索引,所以爲視圖創建非聚集索引

create  nonclustered index uci_index_Employees_Orders

on Sales.Orders(orderdate)

go

--刪除索引

drop index Sales.Orders.uci_index_Employees_Orders;

發佈了18 篇原創文章 · 獲贊 0 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章