简体   繁体   中英

SQL JOIN only when a condition is true

I have 3 variables in my SQL stored procedure and want to add a join only if the 3rd variable is not null.

This is how i am trying to do it but it doesn't work. It gives the following error on the line pointed out:

Incorrect syntax near '{'

ALTER PROCEDURE [dbo].[Search] 
@one NVARCHAR(50), @two NVARCHAR(50), @three NVARCHAR(50)

SELECT  cinfo.ID,
    cinfo.Nam,
    cinfo.INAM,
    cinfo.CA,
    cinfo.Form,
    cinfo.Std,
    cval.Prop,
    cval.Cons,
    sc.Accep

From dbo.Info AS cinfo
Inner JOIN dbo.values AS cval
    ON cinfo.ID = cval.ID
INNER JOIN dbo.Sources AS sc
    ON (cval.sID = sc.sID AND sc.Accept = 'A')
IF @three IS NOT NULL{               **<---------------------**
LEFT JOIN dbo.Synonym AS synm
    ON cinfo.ID = synm.ID}

where (cinfo.NAM LIKE '%'+@one+'%' OR cinfo.CAS LIKE '%'+@two+'%' OR 
  synm.SynonymID LIKE '%'+@three+'%') AND
    (cval.PropID = '1' OR
    cval.PropID = '2' OR
    cval.PropID = '3' OR
    cval.PropID = '4' OR)

Couldn't you just use an and on the join? The join will be attempted but if @three is null then no joins to synonym would occur.... or do you really need to ignore the join for performance reasons? if so Dynamic SQL is the only way I could see to make it work...

ALTER PROCEDURE [dbo].[Search] 
@one NVARCHAR(50), @two NVARCHAR(50), @three NVARCHAR(50)

SELECT  cinfo.ID,
    cinfo.Nam,
    cinfo.INAM,
    cinfo.CA,
    cinfo.Form,
    cinfo.Std,
    cval.Prop,
    cval.Cons,
    sc.Accep

From dbo.Info AS cinfo
Inner JOIN dbo.values AS cval
    ON cinfo.ID = cval.ID
INNER JOIN dbo.Sources AS sc
    ON (cval.sID = sc.sID AND sc.Accept = 'A')
LEFT JOIN dbo.Synonym AS synm
    ON cinfo.ID = synm.ID
   and @three IS NOT NULL               **<---------------------**

where (cinfo.NAM LIKE '%'+@one+'%' OR cinfo.CAS LIKE '%'+@two+'%' OR 
  synm.SynonymID LIKE '%'+@three+'%') AND
    (cval.PropID = '1' OR
    cval.PropID = '2' OR
    cval.PropID = '3' OR
    cval.PropID = '4' OR)

This is not correct syntax, but you could do achieve this in few ways, the dumbest way to do is add the Boolean check on the top.

IF @three IS NOT NULL
BEGIN
--FULL QUERY that JOIN dbo.Synonym 
END 

IF @Three IS NULL
BEGIN
--FULL QUERY that does not JOIN dbo.Synonym 
END

Or you could use case..when to control, it does the same thing as multiple if

You need to give that condition while joining itself.

ALTER PROCEDURE [dbo].[Search] 
@one NVARCHAR(50), @two NVARCHAR(50), @three NVARCHAR(50)

SELECT  cinfo.ID,
    cinfo.Nam,
    cinfo.INAM,
    cinfo.CA,
    cinfo.Form,
    cinfo.Std,
    cval.Prop,
    cval.Cons,
    sc.Accep

From dbo.Info AS cinfo
Inner JOIN dbo.values AS cval
    ON cinfo.ID = cval.ID
INNER JOIN dbo.Sources AS sc
    ON (cval.sID = sc.sID AND sc.Accept = 'A')
       LEFT JOIN dbo.Synonym AS synm
    ON (cinfo.ID = synm.ID and @three is not null) **<---------------------**

where (cinfo.NAM LIKE '%'+@one+'%' OR cinfo.CAS LIKE '%'+@two+'%' OR 
  synm.SynonymID LIKE '%'+@three+'%') AND
    (cval.PropID = '1' OR
    cval.PropID = '2' OR
    cval.PropID = '3' OR
    cval.PropID = '4' OR)

You can achieve this by building dynamic query like following

ALTER PROCEDURE [dbo].[Search] 
@one NVARCHAR(50), @two NVARCHAR(50), @three NVARCHAR(50)

DECLARE @query varchar(2000)=' SELECT  cinfo.ID,
    cinfo.Nam,
    cinfo.INAM,
    cinfo.CA,
    cinfo.Form,
    cinfo.Std,
    cval.Prop,
    cval.Cons,
    sc.Accep

From dbo.Info AS cinfo Inner JOIN dbo.values AS cval ON cinfo.ID = cval.ID
INNER JOIN dbo.Sources AS sc ON (cval.sID = sc.sID AND sc.Accept = ''A'')'

IF @three IS NOT NULL
BEGIN
   SET @query = @query + ' LEFT JOIN dbo.Synonym AS synm ON cinfo.ID = synm.ID '
END

SET @query = @query + 'where (cinfo.NAM LIKE ''%' + @one + '%'' OR cinfo.CAS LIKE ''%' + @two + '%'' OR 
  synm.SynonymID LIKE ''%' + @three + '%'') AND
    (cval.PropID = ''1'' OR
    cval.PropID = ''2'' OR
    cval.PropID = ''3'' OR
    cval.PropID = ''4'')'

EXEC(@query)

What about:

ALTER PROCEDURE [dbo].[Search] 
@one NVARCHAR(50), @two NVARCHAR(50), @three NVARCHAR(50)

SELECT  cinfo.ID,
    cinfo.Nam,
    cinfo.INAM,
    cinfo.CA,
    cinfo.Form,
    cinfo.Std,
    cval.Prop,
    cval.Cons,
    sc.Accep

From dbo.Info AS cinfo
Inner JOIN dbo.values AS cval
    ON cinfo.ID = cval.ID
INNER JOIN dbo.Sources AS sc
    ON (cval.sID = sc.sID AND sc.Accept = 'A')
LEFT JOIN dbo.Synonym AS synm
    ON (cinfo.ID = synm.ID AND @three IS NOT NULL)

where (cinfo.NAM LIKE '%'+@one+'%' OR cinfo.CAS LIKE '%'+@two+'%' OR 
  synm.SynonymID LIKE '%'+@three+'%') AND
    (cval.PropID = '1' OR
    cval.PropID = '2' OR
    cval.PropID = '3' OR
    cval.PropID = '4' OR)

replace IF @three with this :

 LEFT JOIN (select * from dbo.Synonym  where @three IS NOT NULL) as synm ON cinfo.ID = synm.ID

and verify ALTER procedure syntax and LIKE syntax.

You cannot use { for if condition just remove '{'

ALTER PROCEDURE [dbo].[Search] 
@one NVARCHAR(50), @two NVARCHAR(50), @three NVARCHAR(50)

SELECT  cinfo.ID,
    cinfo.Nam,
    cinfo.INAM,
    cinfo.CA,
    cinfo.Form,
    cinfo.Std,
    cval.Prop,
    cval.Cons,
    sc.Accep

From dbo.Info AS cinfo
Inner JOIN dbo.values AS cval
    ON cinfo.ID = cval.ID
INNER JOIN dbo.Sources AS sc
    ON (cval.sID = sc.sID AND sc.Accept = 'A')
**IF @three IS NOT NULL**           Remove this line
LEFT JOIN dbo.Synonym AS synm
    ON cinfo.ID = synm.ID}

where (cinfo.NAM LIKE '%'+@one+'%' OR cinfo.CAS LIKE '%'+@two+'%' OR 
  synm.SynonymID LIKE '%'+@three+'%') AND
    (cval.PropID = '1' OR
    cval.PropID = '2' OR
    cval.PropID = '3' OR
    cval.PropID = '4' OR)

Try to write Like IF @three IS NOT NULL ALTER PROCEDURE [dbo].[Search] @one NVARCHAR(50), @two NVARCHAR(50), @three NVARCHAR(50)

SELECT  cinfo.ID,
    cinfo.Nam,
    cinfo.INAM,
    cinfo.CA,
    cinfo.Form,
    cinfo.Std,
    cval.Prop,
    cval.Cons,
    sc.Accep

From dbo.Info AS cinfo
Inner JOIN dbo.values AS cval
    ON cinfo.ID = cval.ID
INNER JOIN dbo.Sources AS sc
    ON (cval.sID = sc.sID AND sc.Accept = 'A')

where (cinfo.NAM LIKE '%'+@one+'%' OR cinfo.CAS LIKE '%'+@two+'%' OR 
  synm.SynonymID LIKE '%'+@three+'%') AND
    (cval.PropID = '1' OR
    cval.PropID = '2' OR
    cval.PropID = '3' OR
    cval.PropID = '4' OR)

end else ALTER PROCEDURE [dbo].[Search] @one NVARCHAR(50), @two NVARCHAR(50), @three NVARCHAR(50)

SELECT  cinfo.ID,
    cinfo.Nam,
    cinfo.INAM,
    cinfo.CA,
    cinfo.Form,
    cinfo.Std,
    cval.Prop,
    cval.Cons,
    sc.Accep

From dbo.Info AS cinfo
Inner JOIN dbo.values AS cval
    ON cinfo.ID = cval.ID
INNER JOIN dbo.Sources AS sc
    ON (cval.sID = sc.sID AND sc.Accept = 'A')
LEFT JOIN dbo.Synonym AS synm
    ON cinfo.ID = synm.ID}

where (cinfo.NAM LIKE '%'+@one+'%' OR cinfo.CAS LIKE '%'+@two+'%' OR 
  synm.SynonymID LIKE '%'+@three+'%') AND
    (cval.PropID = '1' OR
    cval.PropID = '2' OR
    cval.PropID = '3' OR
    cval.PropID = '4' OR).. rest code

end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM