2014-02-13 193 views
2

我想知道,如果一個字符串的最後一個字符是一個星號*如何匹配TSQL中字符串的最後一個字符?

我有這給我的最後一個字符如下:

select RIGHT('hello*',1) 

,但我會怎麼使用它作爲一個條件在if語句中通過匹配嗎?以下不起作用,因爲它只返回最後一個字符。

select '*' = RIGHT('hello*',1) 

我可以使用正則表達式嗎?

回答

4

你只是在那裏。通過使用:

select '*' = RIGHT('hello*',1) 

的Sql評估RIGHT但認爲要別名它作爲一個名爲*

您可以使用條件表達式列:

if RIGHT('hello*',1) = '*' 
    print 'Ends in *' 
else 
    print 'Does not end in *' 

您可以過濾像等一張桌子:

select * 
from MyTable 
where RIGHT(MyColumn, 1) = '*'; 

雖然perfor mance將不會是恆星。 編輯:見卡爾Kieninger的答案如何,大大提高了該查詢

0

的性能試試這個想法:

DECLARE @x NVARCHAR(32) = 'bbbbbbb*aaaaaaa'; 

IF(LEN(@x)=(SELECT LEN(@x) - CHARINDEX('*', REVERSE(@x)) + 1)) 
PRINT 'End with *' 
ELSE 
PRINT 'No end with *' 
1

StuartLC提到的性能。您可以以索引持久計算列爲代價來提高性能。這種戰術已經在其他地方,如已經提到的幾種:

我創建了一個樣品,看看它在行動,但執行計劃表明,它從來沒有真正採摘提高我對索引期望的索引在計算列上的索引。所以現在我不確定我的測試有什麼問題。如果有人能指出我的失敗,我會更正答案。

CREATE TABLE Test(
    TestData VARCHAR(10) 
,TestData_Reverse AS REVERSE(TestData) PERSISTED 
,TestData_Right1 AS RIGHT(TestData,1) PERSISTED 
) 
INSERT INTO Test(TestData) VALUES ('Bob'),('Joe'),('Ed*') 

CREATE INDEX IX_Test_TestData ON Test (TestData) 
CREATE INDEX IX_Test_TestData_Reverse ON Test (TestData_Reverse) 
CREATE INDEX IX_Test_TestData_Right1 ON Test (TestData_Right1) 

GO 

SELECT * FROM Test WHERE TestData LIKE '%*' --Index Scan 
SELECT * FROM Test WHERE RIGHT(TestData,1) = '*' --Table Scan 
SELECT * FROM Test WHERE TestData LIKE '*%' --Index Seek 
SELECT * FROM Test WHERE TestData_Reverse LIKE '*%' --Table Scan 
SELECT * FROM Test WHERE LEFT(TestData_Reverse,1) = '*' --Index Scan 
SELECT * FROM Test WHERE TestData_Right1 = '*' --Table Scan 

DROP TABLE Test 

編輯 - 臨時編輯

這確實是優秀的 - 你只是需要更多的數據,從而使:

  1. 幾個「*」行選擇性提高到如此地步select select返回小於錶行總數的百分之幾,以保證搜索
  2. 用於存儲數據的頁面數量並不重要,這樣相對成本就會更準確
  3. 我們需要小心SELECT *的,因爲這將觸發RID /書籤查找(這是可能比集羣更加昂貴,因爲我們可以攜帶一個聚集索引列的至少一個)

這裏的更多的數據,測試在SQL Express 2014完成:

INSERT INTO Test(TestData) 
    SELECT o1.name + o2.name from sys.objects o1, sys.objects o2; 

UPDATE STATISTICS Test; 

SELECT TestData FROM Test WHERE TestData LIKE '%*' --Index Scan IX_Test_TestData *1 .038 
SELECT TestData FROM Test WHERE RIGHT(TestData,1) = '*' --Index Seek (IX_Test_TestData_Right1) *2 .003 
SELECT TestData FROM Test WHERE TestData LIKE '*%' --Index Seek IX_Test_TestData *3 .003 
SELECT TestData FROM Test WHERE TestData_Reverse LIKE '*%' --Index Scan IX_Test_TestData *4 .038 
SELECT TestData FROM Test WHERE LEFT(TestData_Reverse,1) = '*' --Index Scan IX_Test_TestData *5 .038 
SELECT TestData FROM Test WHERE LEFT(TestData_Right1,1) = '*' --Index Scan IX_Test_TestData_Right1 *5 .031 
SELECT TestData FROM Test WITH (INDEX = IX_Test_TestData_Reverse) WHERE TestData_Reverse LIKE '*%' --Index Scan IX_Test_TestData *6 .05 
SELECT TestData FROM Test WHERE TestData_Right1 = '*' --Index Seek IX_Test_TestData_Right1 *7 .003 
SELECT * FROM Test WHERE REVERSE(TestData) = '*dE' --Index Seek (IX_Test_TestData_Reverse) *8 .006 

好消息 IMO是SQL Server將能夠 「神交」 這RIGHT(TestData,1)可替代d爲計算列並且使用IX_Test_TestData_Right1(和REVERSE * 8相同)。這意味着(對於非常具體的查詢)(隱含地,對於非常具體的查詢),持久計算的列可以隱藏在世界後面,像普通索引那樣隱藏在幕後,並且意味着在有限的情況下實際上可以緩解函數缺乏可變性。

w.r.t.令人失望的掃描例如* 4,值得注意的是測試表是一個堆,並且Sql不使用LIKE運算符的可能原因之一是認爲到集羣的RID查找將超過使用IX_Test_TestData_Right/IX_Test_TestData_ReverseTestData。 我相信實際表格中的最佳策略是使用原始非反轉列的INCLUDE的覆蓋索引。

CREATE INDEX IX_Test_TestData_Reverse ON Test (TestData_Reverse) INCLUDE (TestData) 

SELECT TestData FROM Test WHERE TestData_Reverse LIKE '*%' --Index Scan IX_Test_TestData .003 
+0

這真是太好了,我不知道該SQL能夠替代品具有同等功能持久化計算列(這意味着你也可以給優化搜索,非單調函數的錯覺)。這個替換也發生在確定性標量('WITH SCHEMABINDING')用戶定義的函數上。 – StuartLC

+1

哦,對。 SQL Server剛剛決定使用蠻力的表太小,比嘗試使用其他任何東西都快。我知道。感謝您的幫助。我很想離開臨時編輯,但肯定會這樣做,直到(除非)我有機會充分消化和整合。 –

相關問題