如何为以下编写动态SQL?

时间:2015-07-03 01:44:57

标签: sql sql-server tsql

1)我有这样的字符串:

vagalla AND suresh NOT employee OR industry

我想要的结果如下:

Name like '%vagalla%' and Name like '%suresh%' and not (Name like '%employee%' or description like '%industry4%')

2)我有这样的字符串:

vagalla OR suresh AND employee OR industry

我想要的结果如下:

(Name like '%vagalla%' or Name like '%suresh%' ) and (Name like '%employee%' or Name like '%industry%')

这是功能:

ALTER FUNCTION DBO.BOOLEANSEARCH(@SEARCHNME VARCHAR(50))                
RETURNS VARCHAR(MAX)                
AS              
-- SELECT  DBO.GETBOOLEANSEARCH ('VAGALLA SURESH')              
BEGIN               
DECLARE @QRY VARCHAR(MAX)               
DECLARE @SEARCHSTRING VARCHAR(50)               
DECLARE @START INT              
DECLARE @END INT            
SET @SEARCHSTRING = REPLACE(REPLACE(@SEARCHNME,'+' COLLATE LATIN1_GENERAL_CS_AI,'AND' ),'-' COLLATE LATIN1_GENERAL_CS_AI,'OR')              
SELECT @START = CHARINDEX('"',@SEARCHSTRING), @END = CHARINDEX('"',REVERSE(@SEARCHSTRING))              
IF( @START = 1 AND @END = 1)                
BEGIN               
     SELECT @QRY =' COLUMNNAME = '+ SUBSTRING(@SEARCHSTRING,2,LEN(@SEARCHSTRING)-2)         
END             
ELSE                
BEGIN               
    IF  (   ((1>(SELECT PATINDEX('% OR %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI)))    
            OR (1>(SELECT PATINDEX('% AND %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI))) 
            OR (1>(SELECT PATINDEX('% NOT %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI))) 
            ) AND ((SELECT CHARINDEX('*' COLLATE LATIN1_GENERAL_CS_AI,@SEARCHSTRING))>1))   
        BEGIN       
            SELECT @QRY= ' COLUMNNAME LIKE '+  REPLACE(@SEARCHSTRING,'*', '%' ) 
        END 
        ELSE IF (   ((1>(SELECT PATINDEX('% OR %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI)))    
            OR (1>(SELECT PATINDEX('% AND %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI))) 
            OR (1>(SELECT PATINDEX('% NOT %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI))) 
            ) AND ((SELECT CHARINDEX('*' COLLATE LATIN1_GENERAL_CS_AI,@SEARCHSTRING))<1))   
        BEGIN       
            SELECT @QRY= ' COLUMNNAME = ' + @SEARCHSTRING   
        END     
    ELSE            
    BEGIN           
        IF(1<(SELECT PATINDEX('% OR %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI)))       
        BEGIN       
            SELECT @QRY =' COLUMNNAME LIKE %'+SUBSTRING(@SEARCHSTRING,1, PATINDEX('% OR %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI)-1) +'%' 
                +' OR COLUMNNAME LIKE %'+ SUBSTRING(@SEARCHSTRING, PATINDEX('% OR %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI)+3,LEN(@SEARCHSTRING))+'%'
        END     
    ELSE IF(1<(SELECT PATINDEX('% AND %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI)))     
        BEGIN       
            SELECT @QRY =' COLUMNNAME LIKE %'+SUBSTRING(@SEARCHSTRING,1, PATINDEX('% AND %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI)-1) +'%'    
                +' AND COLUMNNAME LIKE %'+ SUBSTRING(@SEARCHSTRING, PATINDEX('% AND %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI)+4,LEN(@SEARCHSTRING))+'%'
        END     
ELSE IF(1<(SELECT PATINDEX('% NOT %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI)))     
        BEGIN       
            SELECT @QRY =' COLUMNNAME LIKE %'+SUBSTRING(@SEARCHSTRING,1, PATINDEX('% NOT %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI)-1) +'%'    
                +' AND COLUMNNAME NOT LIKE %'+ SUBSTRING(@SEARCHSTRING, PATINDEX('% NOT %', @SEARCHSTRING COLLATE LATIN1_GENERAL_CS_AI)+4,LEN(@SEARCHSTRING))+'%'
        END     
---HERE I NEED TO IMPLEMENT THE OTHER CONDITION
    END         
END             
RETURN @QRY             

END             

1 个答案:

答案 0 :(得分:0)

运算符的优先级在您的示例中不清楚,因此我建议您更改规范以将括号放在输入字符串中。如果您有明确定义的优先级,我们可以在处理下一步之前使用一些代码添加括号。在那之前,你可以使用这样的东西:

DECLARE @Input VARCHAR(100)
SET @Input='(vagalla AND suresh) AND NOT (employee OR industry)'
--SET @Input='(vagalla OR suresh) AND (employee OR industry)'

DECLARE @Result VARCHAR(MAX)
DECLARE @Pos INT=0, @Prev INT, @Separator CHAR(1), @Word VARCHAR(100), @Replacement VARCHAR(350)
WHILE 1=1 BEGIN
    SET @Prev=@Pos+1
    DECLARE @Pos1 INT, @Pos2 INT, @Pos3 INT
    SET @Pos1=ISNULL(NULLIF(CHARINDEX(' ',@Input,@Pos+1),0),LEN(@Input)+1)
    SET @Pos2=ISNULL(NULLIF(CHARINDEX('(',@Input,@Pos+1),0),LEN(@Input)+1)
    SET @Pos3=ISNULL(NULLIF(CHARINDEX(')',@Input,@Pos+1),0),LEN(@Input)+1)
    SET @Pos=CASE 
        WHEN @Pos1<=@Pos2 AND @Pos1<=@Pos3 THEN @Pos1 
        WHEN @Pos2<=@Pos1 AND @Pos2<=@Pos3 THEN @Pos2
        ELSE @Pos3
    END
    IF @Pos=LEN(@Input)+1 SET @Pos=0
    SET @Separator=SUBSTRING(@Input,NULLIF(@Pos,0),1)
    SET @Word=SUBSTRING(@Input,@Prev,ISNULL(NULLIF(@Pos,0)-1,LEN(@Input))-@Prev+1)
    SET @Replacement=CASE 
        WHEN @Word IN ('AND','NOT','OR','') THEN @Word 
        ELSE 'Name LIKE ''%'+REPLACE(REPLACE(REPLACE(@Word,'''',''''''),'_','[_]'),'%','[%]')+'%''' 
    END
    SET @Result=ISNULL(@Result,'')+@Replacement+ISNULL(@Separator,'')
    --SELECT @Pos, @Separator, @Word, @Replacement, @Result
    IF @Pos=0 BREAK
END

PRINT 'Input : '+@Input
PRINT 'Result: '+@Result

代码迭代搜索每个单词,考虑以下分隔符:空格,左括号,右括号。然后用LIKE表达式替换每个单词(AND,OR和NOT除外)。

在动态SQL中使用LIKE时,必须注意特殊字符,如撇号,百分比和下划线。我试图逃避那些使用REPLACE的东西,但在这种情况下正确定义字符串的长度非常重要。