java編程——MySQL 查詢栽坑筆記

前言

這幾天在做數據分析的時候,數據要自己從數據庫裡面拿(之前都是別人把數據庫導出來給我的說),心塞。還好之前學的SQL沒有忘掉,咱連上數據庫就開始寫查詢語句。之後就栽坑裡了,執行的結果與預期的結果相差甚遠,哭~。下面我把我栽坑的原因寫下來,以幫助到可能會在此栽坑的開發人員。

正文

SQL作為一門的聲明式語言,它的運行方式並不同於我們所熟知的命令式程序語言。

在此廢話幾句,解釋下什麼是聲明式語言,什麼是命令式語言。

聲明式語言:告訴計算機我要什麼結果,至於怎麼做,那是它的事情。

命令式語言:告訴計算機怎麼做,它會返回按照我要求做之後的結果。

java編程——MySQL 查詢栽坑筆記

執行順序的坑

按照上面的解釋,大概你也會了解一些為什麼有些SQL編程出來的東西和你實際想要的結果是有些出入的,因為我們在潛意識中的行為動作是按照命令式編程的思維方式思考的。就好像用戶在告訴計算機:“先執行第一步,再執行第二步,並在執行第二步之前先檢查一下是否滿足條件A 和條件B ”。例如,我們有時候會在SQL中用變量傳參、使用循環語句、調用函數等等,會按照命令式編程的思維編寫。然而,敲黑板, SQL恰恰沒有按照這種命令式編程的思維方式來處理問題。另外還有一點, SQL的執行順序並不參照語法順序 。下面表格【1】能幫你理解到這一點。

執行命令編寫順序執行順序SELECT18DISTINCT(等)29FROM31JOIN43ON52WHERE64GROUP BY75WITH86HAVING97ORDER BY1010LIMIT1111.........

也就是說在一個SQL語句開始執行的時候,最先執行的總是FROM操作,最後執行的是LIMIT操作,在執行過程中,每一個操作都會產生一張虛擬的表,每一個虛擬的表都會作為下一步處理的輸入,直至最後一步操作前,這些虛擬的表對於用戶都是透明的,最後一步的操作結果產生的表作為最終的輸出返回給用戶。

執行時使用的變量也有坑

在SQL中,用戶不只是可以使用系統中提供的變量,用戶也可以自定義一些變量以供快速開發使用。

對於一些語句中,比如SELECT,在使用用戶自定義變量時會得到期望的效果,但是,這個是很不穩定的。比如下面的語句,按照命令式編程思想地會認為MySQL會在第一輪和第二輪查詢的時候,會給 @b 附上值,之後 @b 顯示的是 @a 前兩次的數值,但是事實上, @b 會一直為0(不同的SQL解釋器的運行機制不同,結果可能不同):

SET @a = 0;

SET @b = 0;

SELECT

@b,

@b=@a,

@a:= @a + 1

FROM

sys.sys_config;

除此之外,還有另一個問題。變量的默認返回類型由語句開始時的類型決定的,正如下面的例子:

SET @a='test';

SELECT @a,(@a:=20) FROM tbl_name;

上述的SELECT語句中,MySQL會報告給客戶端第一列的字段類型為字符串,同時將所有對@a變量的使用均轉換為字符串處理,儘管在SELECT語句中將@a變量設置為數字類型。在SELECT語句執行後,@a變量才會在下一個語句中識別為數字類型。為了避免上述問題的發生,要麼不在同一個語句中同時賦值並使用變量,要麼在使用之前,將變量設置為0,0.0或者'',以確定它的數據類型。【2】

原文中有這樣的一句話

In a SELECT statement, each select expression is evaluated only when sent to the client. This means that in a HAVING , GROUP BY , or ORDER BY clause, referring to a variable that is assigned a value in the select expression list does not work as expected.

在SELECT語句中,每個選擇表達式僅在發送給客戶端時才被計算。 這意味著在HAVING,GROUP BY或ORDER BY子句中,引用在選擇表達式列表中指定值的用戶自定義變量不能按預期工作。 也就是說用戶自定義變量的值是在結果集發送到客戶端後才計算的

這裡有一種解釋是:“MySQL優化器在某些場景下可能會將這些變量優化掉,這可能導致代碼不按預想的方式運行。”

後記

關於用戶自定義變量,如果運用的好,能夠寫出高效簡潔的SQL語句,如果運用不當,也可能把自己給坑了(比如我? 哭~)。這個完全取決於使用它的人。

java編程——MySQL 查詢栽坑筆記


分享到:


相關文章: