如何使用基於策略的管理為對象名稱應用 Title-Case RegEx 條件
我在 SQL Server 2014 實例上實現 PBM,並希望強制執行一個條件,即所有對像都在
dbo
架構之外創建,並且所有對象名稱都以標題大小寫(即 OrderDetail)創建。我起草了正則表達式[A-Z]{1}[a-z]+[A-Z]?[a-z]*
,但無法用它創建令人滿意的對象名稱。範例輸出在這裡。
Policy condition: '@Schema != 'dbo' AND @Name LIKE '[A-Z]{1}[a-z]+[A-Z]?[a-z]*'' Policy description: '' Additional help: '' : '' Statement: 'CREATE TABLE Test.OrderDetail ( Col1 int)
PBM 不支持這個特定的表達式,還是我應該在條件中使用替代語法?
SQL Server 對Like運算符的實現僅支持一種真正縮減的正則表達式,其中包括基本字元匹配和萬用字元,但不包括重複次數 like
{1}
或其他類型的正則表達式錨點,如\b
or\s
。一般來說,它也是不區分大小寫的。也就是說,您有時可以使用
Like
. 假設您想找到 3 個字母字元和兩個數字,您可以執行以下操作:[a-z][a-z][a-z][0-9][0-9]
您還可以通過使用區分大小寫的排序規則來強制區分大小寫匹配,例如
DECLARE @s VARCHAR(10) = 'orderDetail' -- Check case; SELECT CASE WHEN UPPER( LEFT( @s, 1 ) ) = LEFT( @s, 1 ) COLLATE SQL_Latin1_General_CP1_CS_AS THEN 1 ELSE 0 END SET @s = 'OrderDetail' -- Check case; SELECT CASE WHEN UPPER( LEFT( @s, 1 ) ) = LEFT( @s, 1 ) COLLATE SQL_Latin1_General_CP1_CS_AS THEN 1 ELSE 0 END
然而,TitleCase 與其說是一種政策,不如說是一種哲學立場?您將如何確定TitleCase或Titlecase是否正確?事實上,他們倆都是。
您的特定正則表達式模式也將匹配“orderDetails”和“orderDetails”的“Details”部分。你可以做的是添加開始和結束詞錨,例如
^[A-Z]{1}[a-z]+[A-Z]?[a-z]*$
但正如所描述的,這無論如何都不起作用,
Like
我不相信這是值得的。所有你真正想做的(除了dbo
模式檢查,這很容易而且很有價值),就是檢查第一個字元是大寫的。所以理論上你可以用極其強大的 PBM ExecuteSql函式來做這樣的事情:ExecuteSql('Bool', 'SELECT CASE WHEN UPPER( LEFT( @@ObjectName, 1 ) ) = LEFT( @@ObjectName, 1 ) COLLATE SQL_Latin1_General_CP1_CS_AS THEN 1 ELSE 0 END')
我想我花了很短的時間就完成了這項工作,此外,您可能應該使用 camelCase :)
高溫高壓
我認為您的意思是PascalCase(不是camelCase),因為Title Case僅適用於單詞之間有空格的情況。
我同意@wBob 的觀點,即您可以通過 T-SQL 做的最好的事情是確保第一個字母是大寫的。儘管您可能會更進一步,擴展@wBob 建議的條件,並確保第二個字母(假設它不會被接受為具有單個字母表名)遵循相同的模式(並且您也可以使用二進制排序規則,因為您只是將字元與自身進行比較):
ExecuteSql('Bool', 'SELECT CASE WHEN UPPER( LEFT( @@ObjectName, 1 ) ) = LEFT( @@ObjectName, 1 ) COLLATE Latin1_General_100_BIN2 AND LOWER( SUBSTRING( @@ObjectName, 2, 1 ) ) = SUBSTRING( @@ObjectName, 2, 1 ) COLLATE Latin1_General_100_BIN2 THEN 1 ELSE 0 END')
但是,只要您這樣做
ExecuteSql
,您可能會朝著目標再邁出一步並應用實際的正則表達式。RegEx 功能只能通過 SQLCLR 獲得,在這種情況下,您可以編寫自己的程式碼或下載免費版本的SQL#(我創建的,但 RegEx 函式是免費的),並使用以下模式:\b(?:\p{Lu}\p{Ll}+)+\b
. 這個模式正在做的是:
\b
意思是“單詞邊界”。它不會在單詞中間匹配,但會在相鄰字元為空格、標點符號等時匹配單詞字元之前或之後的字元。(?: ... )+
指被找到 1 次或多次的非擷取組。\p{Lu}
表示與“大寫字母”的 Unicode 類別匹配的任何單個字元。\p{...}
表示“Unicode 類別”,而具體表示Lu
“大寫字母”類別(L
其本身表示任何字母,無論大小寫)。這允許此條件接受不屬於該A-Z
範圍的其他語言的大寫字母。無需指定{1}
表示單個實例,因為無論如何這是預設值。\p{Ll}+
表示與“小寫字母”的 Unicode 類別匹配的 1 個或多個字元。雖然我相信此模式擷取了您嘗試的模式的意圖,但正如您從下面的結果中看到的那樣,它仍然無法處理名稱中間應該使用大寫字母但目前是小寫的情況:
DECLARE @Tests TABLE (Name NVARCHAR(50), ExpectedResult BIT); INSERT INTO @Tests (Name, ExpectedResult) VALUES (N'OrderDetail', 1); INSERT INTO @Tests (Name, ExpectedResult) VALUES (N'orderDetail', 0); INSERT INTO @Tests (Name, ExpectedResult) VALUES (N'Orderdetail', 0); INSERT INTO @Tests (Name, ExpectedResult) VALUES (N'OrderDEtail', 0); INSERT INTO @Tests (Name, ExpectedResult) VALUES (N'ORderDetail', 0); INSERT INTO @Tests (Name, ExpectedResult) VALUES (N'OrderDetaiL', 0); SELECT t.[Name], t.ExpectedResult, SQL#.RegEx_IsMatch(t.[Name], N'\b(?:\p{Lu}\p{Ll}+)+\b', 1, NULL) AS [ActualResult] FROM @Tests t
回報:
Name ExpectedResult ActualResult OrderDetail 1 1 orderDetail 0 0 Orderdetail 0 1 OrderDEtail 0 0 ORderDetail 0 0 OrderDetaiL 0 0
Orderdetail
應該只有人類才能確定OrderDetail
。這就是為什麼,無論您如何實施條件,政策的“評估模式”都不應該是“改變:防止”。這種類型的標準/政策確實應該留給程式碼審查,所以最好將“評估模式”保留為“按需”,並可能在每個開發週期結束時執行它(雖然之前仍有機會修復它任何違規行為都會進入生產階段)。