主鍵有兩種選用策略:業務主鍵和邏輯主鍵.
業務主鍵是使用有業務意義的字段做主鍵,比如身份證號,銀行賬號.
邏輯主鍵是使用沒有任何業務意義的字段做主鍵.因爲很難保證業務主鍵不會重複,推薦用邏輯主鍵
(2)表間關聯,外鍵(ForeignKey)
(3)SQLSever的管理
bit位,相當於bool類型,0,1
char(10) 字符 長度10 不足用空格填充
int整型
bigint 超大整型
nvarchar(MAX) 最大,無限大,可能有中文信息,日文
varchar() 無中文信息 不會用空格填充 var(variable)
datatime 日期
--註釋內容
關鍵字,表名,變量名對大小寫是不敏感的
CREATE TABLE TABLE_NAME(ID int NOT NULL,NAME nvarchar(50),AGE int NULL)
INSERT INTO TableName(Column1, Column2, ..., ColumnN) VALUES(Column1Value, Column2Value, ..., ColumnNValue)
DELETE FROM TableName WHERE whereCondition
UPDATE TableName SET Column1 = Column1Value, Column2=Column2Value, ..., ColumnN=ColumnNValue WHERE whereCondition
SELECT * FROM TableName (WHERE whereCondition)
常用主鍵類型,int,bigint,uniqueidentifier(又稱GUID,UUID)
guid算法使用mac地址,地址,納秒級時間,芯片id碼等算出來,每次guid永遠不會重複
.net中生成guid的方法,Guid.NewGuid(),返回Guid類型 SQL中newid(),比如select newid()
(*)int自增字段的優點:佔用空間小,無需開發人員干預,易讀;缺點: 效率低,數據導入導出的時候很痛苦
(*)Guid的優點:效率高,數據導入導出方便; 缺點:佔用空間太大,不容易讀懂(慢慢成爲主流)
可以給字段設置默認值,如果guid類型主鍵的默認設爲newid(),就會自動生成,很少這麼幹
中文前面加N
insert into Person2(Id,Name,Age)values(newid(),'tom',30)
update Person1 set NickName=N'青年人' where Age>=20
<>不等於
(5)表刪除
刪除表中全部數據
DELETE FROM TABLE_NAME WHERE
select COUNT(*) FROM Person1
select MAX(Age) FROM Person1
select MIN(Age) FROM Person1
select avg(Age) FROM Person1
select sum(Age) FROM Person1
select COUNT(*) FROM Person1 Where
select * from Person1 order by Age (ASC升序 DESC降序) ascend descend
select * from Person1 order by Age DESC,Number ASC;按照age降序,number升序
order by 要放在where句子後面
單字符通配符“_”,它匹配單個出現的字符, LIKE '_erry' 任意第一個字符
多字符通配符“%”,它匹配任意長度字符,0到多個 LIKE '%n%' 包含n的所有字符
(4)sql中的null的理解
select * from Person1
where Name is null 或者 where Name is not null
(5)多值匹配
select * from Person1
where Age=13 or Age=15 or Age=30
使用where Age in(13,15,30) 簡單
where Age>13 and Age <15 清晰
(where Age between 13 and 15) 比較少用
(6)數據分組
Group by 放在 where 後面
select Age as 年齡,count(*) as 人數 from Person1
group by Age
根據年齡進行分組,
聚合函數不應出現在where中
having出現在group by之後
select Age as 年齡,count(*) as 人數 from Person1
group by Age
Having count(*) > 1
order by 人數 ASC
注意先後順序
Having是對分組後信息的過濾,能用的列和select中能用的列是一樣
(8)Top 限制結果集的行數
select top 3 * from ... 前三行
select top 3 * from Person1
where Number Not In (select top 5 Number from Person1 order by Age DESC)
order by Age DESC
顯示第6條以下的前3條行
SQL2005後增加了Row_Number函數簡化實現,後面會講
(9) Distincct 去掉重複數據
select DISTINCT Age as 年齡 from Person1
select Age,NickName from Person1
select DISTINCT Age,NickName from Person1
DISTINCT針對整行重複,不是一個字段的重複,這裏的指的是你檢索出來的行,如果Age,NickName兩個字段,就是這樣的兩個字段的行,其實實際也很符合,如果nickname不一樣,不顯示就失去數據了
select '正式工最高年齡',MAX(Age) FROM Person1
union all
select '正式工最低年齡',MAX(Age) FROM Person1
union all
select '臨時工最高年齡',MAX(Age) FROM Person2
union all
select '臨時工最高年齡',MAX(Age) FROM Person2
案例2
查詢正式工的信息,包括工號,工資,最後一行加上所有員工的工資合計
select FNumber,FSalary FROM T_Employee
union all
select '工資合計',sum(Fsalary)
ABS():求絕對值
CEILING():舍入到最大整數 3.33->4, -3.6->-4
FlOOR() :舍入到最小整數
ROUND(): 四捨五入 有兩個參數 ROUND(半徑,小數精度)
(12)字符串函數
LEN() : 求字符串長度 LEN('abc') : 3 ??字符串右側的空格SQL中似乎不識別,比如len('abd ')=3
LTRIM():字符串左側的空格去掉
RLTRIM() :字符串右側的空格去掉
SUBSTRING() : 取子字符串, 三個參數, SUBSTRING(主字符串,起始,長度),從1開始計數,substring('123',1,1)結果是'1'
(13)日期函數
GETDATE() : 取得當前時間
DATEADD(datepart,number,date) : 計算增加以後的日期number是日期增量
quarter qq,q 季度
month mm,m 月份
dayofyear dy,y 當年度的第幾天
day dd,d 日
week wk,ww 當年度的第幾周
weekday dw,w 星期幾
hour hh 小時
minute mi,n 分
second ss,s 秒
millisecond ms 毫秒
select getdate() as 今天
,DateAdd(day,-1,getdate()) as 前天
,DateAdd(hh,-1,getdate()) as 前一個小時
,DateAdd(mm,-1,getdate()) as 前一個月
例1:select DateDiff(hh,getdate(),DateAdd(hh,1,getdate())) 結果爲1
例2:select DateDiff(year,FinDate,getdate()),count(*) as 入職年數 from T_Employee
group by DateDiff(year,FinDate,getdate())
按照入職的年數進行分組
DatePart(datepart,date) : 返回一個日期的特定部分
例1:select DatePart(year,getdate()),DatePart(month,getdate())
例2:select DatePart(year,FInDate),count(*) from T_Employee
group by DatePart(year,FInDate)
CAST(expression AS data_type)
CONVERT(data_type,expression)
select cast('123' as int )+1,cast('2008-09-09' as datetime),
convert(int,'333'),convert(datetime,'2008-09-09')
select DatePart(year, cast('2008-09-09' as datetime)) : 確保類型正確
ISNULL(expression,value): 如果 expression不爲空,返回expression,否則返回value
例子:select ISNULL(Name,'佚名') from Person1
Case i
when value1 then returnvalue1
when value2 then returnvalue2
...
例子1:
select FName,
(
Case FLevel
when 1 then '普通客戶 '
when 2 then '會員 '
when 3 then 'VIP'
else ' 未知類型'
end
) as 客戶類型
from T_Customer
例子2:
select FName,
(
case
when Fsalary< 2000 then '低收入'
when Fsalary>= 2000 and Fsalary <5000 then '中等收入 '
when Fsalary>= 5000 then '高收入'
end
) as 收入水平
from T_Customer
五.課後練習(*)
select 單號 ,
(
case
when 金額 >0 then 金額
else 0
end
) as 收入,
(
case
when 金額 <0 then ABS( 金額)
else 0
end
) as 支出
from T_1
練習二
2008/8/8 拜仁 勝
2008/8/9 奇才 勝
2008/8/9 湖人 勝
2008/8/10 拜仁 負
2008/8/8 拜仁 負
2008/8/12 奇才 勝
顯示成
拜仁 1 2
湖人 1 0
奇才 2 0
下面是SQL語句:
CREATE TABLE [T_Scores](
[Date] [datetime] NULL,
[Name] [nvarchar] (50) NULL,
[Score] [nvarchar] (50) NULL
);
INSERT [T_Scores] ( [Date],[Name] ,[Score]) VALUES(CAST ('2008-08-08' as datetime),N '拜仁' ,N' 勝')
INSERT [T_Scores] ( [Date],[Name] ,[Score]) VALUES(CAST ('2008-08-09' as datetime),N '奇才' ,N' 勝')
INSERT [T_Scores] ( [Date],[Name] ,[Score]) VALUES(CAST ('2008-08-09' as datetime),N '湖人' ,N' 勝')
INSERT [T_Scores] ( [Date],[Name] ,[Score]) VALUES(CAST ('2008-08-10' as datetime),N '拜仁' ,N' 負')
INSERT [T_Scores] ( [Date],[Name] ,[Score]) VALUES(CAST ('2008-08-08' as datetime),N '拜仁' ,N' 負')
INSERT [T_Scores] ( [Date],[Name] ,[Score]) VALUES(CAST ('2008-08-12' as datetime),N '奇才' ,N' 勝')
SELECT Name ,
SUM(
CASE Score
WHEN ' 勝' THEN 1
ELSE 0
END
) AS 勝,
SUM(
CASE Score
WHEN ' 負' THEN 1
ELSE 0
END
) AS 負
FROM T_Scores
GROUP BY Name
練習3
創建一張表,記錄電話呼叫員的工作流水,記錄呼叫員的編號,對方號碼,通話開始時間,通話結束時間.
建表,插數據都自己寫SQL語句
要求:輸出所有數據中通話時間最長的5條記錄.
輸出所有數據中撥打長途號碼(對方號碼以0開頭)的總時長
輸出本月通話總時長最多的前三個呼叫員的編號
輸出本月撥打號碼次數最多的前三個呼叫員的編號
輸出所有數據的撥號流水,並且在最後的一行添加總呼叫次數
-記錄呼叫員編號,對方號碼,通話時長
-...
-彙總[市內號碼總時長][長途號碼總時長]
SQL的代碼:
CREATE TABLE [T_PhoneWork] (
[id] int identity (1, 1) primary key ,
[WorkNum] [nvarchar] (50) NOT NULL,
[PhoneNum] [nvarchar] (20) NULL,
[StartTime] [datetime] NULL,
[EndTime] [dateTime] NULL
);
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100001' ,'13888888888', CAST('2013-1-1 7:10:10' AS datetime),CAST ('2013-1-1 7:20:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100002' ,'13887888788', CAST('2013-1-1 8:10:10' AS datetime),CAST ('2013-1-1 8:30:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100003' ,'13888688868', CAST('2013-1-1 7:20:10' AS datetime),CAST ('2013-1-1 8:20:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100004' ,'13838883888', CAST('2013-1-1 8:10:10' AS datetime),CAST ('2013-1-1 10:20:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100001' ,'13844888888', CAST('2013-1-1 10:10:10' AS datetime),CAST ('2013-1-1 12:20:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100002' ,'013888885888', CAST('2013-1-1 13:16:10' AS datetime),CAST ('2013-1-1 14:20:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100003' ,'13888588888', CAST('2013-1-1 14:10:10' AS datetime),CAST ('2013-1-1 16:20:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100001' ,'013868886888', CAST('2013-1-1 12:10:10' AS datetime),CAST ('2013-1-1 17:20:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100004' ,'13788878877', CAST('2013-1-1 14:10:10' AS datetime),CAST ('2013-1-1 16:20:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100001' ,'13787878877', CAST('2013-1-1 16:10:10' AS datetime),CAST ('2013-1-1 18:20:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100002' ,'13787878877', CAST('2013-1-1 12:10:10' AS datetime),CAST ('2013-1-1 14:20:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100003' ,'13788078877', CAST('2013-1-1 16:10:10' AS datetime),CAST ('2013-1-1 17:20:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('100005' ,'13799078877', CAST('2013-5-1 12:10:10' AS datetime),CAST ('2013-5-2 22:20:10' AS datetime))
CREATE TABLE [T_PhoneWork] (
[id] int identity (1, 1) primary key ,
[WorkNum] [nvarchar] (50) NOT NULL,
[PhoneNum] [nvarchar] (20) NULL,
[StartTime] [datetime] NULL,
[EndTime] [dateTime] NULL
);
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('001' ,'020888888', CAST('2010-7-10 10:00:00' AS datetime),CAST ('2010-7-10 10:05:03' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('001' ,'020888888', CAST('2010-7-11 13:00:00' AS datetime),CAST ('2010-7-11 13:01:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('001' ,'8934343434', CAST('2010-7-11 14:06:00' AS datetime),CAST ('2010-7-11 14:09:00' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('002' ,'9837434777', CAST('2010-7-13 21:06:00' AS datetime),CAST ('2010-7-13 21:08:08' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('002' ,'0213434343', CAST('2010-6-29 20:11:00' AS datetime),CAST ('2010-6-29 20:16:06' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('001' ,'787878778', CAST('2010-7-15 13:16:00' AS datetime),CAST ('2010-7-15 13:26:00' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('003' ,'0334343444', CAST('2010-7-13 11:16:00' AS datetime),CAST ('2010-7-13 11:17:09' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('003' ,'676777333', CAST('2010-7-19 19:26:02' AS datetime),CAST ('2010-7-19 19:30:33' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('001' ,'89923434333', CAST('2010-6-19 15:16:02' AS datetime),CAST ('2010-6-19 15:26:10' AS datetime))
INSERT INTO [T_PhoneWork]([WorkNum], [PhoneNum],[StartTime] ,[EndTime]) VALUES('004' ,'400400400', CAST('2010-6-19 15:16:02' AS datetime),CAST ('2010-6-19 15:26:10' AS datetime))
1.輸出所有數據中通話時間最長的5條記錄.
SELECT TOP 5 *FROM T_PhoneWork
ORDER BY (DateDiff (s, StartTime,EndTime )) DESC
2.輸出所有數據中撥打長途號碼(對方號碼以0開頭)的總時長
SELECT SUM (
DateDiff(s ,StartTime, EndTime)
) AS 長途總時長
FROM T_PhoneWork
WHERE PhoneNum LIKE '0%'
3.輸出本月通話總時長最多的前三個呼叫員的編號
SELECT TOP 3 WorkNum,count (*) FROM T_PhoneWork
WHERE DateDiff (month, StartTime,getdate ()) = 0
group by WorkNum
order by sum( datediff(s ,StartTime, EndTime)) DESC
SELECT TOP 3 WorkNum FROM T_PhoneWork
WHERE DateDiff (month, StartTime,'2010-7-2 9:12:00' ) = 0
group by WorkNum
order by sum( datediff(s ,StartTime, EndTime)) DESC
select top 3 WorkNum from T_PhoneWork
WHERE DateDiff (month, StartTime,getdate ()) = 0
group by WorkNum
order by count(*) DESC
5.注意,union的兩個原則,類型要相容,這個容易犯錯,謹記
輸出所有數據的撥號流水,並且在最後的一行添加總呼叫次數
-記錄呼叫員編號,對方號碼,通話時長
-...
-彙總[市內號碼總時長][長途號碼總時長]
select WorkNum as 呼叫員編號,PhoneNum as 對方號碼 ,DateDiff( s,StartTime ,EndTime) as 通話時長
from T_PhoneWork
union all
select ' 彙總',
cast(
sum(
CASE substring (PhoneNum, 1,1 )
when '0' then 0
else DateDiff (s, StartTime,EndTime )
end
) as nvarchar( 50)),
cast(
sum(
CASE substring (PhoneNum, 1,1 )
when '0' then DateDiff(s ,StartTime, EndTime)
else 0
end
) as nvarchar( 50))
from T_PhoneWork
老師做的
select WorkNum as 呼叫員編號,PhoneNum as 對方號碼 ,DateDiff( s,StartTime ,EndTime) as 通話時長
from T_PhoneWork
union all
select ' 彙總',
cast(
sum(
CASE
when PhoneNum not like '0%' then DateDiff( s,StartTime ,EndTime)
else 0
end
) as nvarchar( 50)),
cast(
sum(
CASE
when PhoneNum like '0%' then DateDiff (s, StartTime,EndTime )
else 0
end
) as nvarchar( 50))
from T_PhoneWork
30.索引
全表掃描:對數據進行檢索(select)效率最差的是全表掃描,就是一條條的找
如果沒有目錄,查漢語字典就要一頁頁的翻,而有了目錄只要查目錄即可.爲了提高檢索速度,可以爲經常進行檢索的列添加索引,相當於創建目錄
建立索引優點:檢索速度快
缺點:佔磁盤空間,降低編輯表的操作,如insert,update
(*)即使創建了索引,仍然有可能全表掃描,比如like,函數,類型轉換等
31.表連接jion 主流不增加外鍵
有客戶表 和 訂單表 ,關聯查詢 [table1] as [別名] join [table2] as [別名] on [約束條件]
select o. BillNo,p .Name, p.Age
32.子查詢
將一個查詢語句作爲一個結果,作爲一個結果集供其他SQL語句使用,就像使用普通的表一樣,被當做結果集的查詢語句被稱爲子查詢.
左右可以使用表的地方几乎都可以使用子查詢來代替
select * from
(select * from Person1) as p1
單值作爲子查詢 一行一列,單值查詢
單列多行的數據可看做一個數據集,單列多行的子查詢
例子
select * from T_Reader
where FYearOfJoin IN( 2001,2003 )
select * from T_Reader
where FYearOfJoin IN
(select FYearPublished from T_Book) --查詢書記出版那年加入協會的人的信息
select * from
(
select ROW_NUMBER() OVER( ORDER BY Age ASC) AS rownum ,
Number ,Name, Age,NickName From Person1
) as e1
where e1. rownum>=3 and e1. rownum<=5
經典的應用是: 分頁的操作
select * from (
select ROW_NUMBER()
over(order by k1 .TimeDiff DESC ) as rownum,k1 .WorkNum, k1.TimeDiff as d
from (
select WorkNum, sum(datediff (second, StartTime,EndTime )) as TimeDiff
from T_PhoneWorkTest
group by WorkNum
)as k1
) as e1
where e1. rownum >= 2 and e1. rownum <=3