Skip to content

查詢結果格線 ​

回到 索引。 欄位剖析與完整內容視窗的版面標準見自製 UI 準則。

SELECT 跑完之後,在結果格線上按右鍵,選單底下會多出一段 SqlAssist 的命令, 把選取的資料變成可以直接用的 T-SQL。範圍只到「格線上已經有的資料」——這裡的每一個 命令都不會再連一次資料庫。

命令直接排在右鍵選單上,不收成子選單:用法是「選幾格、按右鍵、挑一個」, 多一層子選單就是每一次都多一次移動與展開。

命令 ​

分成三段,分法照的是按下去之後東西跑到哪裡,不是功能相不相像。第一段進剪貼簿, 接下來要按的是 Ctrl+V;第二段開一個新的視窗,畫面會換掉,所以三項都帶刪節號。 混成一段的話,使用者要一項一項讀完才知道哪一個會把手上的畫面換掉。

命令產出交到哪裡
複製成 IN 條件一段接得上 WHERE 的述詞剪貼簿
複製成 Markdown 表格對齊過的 Markdown 表格剪貼簿
複製成 JSON一列一個物件的 JSON 陣列剪貼簿
建立 #temp 指令碼DROP 守門 + CREATE TABLE #SqlAssistRows + INSERT + SELECT新查詢視窗(沿用同一個連線)
欄位剖析每一欄的 NULL/空字串/相異值數與範圍一個可以複製成表格的視窗
檢視這一格完整內容那一格的原文,加上型別與大小一個可以選、可以捲的視窗
結果診斷資訊格線內部狀態的報告診斷紀錄檔(只在「詳細記錄」開啟時出現)

三種產出的去處不同,因為用法不同:#temp 是完整的一段指令碼,開進新視窗按 F5 就能跑;IN 條件是要貼進手上那一句查詢的,開新視窗反而多一次搬運;欄位剖析的用途 是看不是貼,178 欄的摘要塞進查詢視窗變成 178 行註解,比原本捲格線還難讀。 前三個複製命令只放純文字、不放 HTML:它們是要貼進 SQL、工單或設定檔的原文, 多一份 HTML 會讓 Word 或郵件把 Markdown 貼成表格。

欄位剖析在寬表上的價值遠高於窄表。真正想知道的往往只是「哪幾欄整欄是 NULL、 哪幾欄從頭到尾只有一個值」——那兩件事看資料看不出來,看摘要一眼就有。統計的對象 刻意就是眼前這一份結果,不是資料表的全貌;後者下一句 GROUP BY 比較快也比較準。

欄位剖析可依欄名/型別篩選,或快速只看「全為 NULL」「僅單一值」;後者至少需兩列, NULL 也算一種值。欄名在橫向捲動時固定,數量可按表頭排序;「複製目前表格」依目前 篩選與排序同時放 TSV 與 HTML 表格,貼進 Excel 就是一張表。 相異值數包含 NULL,不同於 SQL COUNT(DISTINCT); 最小/最大值與字元範圍的排序依顯示文字,不是跨型別的 SQL 比較。

格線一列只有一行高,而它顯示的字數上限是 65535(NumberOfCharsToShow)——一段 nvarchar(max) 的 XML 在格線上只看得到開頭那幾十個字,而且沒有「後面還有」的提示。 「檢視這一格的完整內容」取的是選取範圍第一個區塊的左上角,也就是剛剛按右鍵那一格。 文字與 XML 給原文(要讀的是內容本身,多一層引號跳脫只會擋路),二進位給十六進位 並每 32 位元組換行,其他型別給 T-SQL 字面值(那時候的下一步多半是貼進一句 WHERE)。 長度單位跟著型別走:文字算字元、二進位算位元組——混成同一個數字的話, 「這一欄會不會被截斷」就答不出來了。

完整內容的「自動換行」只改變閱讀方式,不格式化 JSON/XML、不改原始空白或複製內容。 NULL 與空內容各有提示,提示本身不會被複製;也可選取一段後按 Ctrl+C。

NULL 與空字串分開算:兩者在格線上都是不顯眼的一格,查問題時卻代表完全不同的事。 文字欄位另外報字元數範圍,那是找截斷的第一個線索——整欄都剛好 20 個字元的 nvarchar(20) 值得看一眼。最小與最大寫成 T-SQL 字面值而不是顯示字串,因為它們的 下一步幾乎一定是被貼進一句 WHERE。

為什麼沒有 Excel 匯出 ​

SSMS 22 自己就有:「另存結果為…」的存檔對話方塊裡有 CSV、TSV、JSON、XML、 Markdown 與 XLSX 六種格式(GridSaveFormats)。重做一份只會多一個要跟著 SSMS 改版維護的東西。

Markdown 例外,因為內建那條路有一個補得起來的落差:它一律寫成檔案、一律 整份結果,看不到選取範圍。而真正要貼進工單、PR 或聊天室的時候,要的是剪貼簿 裡的那幾列。所以「複製成 Markdown 表格」做的只有那一半,XLSX 就不重做。

表格是給人讀的,所以值不帶引號也不帶 N 前綴,但日期的精確度仍然跟著型別走—— 與儲存格視窗共用同一份判斷,否則同一個值在兩個地方長得不一樣,看起來像資料有問題。 真正的 NULL 寫成斜體的 *NULL*,一個內容剛好是 NULL 的字串就是那四個字: 兩者在渲染出來的表格上一個是斜體一個不是。豎線跳脫成 \|,換行換成 <br>—— 不處理的話,前者會切出一欄不存在的欄,後者會把一列切成兩列。

JSON 的型別對應 ​

JSON 是這一組命令裡唯一分得出 NULL 的文字格式:真正的 NULL 是 null, 一個內容剛好是 NULL 這四個字的字串是 "NULL",不必像 Markdown 那樣靠斜體區分。

去處只有三種,而挑錯的代價各不相同:數值寫成字串之後,收下這份 JSON 的那一端 要嘛比對失敗、要嘛自己再轉一次;字串寫成數值則會掉前導零。所以判斷一律看伺服器 給的型別,不看值長什麼樣——與 #temp 那段「別從值反推型別」是同一個理由。

來源JSON
SQL NULLnull
bittrue/false
數值型別不加引號的數值
二進位"0x..." 字串
其餘(文字、日期、GUID、XML)字串

值走 ResultGridCellText.Display,與 Markdown 表格同一份,日期精確度在兩個命令裡 才不會不一樣。也因此轉不成 T-SQL 字面值的型別在這裡不會整段拒絕:這一份的用途 是讀與貼,不是拿去執行。非 ASCII 照原樣寫出去而不是 \uXXXX——中文值轉成六個字元 一組之後就沒得讀了,而這份東西的去處正是工單與設定檔。

為什麼沒有 UPDATE/DELETE ​

原本規劃過「照主索引鍵產生 UPDATE/DELETE」,查完之後放棄,理由是資料拿不到而 不是不想做。

結果格線的結構描述來自 QEResultSet.GetSchemaRow,而那份 schema table 是 m_reader.GetSchemaTable()——那個 reader 是用 CommandBehavior.SequentialAccess(連線啟用 Always Encrypted 時是 Default) 執行的,全組件沒有一處用 KeyInfo。少了 KeyInfo,schema table 的 IsKey 與 BaseTableName 都不會填。也就是說格線既不知道這些欄屬於哪一張資料表, 也不知道哪幾欄是鍵。

那就只剩下猜:從查詢文字裡挑一個 FROM,再假設選到的欄能唯一識別資料列。 DELETE 猜錯是救不回來的,而「識別出這幾列」這件事 IN 條件已經做到了—— 把它貼進自己寫的 DELETE 只多一步,而那一步正是該由人確認的一步。

選取範圍怎麼算 ​

  • 沒有選取:整份結果。
  • 有選取:所有被選到的列 × 所有被選到的欄,取聯集。

聯集是刻意的。選取範圍不保證是矩形——按住 Ctrl 點六格拿到的是六個 1×1 的區塊, 而 INSERT 與 IN 都需要矩形的資料。挖洞的那一份要嘛補 NULL(值就錯了), 要嘛拆成好幾段(更難用)。產出的第一行一律寫明實際的形狀,範圍被撐開時看得出來。

一次最多 200,000 格(ResultGridSelectionPlan.MaxCells)。門檻用格數而不是列數: 一個 178 欄的查詢,1000 列就是 17.8 萬格,而列數的門檻在寬表與窄表上差太多。

以 Apache-2.0 授權條款發布 · 專為 SSMS 22 設計