2014-02-13 150 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刚刚决定使用蛮力的表太小,比尝试使用其他任何东西都快。我知道。感谢您的帮助。我很想离开临时编辑,但肯定会这样做,直到(除非)我有机会充分消化和整合。 –

相关问题