SQL Сохраненная процедура LIKE

Это простой вопрос, и я не могу представить себе решение.

У меня это определено в моей хранимой процедуре:

@communityDesc varchar(255) = NULL

@communityDesc - это "aaa, bbb, ccc"

и в моем фактическом запросе я пытаюсь использовать IN

WHERE AREA IN (@communityDesc)

но это не сработает, потому что мои запятые находятся внутри строки вместо таких, как "aaa", "bbb", "ccc"

Итак, мой вопрос: есть ли что-нибудь, что я могу сделать для @communityDesc, поэтому он будет работать с моей инструкцией IN, например, форматировать строку?

Ответ 1

сначала вы больше всего создаете функцию для разделения строки, например, такой код

CREATE FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) )
RETURNS
 @returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN

 DECLARE @name NVARCHAR(255)
 DECLARE @pos INT

 WHILE CHARINDEX(',', @stringToSplit) > 0
 BEGIN
  SELECT @pos  = CHARINDEX(',', @stringToSplit)  
  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)[email protected])
 END

 INSERT INTO @returnList
 SELECT @stringToSplit

 RETURN
END

то вы можете использовать эту функцию, например, ваш запрос

WHERE AREA IN (dbo.splitstring(@communityDesc))

Ответ 2

Эта статья может помочь вам в вашей проблеме:

http://sqlperformance.com/2012/07/t-sql-queries/split-strings

В этой статье Аарон Бертран пишет о вашей проблеме. Это действительно длинный и очень подробный.

Один из способов:

CREATE FUNCTION dbo.SplitStrings_XML
(
   @List       NVARCHAR(MAX),
   @Delimiter  NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
   RETURN 
   (  
      SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
      FROM 
      ( 
        SELECT x = CONVERT(XML, '<i>' 
          + REPLACE(@List, @Delimiter, '</i><i>') 
          + '</i>').query('.')
      ) AS a CROSS APPLY x.nodes('i') AS y(i)
   );
GO

С помощью этой функции вы вызываете только:

WHERE AREA IN (SELECT Item FROM dbo.SplitStrings_XML(@communityDesc, N','))

Надеюсь, это поможет вам.

Ответ 3

Самый простой способ использования этой переменной:

SELECT * 
FROM something
WHERE ',' + @communityDesc + ',' Like '%,' + AREA + ',%'

это для tsql, для использования оракула || для объединения строк

Ответ 4

In работает только с наборами значений, а не с символами в строке. Чтобы технически ответить на ваш вопрос, единственный способ сделать это - создать набор значений, представляющих три значения: "aaa", "bbb" и "ccc", а затем поместить эти три значения в таблицу (таблица или таблица Temp переменной (в SQL Server), а затем выполнить IN против этого набора значений (в таблице:

declare @Vals table (value varchar(20))
insert @vals(Value) Values('aaa')
insert @vals(Value) Values('bbb')
insert @vals(Value) Values('ccc')

select * from SomeOtherTable 
Where SomeColumn IN (Select value from @vals)

Чтобы создать набор, вам нужно создать пустую таблицу temp или таблицу для хранения этого набора значений, проанализировать строку с разделителями-запятыми в отдельные значения и ввести эти отдельные значения в таблицу temp или табличную переменную.

хотя вы не говорите, что если вы используете SQL Server, следующая функция определяется пользователем SQL Server (UDF), которая будет анализировать строку с разделителями и возвращать таблицу с одной строкой для каждого разделительного значения:

если вы создаете UDF, вы будете использовать его следующим образом:

select * from SomeOtherTable 
Where SomeColumn IN 
        (Select sVal from
          dbo.ParseSTring(@communityDesc, ','))

/****** Object:  UserDefinedFunction [dbo].[ParseString]    
    Script Date:      4/8/2016 1:53:00 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[ParseString] (@S Text, @delim VarChar(5))
Returns @tOut Table 
(ValNum Integer Identity Primary Key, 
 sVal VarChar(8000))
As
Begin 
Declare @dLLen TinyInt  -- Length of delimiter
Declare @sWin  VarChar(8000)-- Will Contain Window into text string
Declare @wLen  Integer  -- Length of Window
Declare @wLast TinyInt  -- Boolean to indicate processing Last Window
Declare @wPos  Integer  -- Start Position of Window within Text String
Declare @sVal  VarChar(8000)-- String Data to insert into output Table
Declare @BtchSiz Integer    -- Maximum Size of Window
Set @BtchSiz = 7900 -- (Reset to smaller values to test routine)
Declare @dPos Integer   -- Position within Window of next Delimiter
Declare @Strt Integer   -- Start Position of each data value in Window
-- --------------------------------------------------------------

-- ---------------------------
If @delim is Null Set @delim = '|'
If DataLength(@S) = 0 Or
    Substring(@S, 1, @BtchSiz) = @delim Return
-- ---------------------------
Select @dLLen = Len(@delim),
    @Strt = 1, @wPos = 1,
    @sWin = Substring(@S, 1, @BtchSiz)
Select @wLen = Len(@sWin),
      @wLast = Case When Len(@sWin) = @BtchSiz
                Then 0 Else 1 End,
      @dPos = CharIndex(@delim, @sWin, @Strt)
-- ----------------------------
While @Strt <= @wLen
  Begin
    If @dPos = 0 Begin    -- No More delimiters in window
        If @wLast = 1 Set @dPos = @wLen + 1 
        Else Begin
            Set @wPos = @wPos + @Strt - 1
            Set @sWin = Substring(@S, @wPos, @BtchSiz)
                -- -------------------------------------
            Select @wLen = Len(@sWin), @Strt = 1,
            @wLast = Case When Len(@sWin) = @BtchSiz
                Then 0 Else 1 End, 
                                      @dPos = CharIndex(@delim, @sWin, 1)
            If @dPos = 0 Set @dPos = @wLen + 1 
            End
        End
        -- -------------------------------
    Set @sVal = LTrim(Substring(@sWin, @Strt, @dPos - @Strt))
    Insert @tOut (sVal) Values (@sVal)
    -- -------------------------------
    -- Move @Strt to char after last delimiter
    Set @Strt = @dPos + @dLLen 
    Set @dPos = CharIndex(@delim, @sWin, @Strt)
    End
Return
 End

Ответ 5

Вы можете сделать это, разделив строку, используя функцию разделения здесь. Функция возвращает таблицу, содержащую один столбец, который содержит ваши токены (т.е. "Aaa", "bbb"...).

Ваш запрос должен выглядеть следующим образом:

-- get the splits
SELECT Name INTO #someTemp
FROM dbo.splitstring(@communityDesc)

-- get data where area in within description
SELECT 1
FROM yourTable T
WHERE EXISTS (SELECT 1 FROM #someTemp tmp WHERE T.Area = tmp.Name)  

Ответ 6

Другой подход - использовать CHARINDEX(). Однако использование функции в предложении WHERE приведет к замедлению производительности.

WHERE CHARINDEX(','+area+',',','[email protected]+',')> 0

Если поле области равно 3 буквам, вы можете упростить это.

WHERE CHARINDEX(area,@CommunityDec)> 0

Это быстрое решение, но также и разрыв остановки. Лучшее решение - изменить подход поиска строк, чтобы построить таблицу с одной строкой для каждого критерия поиска и использовать JOIN или sub-запрос.

Ответ 7

Вы можете просто разбить этот csv с помощью XML и использовать его для фильтрации в вашем запросе. Нет необходимости использовать определенную пользователем функцию или @Table_Valiable или #Temp_Table здесь.

DECLARE @xml as xml,@communityDesc varchar(255) = 'aaa,bbb,ccc'

SET @xml = cast(('<X>'+replace(@communityDesc,',' ,'</X><X>')+'</X>') as xml)

SELECT * FROM TABLE1
WHERE AREA IN (
    SELECT N.value('.', 'varchar(10)') as value FROM @xml.nodes('X') as T(N)
) 

Если вам нужны эти значения разделения в дальнейшем процессе, вы можете вставить это в #table_Variable или #Temp_Table и использовать их.