SQL學習基礎筆記


一.數據庫概述
(1)DBMS(數據庫管理系統)和數據庫,平時談到"數據庫"兩種含義:MSSQLSever,Oracle等某種DBMS;存放一堆數據表的一個分類(Catalog)
     不同牌子的DBMS有自己的不同特點
     主鍵有兩種選用策略:業務主鍵和邏輯主鍵.
     業務主鍵是使用有業務意義的字段做主鍵,比如身份證號,銀行賬號.
     邏輯主鍵是使用沒有任何業務意義的字段做主鍵.因爲很難保證業務主鍵不會重複,推薦用邏輯主鍵
(2)表間關聯,外鍵(ForeignKey)
(3)SQLSever的管理

二.數據庫基礎
(1)數據類型
     bit位,相當於bool類型,0,1
     char(10) 字符 長度10 不足用空格填充
     int整型
     bigint 超大整型
     nvarchar(MAX) 最大,無限大,可能有中文信息,日文   
     varchar() 無中文信息  不會用空格填充  var(variable)
     datatime 日期
     --註釋內容

三.SQL語句表操作
(1)ALTER 修改表
     關鍵字,表名,變量名對大小寫是不敏感的

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)

 SQL主要分DDL(數據定義語言)和DML(數據操作語言)兩類,Create Table,Drop Table,等屬於DDL, select,insert,update,delete,屬於DML

(2)主鍵選擇
     常用主鍵類型,int,bigint,uniqueidentifier(又稱GUID,UUID)
     guid算法使用mac地址,地址,納秒級時間,芯片id碼等算出來,每次guid永遠不會重複
     .net中生成guid的方法,Guid.NewGuid(),返回Guid類型   SQL中newid(),比如select newid()
     (*)int自增字段的優點:佔用空間小,無需開發人員干預,易讀;缺點: 效率低,數據導入導出的時候很痛苦
     (*)Guid的優點:效率高,數據導入導出方便; 缺點:佔用空間太大,不容易讀懂(慢慢成爲主流)
(3)數據插入
     可以給字段設置默認值,如果guid類型主鍵的默認設爲newid(),就會自動生成,很少這麼幹
     中文前面加N
     insert into Person2(Id,Name,Age)values(newid(),'tom',30)
(4)數據更新
     update Person1 set NickName=N'青年人' where Age>=20
     <>不等於
(5)表刪除
     刪除表中全部數據
     DELETE FROM TABLE_NAME WHERE

四.SQL數據檢索(*)
(1)數據的檢索 -- select
select * from  這裏注意在數據檢索中,如果能不用*就不用,儘量用所需要的字段名進行檢索 就像下面
     SELECT FName as 姓名, Fage as年齡 ,Fsalary as 月薪FROM T_Employee
     <as的作用 :取別名>
 

 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 

(2)數據的排序 -- order by
 

 select * from Person1 order by Age (ASC升序 DESC降序) ascend   descend
 select * from Person1 order by Age DESC,Number ASC;按照age降序,number升序

 order by 要放在where句子後面

(3)模糊搜索 -- like
通配符
     單字符通配符“_”,它匹配單個出現的字符, LIKE '_erry'    任意第一個字符
     多字符通配符“%”,它匹配任意長度字符,0到多個 LIKE '%n%'   包含n的所有字符
(4)sql中的null的理解
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
     根據年齡進行分組,
(7)Having語句
     聚合函數不應出現在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不一樣,不顯示就失去數據了
(10)union 聯合
    select Age from Person1
     union
     select Age from Person2
     組合成一列 ,關鍵字段必須一致,數據類型要相容
     select Age, NickName from Person1
     union
     select Age, '沒有暱稱' from Person2
     會去掉完全重複的數據,union all 就可以不去掉(一般都用union all)
案例1

 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)

(11)數字函數
     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)
(14)類型轉換函數  

 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)) : 確保類型正確


(15) Isnull  空值控制函數

 ISNULL(expression,value): 如果 expression不爲空,返回expression,否則返回value
  例子:select ISNULL(Name,'佚名') from Person1

 

(16) case函數用法1   面試中用到很多
     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


五.課後練習(*)
練習1
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


4.輸出本月撥打號碼次數最多的前三個呼叫員的編號
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 [約束條件]
     例子:顯示所有年齡大於25的客戶訂單號,客戶名字,客戶年齡
           select o. BillNo,p .Name, p.Age
      from T_Order as o join Person1 as p on o.CustomerId =p. Number
       where p. Age > 25
     例子2:大於平均年齡
select o. BillNo,p .Name, p.Age
from T_Order as o join Person1 as p on o.CustomerId =p. Number
where p. Age > (select avg(Age ) from Person1)
    
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

 


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