子句邊界與不開清單
本頁包含往回判斷子句關鍵字時要認得的結構與語句界線,以及哪些位置不開清單或預設不選。 清單本身怎麼排名與觸發見補全,關鍵字目錄見關鍵字。
往回找子句關鍵字時要認得的結構
「最近的子句關鍵字」不是往回數詞元就找得到的:
- 括號群組是一個運算元,往回走時整組跳過;走進
FROM (SELECT … ON a = b) d撈到內層的ON就打不出WHERE。 配對不起來時放行成Any。 - 寫完的
CASE … END也是運算元,後面照外層位置。還沒寫完的 CASE 是游標 所在的那一層:CASE WHEN a = 1 THEN b之後接WHEN、ELSE、END。 - 逗號代表清單再來一項,位置回到清單的起點:
SELECT a,與SELECT同一個位置; 判成尾端的話CASE不見。 - TOP 子句不是選取清單的一項:
SELECT TOP 10、TOP (10)、TOP 10 PERCENT之後仍是起點,另接PERCENT、WITH TIES。 ON的述詞寫完之後是兩個位置的聯集:述詞尾端(AND、OR)與資料來源尾端 (WHERE、JOIN、GROUP)。SET子句寫完之後也是:UPDATE t SET a = 1另接WHERE、FROM、OUTPUT。- 其餘的
SET帶出選項(含ALTER DATABASE x SET)。名稱寫完 (SET NOCOUNT)只列ON、OFF這類值;停在關鍵字上是還沒寫完(SET IDENTITY_INSERT要資料表)。值寫完這一句就結束;否則SET ANSI_NULLS ON⏎G的ON被當成 JOIN 的,GO變成GROUPING。識別字的值(SET DATEFORMAT dmy) 與名稱分不開,換行才補語句開頭。 NOT也是聯集:WHERE NOT開一個述詞,a.Big5Code NOT之後接IN、LIKE。IF、WHILE是錨點:條件寫完是主體的開頭,也接AND、OR;括號沒關上時只算條件。 IF 只有一句的主體寫完另接ELSE(IfBodyEnd)。- 區塊邊界之後是下一句:
BEGIN TRY、END CATCH、IF 的ELSE。BEGIN … END的 END 另接ELSE、TRY、CATCH(BlockEnd);CASE 的 ELSE 與 END 不算。
名稱位置三分類
分析器替游標那一格分類(SqlCompletionSlot);開不開、選不選只看 SqlCompletionPolicy 一條規則。開的兩類還要候選集合封閉或前綴達到觸發字元數。
| 分類 | 意思 | 例子 | 清單 |
|---|---|---|---|
Inert | 不可補 | 字串、註解、10、1. | 不開 |
Name | 一定是新名字 | AS 、DECLARE @、CREATE PROCEDURE dbo. | 不開 |
MaybeName | 名字或關鍵字都可能 | FROM dbo.T 、SELECT PublCode 、CREATE PROCEDURE | 開,軟選 |
Grammar | 其餘 | SELECT 、WHERE a = | 開,打了字才硬選 |
MaybeName 的 FROM dbo.T W 可能是別名也可能是打到一半的 WHERE,軟選讓 Enter 保住別名, 代價是 FR+Enter 不再補成 FROM。它寫得出清單外的新名字,目標不讓它封閉:打了字才開。
Name:AS之後的別名、文法強制別名的括號之後(衍生資料表、PIVOT (…)、UNPIVOT (…))、DECLARE @(見變數)、CREATE <種類>列不出東西的那一段(見下文)、敘述開頭WITH與WITH a AS (…),的 CTE 名、SELECT … INTO的新資料表 (INSERT INTO、MERGE INTO要既有資料表,是Grammar)、RESULT SETS ((的資料行名稱。MaybeName:同一行沒有 AS 的別名、CREATE <種類>列得出東西的那一段、資料行定義的起點(CREATE TABLE t (、逗號之後、DECLARE @t TABLE ()、ALTER TABLE t ADD——新資料行名稱或CONSTRAINT都對。
括號是什麼由前面那個字決定:接在 FROM、JOIN、APPLY、USING 後面的是衍生資料表, 接在 IN、EXISTS、= 後面的是運算式;FROM (t1 JOIN t2 ON …) 是括號包起來的聯結、 名稱後的 WITH (NOLOCK) 是提示,都不接別名。AS 也看前面:一項剛寫完、還沒有別名時才是 別名,其餘照常——CREATE VIEW v AS 的主體、EXECUTE AS、FOR SYSTEM_TIME AS(接 OF)。 CAST(x AS 由型別的位置先接走。
別名規則
資料來源與選取清單共用一條:同一行、一項剛寫完、還沒有別名就是 MaybeName。
- 一項:資料來源是名稱或資料表值函式呼叫,連同後綴
FOR SYSTEM_TIME …與函式的WITH (…)資料行結構描述(OPENJSON(@j) WITH (a int)),前面直接是FROM、JOIN、APPLY、USING、MERGE [INTO]或 FROM 清單的逗號;選取清單是一整個運算式, 往回到SELECT、逗號或 TOP 子句。 - DELETE 自己的 FROM 帶出動詞的目標、不接資料來源的 FROM 帶出游標或裝置,都不接別名 (
Grammar):DELETE [TOP (5)] FROM t、FETCH NEXT FROM c。DELETE a FROM t照常。 - 項目結尾是識別字、變數、
)、常值或CASE … END的END;*後面不接別名。 - 還沒有別名:最後一個運算元前面不緊鄰另一個運算元或
AS。 - 同一行:前一個詞元結尾到游標之間沒有換行(註解前的也算), 這是分開別名與
WHE的唯一線索。
CREATE 的名稱格
名稱只有最後一段是新的:列得出東西的那一段是 MaybeName,列不出才是 Name(CreatedNameSlot)。 列得出的是既有物件(CREATE OR ALTER )、同一格的字(CREATE DATABASE SCOPED),或還沒寫限定字時的 結構描述(種類由產生器探出)。 其餘是 Name:CREATE PROCEDURE dbo.、CREATE INDEX 。
取捨:不列資料庫(跨庫建立少見)。打了字才開,否則片段 cp 名稱欄位的 Tab 把 dbo 提交進 dbo.ProcedureName;代價是 CREATE OR ALTER PROCEDURE 也不再空前綴就開。SELECT … INTO 仍整格 Name。
語句的界線
錨點只在游標所在的那一句裡找,自己沒有錨點的一句(EXEC、PRINT)是 Any: 借上一句的話,WHERE b = 1⏎EXEC p @x 打不出 OUTPUT。
語句開頭是能開始一句的關鍵字,而且前一格是界線。這種字也寫在句中(WITH (NOLOCK)、 DROP TABLE IF、THEN UPDATE、INSERT … SELECT),分開它們的就是前一格:
- 明確的:前一格含語句開頭、區塊開頭或區塊的 END——
;、GO、BEGIN、ELSE、模組標頭的AS、IF 的條件、SET 選項的值、寫完一整句的字(BREAK)。 - 隱含的:子句尾端又換了行(下一節),或前一句判不出位置而寫到一個運算元。 但剖析器不看換行:前一句的片語確定接得上的字仍屬於前一句 (
OFFSET 0 ROWS⏎FETCH、ALTER DATABASE d⏎SET)。 WITH只認明確的:CTE 前一句必須以分號結束,CREATE VIEW v⏎WITH SCHEMABINDING是選項。
子句屬於哪個動詞另問往回第一個能開始一句的字(FindVerb,UPDATE t⏎SET 的 SET 屬於 UPDATE); 權限清單的一項(REVOKE SELECT)與 WITH 不算,IF UPDATE(a) 是函式,CASE … END 整組跳過。
- FROM 只在動詞是 SELECT、UPDATE、DELETE 時接資料來源,INTO 只有 FETCH 的不接:
FETCH NEXT FROM c接INTO(FetchTail),RESTORE、REVOKE、BULK INSERT的 FROM 是Any。位置、目標與範圍分析 共用IntroducesDataSource,分岔時DISK被收成一張表。
沒有分號時,換行就是界線
WHERE a = 1 之後換行寫 SELECT 或 AND,詞元分不出差別;只給子句尾端會濾光下一句的片段 (ssf…)。所以子句已到尾端又換了行就補上 StatementStart,同一行不補。
補的是旗標聯集,續寫的 FROM、AND 照樣在;括號還沒關、名字那一格前面不補。 認的尾端見 StatementEndPositions,含選取清單:SELECT dbo.fn_Fee('') 不需要 FROM。
數值常值不開清單
SET Fine = Fine - 10 打到 10 時模糊比對會對到 LOG10,Enter 就把數字換成函式。 以數字開頭的詞元必然是數值常值,歸 Inert;點號前那一段以數字開頭也算(1.,否則平台以限定字 1 開清單),方括號裡的不算([192.0.2.10]. 是連結伺服器)。
變數後的點號只有資料表變數算限定字:@rows. 列它的資料行(提交時改寫成 [@rows]., 見插入文字),純量變數的 @x.value( 是 xml 方法,歸 Inert。