1

假设我有一个包含 varchar 字段的表:

CREATE TABLE [MyTable] (
    [MyId]    varchar(3)    NOT NULL,
    .....
)

[ MyId]列包含连续的字母数字值,如 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    

我知道这很难看,但它确实有效……有什么技巧可以即兴编写代码吗?

4

3 回答 3

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 
于 2012-09-20T06:53:41.873 回答
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

于 2012-09-20T07:03:47.103 回答
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 配合使用。检查这个:实体框架存储过程表值参数。所以最好的办法是直接发送一个表到你的存储过程,然后发送一个字符串来解析。

于 2012-09-20T06:59:31.510 回答