假设我有一个包含varchar字段的表:
CREATE TABLE [MyTable] (
[MyId] varchar(3) NOT NULL,
.....
)
[MyId] 列包含连续的alphanum值,如A1,A2 ... A99,B1,B2..B99,C1等等(最高为Z99)。
我想要做的是从 MyId 字段与某些特定前缀匹配的表中提取行...例如我想从A,C,P和X系列中获取行。
我希望能够使用一个sproc,它会根据参数中提供的前缀字母动态构建查询。
我正在考虑这样的事情......
CREATE PROCEDURE [dbo].[uspFilterMyTable]
@prefixArray varchar(max)
AS
... -- split individual characters from @prefixArray into an array
SELECT * FROM [MyTable]
WHERE
[MyId] LIKE ....
OR
[MyId] LIKE .... -- iterate all characters from @prefixArray
我认为存储过程的主要部分将类似于以下伪代码:
DECLARE @sql nvarchar(max)
-- iterate through all the characters
SET @sql = 'SELECT * FROM [MyTable] WHERE [MyId] LIKE ' + @charInTheArray + '%'
SET @sql = @sql + ' OR [MyId] LIKE ' + @nextCharInArray + '%'
EXEC (@sql)
上述行为将被称为:
EXEC uspFilterMyTable("A,C,P,X")
...或者也许是这样(如果它更容易拆分字母表):
EXEC uspFilterMyTable("ACPX")
有什么想法吗?指针?
更新好的,这就是我提出来的(从Chhatrapati Sharma借来的[Split]功能):
-- [MyTable] contains these rows: 'A7', 'A87', 'B16', 'C51', 'H99', 'X12'
-- the "input" parameter
DECLARE @prefixArray NVARCHAR(100)= 'H,A,C'
-- split the string into SQL wild-card patterns
DECLARE charCursor CURSOR FOR
select items + N'%' from dbo.Split(@prefixArray, ',')
OPEN charCursor;
DECLARE @pattern CHAR(2)
-- create temp table if necessary
IF NOT EXISTS(SELECT * FROM TEMPDB.SYS.TABLES WHERE NAME LIKE '#tmpTable%')
CREATE TABLE #tmpTable ([Id] VARCHAR(3) NOT NULL)
-- purge old data
DELETE FROM #tmpTable
FETCH NEXT FROM charCursor into @pattern
WHILE @@FETCH_STATUS = 0
BEGIN
--SELECT * INTO #tmpTable FROM [MyTable] WHERE [MyId] LIKE @pattern
Insert Into #tmpTable Select * FROM [MyTable] WHERE [MyId] LIKE @pattern
FETCH NEXT FROM charCursor into @pattern
END
CLOSE charCursor;
DEALLOCATE charCursor;
-- return the values
SELECT * FROM #tmpTable
我知道这很难看,但它有效......任何即兴创作代码的提示?
答案 0 :(得分:2)
首先你应该创建以下函数,然后在这样的查询中使用它
SELECT * FROM [MyTable] WHERE [MyId] in (select items from dbo.split(@prefixArray,','))
CREATE FUNCTION [dbo].[Split](@String varchar(8000), @Delimiter char(1))
returns @temptable TABLE (items varchar(8000))
as
begin
declare @idx int
declare @slice varchar(8000)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Items) values(@slice)
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
return
end
答案 1 :(得分:2)
这里有一个基于XML的漂亮而快速的分割方法:
DECLARE @str NVARCHAR(100)= 'A1,B3,C4,B12,K19', @separator VARCHAR(1)= ','
DECLARE @SplitedList TABLE (code NVARCHAR(30))
DECLARE @XMLList XML
SET @XMLList=CAST('<i>'+REPLACE(@str, @separator,'</i><i>')+'</i>' AS XML)
INSERT INTO @SplitedList
SELECT x.i.value('(./text())[1]','varchar(100)')
FROM @XMLList.nodes('i') x(i)
SELECT * FROM @SplitedList
结果将是一个包含分割值的表:
code
A1
B3
C4
B12
K19
从这里开始,您可以继续使用此表格,并按照您的提议使用LIKE
加入原始表格。
答案 2 :(得分:1)
我建议你使用表值参数来调用你的存储过程。我想你是从.net调用的。但我认为EF无法处理它,尽管你可能会检查它。如果没有,我认为最好的方法是首先将字符串解析为临时表或表值,然后再加入它。
TVP:
CREATE PROCEDURE [dbo].[uspFilterMyTable]
@prefixArray tvp_idlist readonly
as
select
t.*
from MyTable t
join @prefixArray pa on pa.id = t.myid
使用分割功能(根据您的选择,您可以在网上找到很多示例)
CREATE PROCEDURE [dbo].[uspFilterMyTable]
@prefixArray varchar(max)
as
create @prefixArray tvp_idlist
insert into @prefixArray (id)
select id from dbo.myCustomSplit(@prefixArray,',')
select
t.*
from MyTable t
join @prefixArray pa on pa.id = t.myid
对于两种情况,@ prefixArray是一个表变量,其中Id = varchar(3)
作为一个编辑,经过一番挖掘后,似乎只需要一点点工作,EF就可以和TVP一起使用。检查一下:Entity Framework Stored Procedure Table Value Parameter。所以最好的方法是直接将表发送到存储过程,然后发送一个字符串进行解析。