那些年我們寫過的T-SQL(上)

来源:http://www.cnblogs.com/wanliwang01/archive/2016/02/05/TSQL_Base02.html
-Advertisement-
Play Games

在當今這個多種不同資料庫混用,各種不同語言不同框架融合的年代(一切為了降低成本並高效的提供服務),知識點多如牛毛。雖然大部分SQL腳本可以使用標準SQL來寫,但在實際中,效率就是一切,因而每種不同廠商的SQL新特性有時還是會用到,這部分內容更是讓人抓瞎,常常會由於一些很簡單的問題花很久來搜索準確答案


在當今這個多種不同資料庫混用,各種不同語言不同框架融合的年代(一切為了降低成本並高效的提供服務),知識點多如牛毛。雖然大部分SQL腳本可以使用標準SQL來寫,但在實際中,效率就是一切,因而每種不同廠商的SQL新特性有時還是會用到,這部分內容更是讓人抓瞎,常常會由於一些很簡單的問題花很久來搜索準確答案。趕腳俺弱小的智力已經完全無法記清楚常見的命令了,即使是用的最熟悉的T-SQL(SQL Server)。因此將最常見的T-SQL操作做個簡單的總結,包括一些容易忽視的知識點和常見的開發樣例。實話實說,現在開發中較少直接寫SQL了,但有時需要給測試團隊提供一些便利還是需要的。

本系列包含上中下三篇,內容比較駁雜,望大家耐心閱讀:

那些年我們寫過的T-SQL(上):上篇介紹查詢的基礎,包括基本查詢的邏輯順序、聯接和子查詢

那些年我們寫過的T-SQL(中):中篇介紹表表達式、集合運算符和開窗函數(編輯中)

那些年我們寫過的T-SQL(下):下篇介紹數據修改、事務&併發和可編程對象(編輯中)

 

預祝大家新年快樂,萬事如意! I believe: 萬丈高樓平地起,大海無邊百川融。

這部分中重要的概念就是要弄清楚SQL語句具體的執行順序,記得在南京做一個短期培訓講師期間,就發現這部分是一個很容易被忽視的基礎,一旦弄清這部分內容,基本的標準SQL的編寫基本上就沒有很大問題了。此外關於SQL的一個非常關鍵的概念是,儘可能的使SQL語句進行的是整體的集合操作,而不是類似游標的迴圈迭代操作,這一點也是SQL優化的一個核心概念。

語句
執行順序
SELECT empid, YEAR(orderdate) AS orderyear, COUNT(*) AS numorders
FROM Sales.Orders
WHERE custid = 71
GROUP BY empid, YEAR(orderdate)
HAVING COUNT(*) > 1
ORDER BY empid, orderyear [ASC, DESC]
  1. FROM,從Sales.Orders表查詢行
  2. WHERE, 僅篩選ID為71的客戶
  3. GROUP BY,按固原ID和訂單年度分組
  4. HAVING, 篩選大於1個訂單的組
  5. SELECT,返回每組成員ID、訂單年度、訂單數量
  6. ORDER BY,按固原ID和訂單順序排序輸出行

不知道這兒的執行順序和你心中的是否相同,記得瞭解到這部分知識時,自己也花了很久去理解, 不過從形式上可以看到實際的執行順序很像LINQ,有木有?SQL只所以語句順序和實際執行順序不同是因為SQL設計師將該高級語言作為聲明式語言來定義的,"可以按照類似英語的方法提供自己的請求"。之所以說這部分重要,不知道大家遇到過自己給欄位起的別名在where中不能使用的情況沒有,那是因而where執行時,select還未執行,那麼select中給欄位其的別名還不存在好,但在order by字句中就可以正常使用。接下來,補充說明一下以上六個字句中的相關知識。

 

FROM字句:在From字句中的對象中需要附加上schema架構限定,如dbo.Sales, hr.Employee等。

WHERE字句:該字句中欄位的選擇對於查詢性能影響很大,如果符合索引(包括組合索引,需要正確的順序)條件,那麼查詢就會通過索引而不是全表掃描。例如建立的組合索引為(name, time),那麼如果查詢中使用where time =xx and name = xx會造成索引不起作用,而造成全表掃描,當然由於內置查詢優化器的存在,實際的查詢可能與教科書上說的不同, 一定要實際查看執行計劃,一起以事實說話。在實際項目中,資料庫的設計需要保證基本不犯明顯的錯誤即可,其他的到出現性能問題時通過查詢計劃和查詢統計信息才去優化,不用過度設計,因為數據量沒變化一個量級可能調優的方式就會出現不同。才外,需要記住,在TSQL中使用三值謂詞邏輯,邏輯表達式可以計算為TRUE、FALSE和UNKNOWN,而如果數據欄位為空,需要使用IS [NOT] NULL判斷。

 

GROUP BY字句:當涉及分組時,其後續的所有操作都是對組的操作而不是對單個行的操作,每組均是一個單個行,這些操作中表達式需要保證返回一個標量。不參與到group by中的欄位僅允許作為一個聚合函數的輸入,如COUNT、SUM等。註意,除了Count(*)外,所有的聚合函數忽略NULL標記,DISTINCT可以包含在聚合函數中,針對不重覆且有值的項。

HAVING字句:可以指定一個謂詞來篩選組而不是單個的行,比如使用集合函數count(*)>1表示篩選組成員大於1的組。

 

SELECT字句:指定返回到查詢結果表中列的地方,可以包含表達式,推薦給表達式創建一個易懂的別名,比如Year(orderdate) AS OrderYear,尤其是新增一些與列無關的表達式,如current_timestamp()函數,使關係模型變得完善。這人再次提及SELECT字句中別名的使用範圍,只能是SELECT字句執行之後的部分,也就是Order by字句。此外,有一點曾經困擾了我很久,就是如果我在where字句中使用YEAR(orderdate),還在select中使用YEAR(orderdate),那樣不是重覆計算了?其實,SQL SERVER能夠識別查詢中重覆使用的相同表達式,也就是說在一個查詢,出現多次相同的表達式,實際上只會運算一次,簡直贊贊噠。不過在同層中使用別名還是沒有被支持的,例如,

SELECT YEAR(orderdata)AS orderYear, orderYear + 1 AS nextyear是不正確的。常見的,我們在一般的查詢中,比如檢驗數據等,是推薦使用SELECT *,包括加上top 1000的,但在項目代碼中,是嚴禁這樣的操作的。

補充一點關係代數的知識,我們知道在關係模型中,所有操作均基於關係代數,並且操作結果是一個關係集合,但實際上我們返回的結果集還是會出現重覆行的情況,不過可以通過DISTINCT關鍵字刪除重覆行。

ORDER BY字句:按序輸出行,需要理解的是,在SQL中,表中沒有確定的順序,表假定為一個集合,集合是沒有順序(這個觀念如果是半路出家,需要很久才能真正理會的到)。因此,Order by之後的有序結果,其實失去表資格,一般將這種結果稱之為游標,"一個具有確定行順序的非關係型結果",這部分概念在之後的還會有介紹。此外,該字句中可以使用不在SELECT列表中的欄位排序,但如果使用了DISTINCT關鍵字,則必須使用SELECT列表中的列,否則由於單個結果行可能代表多個原行,造成排序的不清晰。

這兒有點需要補充的是,在同樣的ORDER BY條件下,可能會得到不一樣結果的問題,這個其實和數據結構中排序的概念一樣。在某個條件(比如order by日期)下,有多個符合條件的記錄時,這幾個結果集的順序是不一定的(已實際訪問的物理記錄行的順序為準),屬於不穩定排序。常見排序演算法中,快速排序希爾排序堆排序直接選擇排序不是穩定的排序演算法,而基數排序冒泡排序直接插入排序、折半插入排序、歸併排序是穩定的排序演算法。那麼有沒有穩定的情況呢,那麼就需要排序條件中的每一項都是獨一無二的,比如是主鍵列,唯一列,這種屬性也稱之為排序的決勝屬性(tiebreaker)

 

此外註意在SQL的關鍵字和系統函數名使用大寫,涉及多表查詢時需要給表起別名方便理解。以上是最核心的部分,接下來以列表的形式闡述與基本查詢相關的SQL關鍵字。

關鍵字

解釋與示例

TOP

T-SQL特有功能,用於限制查詢返回的行數或行的百分比

獲取前5行記錄:SELECT TOP 5 userid FROM HR.Employee ORDER BY userid

獲取前5%的記錄:SELECT TOP 5 PERCENT userid FROM HR.Employee ORDER BY userid

這兒其實隱含了一個問題,就是這兒TOP返回的結果是表結果還是游標,因為之前有提到,使用order by之後返回的游標,這個問問的解釋會放到表表達式部分。

OFFSET-FETCH

這是標準SQL的選取行數的語法,並且支持跳過功能,免得我們需要使用開窗函數或者兩個TOP取交來實現該功能,等價於C#中 XXX.Skip(m).Take(n)

查詢第51到75條記錄:SELECT userid FROM HR.Employee ORDER BY userid OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY

Tip:ROW和ROWS關鍵字等價,該關鍵字不支持PERCENT和WITH TIES選項

ROW_NUMBER

是一種開窗函數,理解起來有點困難,其實就是對分組中的數據做更加細粒度的操作,方便實現複雜的查詢,尤其是為報告服務(SSAS報表分析服務)。為了之後能更好的理解該知識點,提前拿出來給大家見見面,本文下篇還會具體介紹

開窗函數的定義:對於一個查詢中的每一行,按行的視窗組進行運算,並計算一個標量結果值,行的視窗使用OVER字句定義

SELECT userid, ROW_NUMBER() OVER(PARTITION BY userid ORDER BY name) AS rownum

這兒的PARTITION分區其實就是分組條件,ROW_NUMBER函數實際用於對分組後小組內成員標上行號,同時OVER窗中的ORDER BY是組內的排序,規則和正常排序一致

 

  • 謂詞、常見運算符和系統函數

謂詞(Predicate,這個委托熟悉不?)主要出現在WHERE、HAVING查詢篩選中,包括TRUE、FALSE和UNKNOWN中邏輯結果,這兒一定不能忘記UNKNOWN未知結果這種情況,比如說讓兩個NULL作比較等,接下來用一個簡單的表格展示。

關鍵字

解釋與示例

BETWEEN, IN, LIKE

BETWEEN AND表示屬於什麼之間;IN表示在枚舉出來的幾個值中;LIKE可以使用%作為萬能替代符,主要註意的LIKE中預設使用的Unicode的字元類型,並且在使用LIKE關鍵字時一定要謹慎,會造成很大的查詢消耗,如果實在需要大量字元串的查詢,考慮使用全文檢索或選用其他類型資料庫等解決方案

NOT, AND, OR

分別表示非、與、或的邏輯,優先順序依次遞減

%

取餘操作符或是之前介紹的萬能占位符

CAST(col1 AS NUMERIC(12, 2))

在數值運算時,如果出現兩個整型相除,需要修改其類型避免丟失小數點後位數

CASE

CASE是一個標量表達式,返回一個基於條件邏輯的值,需要註意CASE不是語句不能用於控制邏輯(比如IF ELSE),實際中,CASE的使用場景還是很多的,比如行列轉換等,才外,ORANGE有一個叫做的decade的簡化版操作符。

尤其需要註意的是,CASE具有"簡單"和"搜索"兩種格式,後者非常的靈活

簡單格式: SELECT studentid, CASE score WHEN 59 THEN 'Fail' WHEN 60 THEN 'Alive' FROM dbo.testScore

搜索格式: SELECT studentid, CASE WHEN score < 60 THEN 'Bad' WHEN score > 60 THEN 'Good'ELSE 'UNKNOWN' FROM dbo.testScore

此外,在SQL SERVER2012中還增加幾個簡化操作符, COALESCE , CHOOSE,ISNULL等,比如ISNULL(col1, '')表示Nullable<T> ?? '',若col1不為空就取其值,為空就是''空字元串,不過均不推薦使用。

NULL

NULL標記的理解在SQL中非常重要,很多細微的SQL錯誤都來之於此。其根源仍然是之前提到的3值邏輯,NULL標記表示不知道是什麼值(在現實生活中,就像登記時缺失了),它與除了IS [NOT] NULL邏輯操作以外的邏輯運算結果均是UNKNOWN。

為了更好的理解應用這個概念,來看看接下來的例子

SELECT COUNT(*) FROM Address WHERE region <> 'Beijing', 假設該表中100條記錄,10條的region是Beijing,20條的region為NULL,70為其他城市,那麼這個查詢的結果將是70,而不是我們想要的90,修改查詢如下即可。

SELECT COUNT(*) FROM Address WHERE region <> 'Beijing' OR region IS NULL

 

  • 同時操作

同時操作(all-at-once operations)表示出現在同一邏輯處理階段的所有表達式在同一時間點進行邏輯運算,即並行運算,這個概念是之前查詢順序概念的補充,之前講的縱向的順序,這兒講的是橫向的並行。是不是覺得很拗口,其實重點就是SQL在同一層中運算的順序不固定,所以之後運算一定不能依賴於之前的運算,並且不支持C#等常見語言中的短路: if(result != null && result == true),前者失敗後者不運算,接下舉兩個錯誤的例子。

SELECT orderID, YEAR(orderdate) AS orderyear, orderyear + 1 AS nextyear FROM [order]
SELECT num1, num2 FROM dbo.tableB WHERE num1 <> 0 AND num2/num1 > 5

那麼不禁要問,SQL中能提供同層次的邏輯運算的解決方案麽?其實是有的,一種技巧性的,一種是通過合理的規劃。

技巧性
通過使用CASE表達式來實現,形式上有一些奇怪
SELECT num1, num2 FROM dbo.tableB CASE WHEN num1 = 0 THEN 0 WHEN num1/num2 > 2 THEN 1 ELSE 0 END = 1。 其中1表示true,0 表示false
合理規劃
SELECT num1, num2 FROM dbo.tableB WHERE (num1 < 0 AND num2/num1 > 5) OR (num1 > 0 AND num2/num1 > 5)

 

  • 字元數據類型及其函數

最基礎的字元類型包括 ASCII(American Standard Code for Information Interchange,這單詞還是第一次認真看)和Unicode類型,在T-SQL中就是(CHAR, VARCHAR)和(NCHAR, NVARCHAR)。ASCII每個字元用一個位元組存儲,用''單引號括起來,Unicode用2個位元組存儲,用N''包起來。CHAR字元類型是固定大小的,效率高但空間浪費率高,VARCHAR靈活節省空間,有2個位元組偏移數據,但在欄位值變長時,可能出現行擴展導致分頁等,更新效率較低。字元類型預設最長(max)為8000個字元,若超過使用LOB存儲,放在行外,此外數據在壓縮(Data Compression)是會有一些變化。

介紹一個不常見的知識點,排序規則,知道以下概念即可

獲取資料庫支持的排序規則:SELECT * FROM sys.fn_helpcollations()
篩選條件區分大小寫; SELECT * FROM user WHERE name COLLATE Latin1_General_CS_AS = N'xionger'

接下來是最重要的字元函數使用示例列表

關鍵字

解釋與示例

+, CONCAT

連接字元串, SELECT firstname + lastname AS fullname FROM user,需要註意的是null與任何字元串連接操作的結果還是NULL

SUBSTRING

獲取world子串:SELECT SUBSTRING('hello world', 7, 5),註意index從1開始,不是0

LEFT, RIGHT

SUBSTRING的簡化形式,獲取字元串左邊/右邊指定的字元數,有個一個很經典的應用場景如下

對ID值補0操作:SELECT RIGHT('0000000000' + CAST(1973 AS char(10)), 10), 1973可以為任何的類似ID的變數

LEN, DATALENGTH

前者返回字元長度,後者返回位元組長度,SELECT LEN('abcde'), LEN(N'abcde'), DATALENGTH(N'abcde')的結果為: 5, 5, 10

CHARINDEX, PATINDEX

前者返回子串第一次出現的位置,後者返回匹配的子串第一次出現的位置,SELECT CHARINDEX(' ', 'xiong er 1'), PATINDEX('%[1-9]', 'xiong er 1'),結果6, 10

REPLACE, REPLICATE, STUFF

分別是替換、複製和刪除後新增,SELECT REPLACE('1e11', 'e', '1'), REPLICATE('0', 10), STUFF('1e11', 2, 2, '222'),結果為 1111, 0000000000, 12221

LIKE

包括幾個常見的通配符,% 表示任意大小字元串 ,_ 表示單個字元,以及其他常見正則表達式,如[ABC]、[A-Z]、[^1-9]

 

  • 時間日期數據類型及其函數

在T-SQL中,常見的時間類型僅僅包含DATETIME,其實記住這個基本上足夠用了。其他的都是一些更高精度和便捷的選擇,包括SMALLDATETIME,DATE, TIME, DATETIME2,DATETIMEOFFSET等,精度達到了ns納秒級,需要時再查閱即可。需要提及的一點時,在SQL中經常使用字元串常量格式的日期實際上最終是通過一個隱式轉化為變為DATETIME類型的,如ordedate = '20160203'等價於orderdate = CAST('20160203'AS DATETIME),這兒的轉化是基於當前會話的語言格式的,在實際中為了相容,推薦使用與語言無關的常量格式: YYYYMMDD hh:mm:ss.nnn或YYYT-MM-DD。

接下來,將一個很容易忽視的知識點,篩選時間範圍,涉及查詢優化,比如我們想選擇今年的全部訂單,很自然的會想到如下SQL語句。

錯誤的方式
SELECT * FROM [order] WHERE YEAR(orderdate) = 2016
正確的方式
SELECT * FROM [order] WHERE orderdate >= '20160101' AND orderdate < '20170101'

對於所有的查詢條件,儘可能的不要在其上使用表達式,這樣查詢優化器更可能通過索引的方式查找,此外想說的是,查詢的條件的順序也很重要哦,其需要和你所建立組合索引的順序一致。

 

時間日期函數看起來比較簡單,但在實際的使用中,由於不同的時間格式,往往會讓人非常的困擾,畢竟那麼多的API使用起來選擇比較多,這兒將最常見的羅列了出來。

關鍵字

解釋與示例

GETDATE(), CURRENT_TIMESTAMP

均是獲得當前時間,後者遵循ANSI SQL規範

CAST, CONVERT, PARSE

將輸入值轉換為目標類型,CAST(value AS datatype)最簡單,CONVERT(datatype, value [,style_number])足夠完美,PARSE(value AS datatype [USING culture])

在SQLSERVER2008之後版本獲取時間、日期方式:CAST(GETDATE() AS DATE), CAST(GETDATE() AS TIME)

老版本相容方式:SELECT CONVERT(CHAR(8),GETDATE(),112), SELECT CONVERT(CHAR(12),GETDATE(),114)

此外如果想的到今天的午夜時間可以用:SELECT CAST(CONVERT(CHAR(8),GETDATE(),112) AS DATETIME)

DATEADD

增加一年, SELECT DATEADD(year, 1, CURRENT_TIMESTAMP), month, day,second, quarter季度, week星期等類似

DATEDIFF

返回兩個日期間的差值,SELECT DATEDIFF(day, '20160101', CURRENT_TIMESTAMP)

常見的,獲得本月(年)的開始:SELECT DATEADD(MONTH, DATEDIFF(month, '19000101', CURRENT_TIMESTAMP), '19000101')

獲得本月(年)的結束:SELECT DATEADD(day, -1, DATEADD(MONTH, DATEDIFF(month, '19000101', CURRENT_TIMESTAMP) + 1, '19000101'))

這部分如果和之前的篩選時間日期的知識點結合在一起就能寫出非常靈活的SQL代碼

DATEPART, YEAR, MONTH, DAY

獲取時間日期中的部分整數,DATEPART(month, CURRENT_TIMESTAMP), 後面的3個函數是前面的簡化版

 

  • 基本元數據查詢

對於.NET程式員來說,元數據這個概念一點也不陌生,這兒指的是資料庫本身以及其中對象的結構信息,接下來介紹最簡單的幾種元數據的查詢。

元數據查詢類型

解釋與示例

目錄視圖

獲取表信息:SELECT SCHEMA_NAME(schema_id) AS table_schema_name, name AS table_name FROM sys.tables

獲取列信息:SELECT name AS columnName, TYPE_NAME(system_type_id) AS columnType FROM SYS.columns WHERE object_id = object_id(N'dbo.tableA')

此外還有很多的目錄信息都在sys這個schema之下,這兒只選擇最常見的表和列

信息架構視圖(推薦使用)

這其實是前面目錄視圖的標準化版本,功能基本類似,相對更加的簡潔,推薦使用這種方式查詢,相關視圖均在INFORMATION_SCHEMA這一schema下

表信息: SELECT TABLE_CATALOG, TABLE_NAME, TABLE_SCHEMA, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES

列信息:SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'tableA' AND TABLE_SCHEMA = 'dbo'

系統存儲過程和函數

還可以通過存儲過程來查詢相關信息,比如EXEC sys.sp_tables; EXEC sys.sp_columns; EXEC sys.sp_help @objname = N'dbo.tableA'等,這種方式不是特別推薦,但sp_help在俺的SQL生涯中確實出現了很多次哦。此外SELECT SERVERPROPERTY('productlevel')可以查詢當前資料庫實例的版本,這不是重點,想說的是本機的查詢結果是RTM,這表示Release to Manufacturing發佈到生產製造,即正式版,有時遇到RTM、SP1等是註意理解。

DBCC命令

查看資料庫的隔離級別的信息:DBCC USEROPTIONS

 

在介紹聯接前先引出一個概念--表運算符,我們知道FROM字句是第一個被邏輯處理的字句,其中包含表信息,那麼對錶進行操作的運算符就是表運算符,其中本節要介紹的JOIN是最重要的,很多時候,工作中可能僅僅使用它就足夠,此外還是APPLY、PIVOT、UNPIVOT等操作符,之後會介紹。其中JOIN操作符對兩個輸入表進行操作,類型包括交叉聯接、內部聯接和外部聯接,它們之間的差別在於其邏輯查詢處理階段,這是本節的最需要理解的概念,是真正理解聯接操作的基礎,通過一個表格來做一個初步的瞭解(這部分初學時,很容易忽視,但非常重要)。

 
邏輯查詢階段
笛卡爾乘積
篩選
添加外部行
示例
聯接類型
 
交叉聯接
Y
N
N
SELECT u.userid, s.studentid FROM user AS u CROSS JOIN student AS s
內部聯接
Y
Y
N
SELECT u.userid, s.studentid FROM user AS u
INNER JOIN student AS s ON u.name = s.name
外部聯接
Y
Y
Y
SELECT u.userid, s.studentid FROM user AS u INNER JOIN student AS s
LEFT JOIN student AS s ON u.name = s.name

之前一直強調的邏輯查詢階段其實相對應與物理查詢階段的,由於資料庫查詢分析器的存在,有時看起來有性能問題的聯接也能運行的很好,所以當遇到查詢性能問題時,查看執行計劃和分析統計數據非常的重要。

 

交叉聯接:只包含笛卡爾乘積階段,比如一張表A有m行,表B有n行,其結果集有m*n行記錄。該類型使用場景非常少,但其中有2個場景還是需要知道的。

自交叉聯接
SELECT e1.empid, e2.empid FROM hr.employee AS e1 CROSS JOIN hr.employee AS e2
生成數字表(有點像數學的輔助函數)
首先在DB中創建一張包含1到10的數字表,之後通過這張表來構建1到1000的數字表
SELECT d3.digit * 100 + d2.digit * 10 + d1.digit + 1 AS n
FROM dbo.digits AS d1 CROSS JOIN dbo.digits AS d2 CROSS JOIN dbo.digits AS d3 ORDER BY n
這兒介紹這個的原因是,在實際工作中,為處理異構數據或者按指定格式呈現時,可能需要構建輔助表,埋下這樣一個種子就好

 

內部聯接:最常見和基礎的聯接方式,包含笛卡爾乘積和篩選兩個步驟,相對複雜的情形包括複合聯接、不等聯接和多聯接查詢,如下表所示。

情形

解釋與示例

複合聯接

一般在查流水、履歷時會遇到這樣的場景,因為這時並沒有一個唯一的主鍵標識,需要組合的候選鍵來查詢

SELECT dbo.tableA AS t1 JOIN dbo.tableB AS t2 ON t1.col1 = t2.col1 AND t1.col2 = t2.col2

不等聯接

用到不等聯接的場景不算太多,一種比較有意思婚配的婚配場景,找到一組人中所有婚配組合(不重覆,不並剔除自己和自己配對)

SELECT e1.empid, e2.empid FROM hr.employee AS e1 INNER JOIN hr.employee AS e2 ON e1.empid < e2.empid

多連接查詢

SELECT * FROM sales.[order] AS o INNER JOIN sales.orderdetail od ON o.orderid = od.orderid INNER JOIN sales.product p ON od.productid = p.id

自聯結

有一個比較典型的例子,就是在員工表找到自己的直屬領導

SELECT e1.*, e2.name AS manageName FROM hr.employee AS e1 INNER JOIN hr.employee AS e2 ON e1.manageid = e2.empid

 

外部聯接:除了包含內聯接的兩個邏輯處理階段,還包含一個"添加外部行"的第三個階段。外聯接包含LEFT OUTER JOIN、RIGHT OUTER JOIN和FULL OUTER JOIN三種類型,分別表示左側表為保留表、右側表為保留表和兩側表均為保留表。這兒的保留表也就是我們常說的基準表,即其中的每一條記錄實際上都會在最終的結果中顯示出來

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • jquery實現的點擊頁面其他地方隱藏顯示的元素:在實際應用中,可能有這樣的效果,那就是有這樣一個彈出層,點擊層本身的時候,這個層不會隱藏,而點擊除去層之外的頁面其他地方則會將這個層隱藏,下麵就通過代碼實例介紹一下如何實現此效果。代碼如下: <!DOCTYPE html> <html> <head>
  • js如何將字元串轉換數值類型:在實際應用中,可能需要將字元串類型轉換為數值類型,下麵就介紹一下如何實現此功能。一.轉換為整數: var strNum="3.1415926"; console.log(typeof(strNum)); console.log(parseInt(strNum)); co
  • css選擇器大於號>的作用是什麼:本章節介紹一下CSS選擇器中的大於號的作用。由於以前瀏覽器支持的問題,可能吃選擇器較少使用,但是隨著時間的推移,版本的更新,相容性已經不是問題,所以它的應用也就多了起來,下麵就通過代碼實例做一下簡單介紹。此選擇器能夠匹配指定元素的所有一級子元素。代碼實例: <!DO
  • 假期前最後一彈,iOS開發進階系列第五篇,希望對你能有所啟發! 另外,喜歡寫博客的博主可以申請加工程師博主交流群:391519124,分享你的博文,和大牛們一起交流技術~ 一、iOS 開發中的 Self-Manager 模式 創業公司的iOS程式員不容易啊,時常面對單挑一個項目的狀況,不過這也是能快
  • -(void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat sectionHeaderHeight = 20; if (scrollView.contentOffset.y <= sectionHeaderHeight&&scrol
  • 1:伺服器端/** * Created by LiuFei on 2016/1/22. */public class HttpService extends Service{ @Override public IBinder onBind(Intent intent) { return null;
  • 第一版: ListView一屏顯示多少對象其內部就創建多少View對象。滑動時退出的緩存對象留給滑進去時調用getView傳的convertView。因為如果每次都findViewById查找創建視圖對象,浪費性能和記憶體。所以我們都利用佈局創建View給convertView。佈局內部的view對象
  • 排名函數三兄弟,一看名字就知道,都是為了排名而生!但是各自有各自的特色!以下一個例子說明問題!(以下慄子沒有使用Partition By 的關鍵字,整個結果集進行排序) RANK 每個值一個排名,同樣的值排同樣的位置,如第一名有2個,下一個值就要排第三,如此類推,表現如下麵的 RandNr 列 DE
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...