Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2005 Forums
 Transact-SQL (2005)
 How to JOIN only when needed

Author  Topic 

R
Constraint Violating Yak Guru

328 Posts

Posted - 2010-11-04 : 12:35:19
I have three tables; one is a table variable, and the other two are many-to-many tables. My query always searches @tmp, but I was wondering if it is possible to only query the other two tables when a variable is passed to query them with. Here's what I'm doing so far which should hopefully explain what I mean...


-- if no parameter values passed, then only query table variable
IF @performanceCriteriaID IS NULL AND @businessObjectiveID IS NULL
BEGIN -- search all user answers without querying many-to-many tables
SELECT
*
FROM
@tmp
ORDER BY
surname,
name
END
-- otherwise, query the many-to-many tables using the passed variables
ELSE
BEGIN -- query many-to-many table(s)
SELECT
DISTINCT(tmp.answerID),
tmp.*
FROM
@tmp tmp LEFT OUTER JOIN
[tbl_BusinessObjectives] bo ON bo.uiAnswerID = tmp.answerID LEFT OUTER JOIN -- only when needed?
[tbl_PerformanceCriteria] pc ON pc.uiAnswerID = tmp.answerID -- only when needed?
WHERE
(bo.boID = @businessObjectiveID OR @businessObjectiveID IS NULL) AND
(pc.pcID = @performanceCriteriaID OR @performanceCriteriaID IS NULL)
ORDER BY
tmp.surname,
tmp.name
END


So here's the pseudo code I'm aiming for...

1. If @performanceCriteriaID and @businessObjectiveID are null, just query @tmp
2. If @performanceCriteriaID is not null, return rows from @tmp where a related row(s) exists in [tbl_BusinessObjectives]
3. If @businessObjectiveID is not null, return rows from @tmp where a related row(s) exists in [tbl_PerformanceCriteria]
4. If 2+3 are both not null, return rows from @tmp where a related row(s) exists in [tbl_BusinessObjectives] and [tbl_PerformanceCriteria]

So I guess I'm trying to join only when required. I only return row values from @tmp to prevent duplicate @tmp rows showing when multiple related rows exist in the other table(s). Or am I wasting my time?!?

mikgri
Starting Member

39 Posts

Posted - 2010-11-09 : 10:53:36
Instead using left joins, use union and inner join with each table with proper criteria.
Go to Top of Page

R
Constraint Violating Yak Guru

328 Posts

Posted - 2010-11-09 : 11:02:39
Can you give an example please?
Go to Top of Page

webfred
Master Smack Fu Yak Hacker

8781 Posts

Posted - 2010-11-09 : 11:18:18
Better you would give table structure of
- @tmp (and maybe how the data is coming into @tmp)
- tbl_BusinessObjectives
- tbl_PerformanceCriteria

and some sample data for each table

and the wanted result set(s) in relation to sample data and in relation to the parameter values.


No, you're never too old to Yak'n'Roll if you're too young to die.
Go to Top of Page

mikgri
Starting Member

39 Posts

Posted - 2010-11-09 : 11:46:10
You can use some thing like this:
IF @performanceCriteriaID IS NULL AND @businessObjectiveID IS NULL
BEGIN -- search all user answers without querying many-to-many tables
SELECT
*
FROM
@tmp
ORDER BY
surname,
name
END
-- otherwise, query the many-to-many tables using the passed variables
ELSE
BEGIN -- query many-to-many table(s)
SELECT
DISTINCT(tmp.answerID),
tmp.*
FROM
@tmp tmp INNER JOIN [tbl_BusinessObjectives] bo ON bo.uiAnswerID = tmp.answerID and bo.boID = ISNULL(@businessObjectiveID,0)
UNION
SELECT
DISTINCT(tmp.answerID),
tmp.*
FROM
@tmp tmp INNER JOIN [tbl_PerformanceCriteria] pc ON pc.uiAnswerID = tmp.answerID AND pc.pcID = ISNULL(@performanceCriteriaID,0)
END

Go to Top of Page

mikgri
Starting Member

39 Posts

Posted - 2010-11-09 : 12:26:16
instead bo.boID = ISNULL(@businessObjectiveID,0)
you can use
bo.boID = @businessObjectiveID
where isnull(@businessObjectiveID,0)>0
depend on structure of your tables.
Go to Top of Page

R
Constraint Violating Yak Guru

328 Posts

Posted - 2010-11-09 : 12:35:34
mikgri

So are you saying the syntax would be...


INNER JOIN [tbl_BusinessObjectives] bo ON bo.uiAnswerID = tmp.answerID and bo.boID = @businessObjectiveID
where isnull(@businessObjectiveID, 0) > 0


I didn't know you could JOIN and specify WHERE on that JOIN...
Go to Top of Page

mikgri
Starting Member

39 Posts

Posted - 2010-11-09 : 14:09:44
it is a where close for select statement, here is a full query,
I don't have a sample data to check, please check it or post table structures

-- 1.If @performanceCriteriaID and @businessObjectiveID are null, just query @tmp
IF @performanceCriteriaID IS NULL AND @businessObjectiveID IS NULL
BEGIN -- search all user answers without querying many-to-many tables
SELECT
*
FROM
@tmp
ORDER BY
surname,
name
END
-- otherwise, query the many-to-many tables using the passed variables
ELSE
BEGIN -- query many-to-many table(s)
--2. If @performanceCriteriaID is not null, return rows from @tmp where a related row(s) exists in [tbl_BusinessObjectives]
SELECT
DISTINCT(tmp.answerID),
tmp.*
FROM
@tmp tmp INNER JOIN [tbl_BusinessObjectives] bo ON bo.uiAnswerID = tmp.answerID and bo.boID = @businessObjectiveID
where isnull(@businessObjectiveID,0)>0
UNION
--3. If @businessObjectiveID is not null, return rows from @tmp where a related row(s) exists in [tbl_PerformanceCriteria]
SELECT
DISTINCT(tmp.answerID),
tmp.*
FROM
@tmp tmp INNER JOIN [tbl_PerformanceCriteria] pc ON pc.uiAnswerID = tmp.answerID AND pc.pcID = @performanceCriteriaID
where ISNULL(@performanceCriteriaID,0)>0
--4. If 2+3 are both not null, return rows from @tmp where a related row(s) exists in [tbl_BusinessObjectives] and [tbl_PerformanceCriteria]
--alredy in 2
END

Go to Top of Page

Lamprey
Master Smack Fu Yak Hacker

4614 Posts

Posted - 2010-11-09 : 14:29:51
Those WHERE clauses are not needed because they don't do anything.
Go to Top of Page

namman
Constraint Violating Yak Guru

285 Posts

Posted - 2010-11-09 : 14:37:36
quote:

I have three tables; one is a table variable, and the other two are many-to-many tables. My query always searches @tmp, but I was wondering if it is possible to only query the other two tables when a variable is passed to query them with. Here's what I'm doing so far which should hopefully explain what I mean...



-- if no parameter values passed, then only query table variable
IF @performanceCriteriaID IS NULL AND @businessObjectiveID IS NULL
BEGIN -- search all user answers without querying many-to-many tables
SELECT
*
FROM
@tmp
ORDER BY
surname,
name
END
-- otherwise, query the many-to-many tables using the passed variables
ELSE
BEGIN -- query many-to-many table(s)

SELECT
DISTINCT(tmp.answerID),
tmp.*
FROM
@tmp tmp LEFT OUTER JOIN
[tbl_BusinessObjectives] bo ON bo.uiAnswerID = tmp.answerID LEFT OUTER JOIN -- only when needed?
[tbl_PerformanceCriteria] pc ON pc.uiAnswerID = tmp.answerID -- only when needed?
WHERE
(bo.boID = @businessObjectiveID OR @businessObjectiveID IS NULL) AND
(pc.pcID = @performanceCriteriaID OR @performanceCriteriaID IS NULL)
ORDER BY
tmp.surname,
tmp.name

END



So here's the pseudo code I'm aiming for...

1. If @performanceCriteriaID and @businessObjectiveID are null, just query @tmp
2. If @performanceCriteriaID is not null, return rows from @tmp where a related row(s) exists in [tbl_BusinessObjectives]
3. If @businessObjectiveID is not null, return rows from @tmp where a related row(s) exists in [tbl_PerformanceCriteria]
4. If 2+3 are both not null, return rows from @tmp where a related row(s) exists in [tbl_BusinessObjectives] and [tbl_PerformanceCriteria]

So I guess I'm trying to join only when required. I only return row values from @tmp to prevent duplicate @tmp rows showing when multiple related rows exist in the other table(s). Or am I wasting my time?!?



Hi R,
No, you are not wasting your time. You should pay more attention on your query (red part). It likely returns unexpected result.

As webfred suggested, you should create 3 sample tables with data, and then the output you want with each condition. That is easier for people to help
Go to Top of Page

R
Constraint Violating Yak Guru

328 Posts

Posted - 2010-11-10 : 03:44:59
Thanks for your feedback. As requested, here's some test data to try and illustrate what I mean.

The pseudo code logic is:

  • If the @boID and @pcID values are null, then simply select all from @tmp

  • If @boID is not null, then show all rows from @tmp where a related row exists in @businessObjectives

  • If @pcID is not null, then show all rows from @tmp where a related row exists in @performanceCriteria

  • if @boID is not null and @pcID is not null, then only show rows from @tmp where related rows exist in both @businessObjectives and @performanceCriteria


What I am trying to avoid is unneccessary use of resources (e.g. joining when a join isn't necessary). I know I could do two separate queries into a table variable and then SELECT DISTINCT (or do a SELECT UNION using the two queries), but just want to check out how other professionals approach this.

declare @tmp table
(
answerID int identity(1,1),
answerText nvarchar(max)
)

declare @businessObjectives table
(
ID int identity(1,1),
answerID int not null,
boID int not null
)

declare @performanceCriteria table
(
ID int identity(1,1),
answerID int not null,
pcID int not null
)

declare @i int
declare @lastID int
SET @i = 1
WHILE @i < 500
BEGIN
INSERT INTO @tmp (answerText) VALUES ('Placeholder text...')
SET @lastID = SCOPE_IDENTITY()
INSERT INTO @businessObjectives (answerID, boID) VALUES (@lastID, (SELECT CAST(RAND() * 10 AS INT)))
INSERT INTO @businessObjectives (answerID, boID) VALUES (@lastID, (SELECT CAST(RAND() * 10 AS INT)))
INSERT INTO @performanceCriteria (answerID, pcID) VALUES (@lastID, (SELECT CAST(RAND() * 10 AS INT)))
INSERT INTO @performanceCriteria (answerID, pcID) VALUES (@lastID, (SELECT CAST(RAND() * 10 AS INT)))
SET @i = @i + 1
END

-- perform selects -----------------------------
declare @boID int
declare @pcID int
SET @boID = 5
--SET @pcID = 3

IF @boID IS NULL AND @pcID IS NULL
BEGIN
SELECT * FROM @tmp ORDER BY answerID
END
ELSE
BEGIN
SELECT
DISTINCT(tmp.answerID),
tmp.*,
bo.boID,
pc.pcID
FROM
@tmp tmp LEFT OUTER JOIN
@businessObjectives bo ON bo.answerID = tmp.answerID LEFT OUTER JOIN -- Unnecessary join when @boID IS NULL!
@performanceCriteria pc ON pc.answerID = tmp.answerID -- Unnecessary join when @pcID IS NULL!

WHERE
(bo.boID = @boID OR @boID IS NULL) AND
(pc.pcID = @pcID OR @pcID IS NULL)
ORDER BY
tmp.answerID
END
Go to Top of Page

mikgri
Starting Member

39 Posts

Posted - 2010-11-10 : 10:07:48
Still not sure if it is a result set(s) you wanted, just onother idea:

IF @boID IS NULL AND @pcID IS NULL
BEGIN
SELECT * FROM tmp ORDER BY answerID
END
ELSE
BEGIN
--If @boID is not null, then show all rows from @tmp where a related row exists in @businessObjectives
if @boID is not null and @pcID is null
begin
SELECT
DISTINCT(tmp.answerID),
tmp.*,
bo.boID
FROM
tmp tmp INNER JOIN
businessObjectives bo ON bo.answerID = tmp.answerID and bo.boID=@boID
end
else
--If @pcID is not null, then show all rows from @tmp where a related row exists in @performanceCriteria
if @boID is null and @pcID is not null
begin
SELECT
DISTINCT(tmp.answerID),
tmp.*,
pc.pcID
FROM
tmp tmp INNER JOIN
performanceCriteria pc ON pc.answerID = tmp.answerID and pc.pcID=@pcID
end
else
--if @boID is not null and @pcID is not null, then only show rows from @tmp where related rows exist in both @businessObjectives and @performanceCriteria
if @boID is not null and @pcID is not null
begin
SELECT
DISTINCT(tmp.answerID),
tmp.*,
bo.boid,
pc.pcID
FROM
tmp tmp INNER JOIN
businessObjectives bo ON bo.answerID = tmp.answerID and bo.boID=@boID
inner join performanceCriteria pc ON pc.answerID = tmp.answerID and pc.pcID=@pcID
end
END
Go to Top of Page

R
Constraint Violating Yak Guru

328 Posts

Posted - 2010-11-10 : 10:32:26
Hi mikgri

Thanks for that. Yes, that is the approach I would have opted for should there not be a neater way. It just seems a lot of code doesn't it, and I'd need a seperate logic block for each new variable introduced into the WHERE clause?!? That's the reason for the post anyway; to see if JOINs could be done in a smarter way...!
Go to Top of Page
   

- Advertisement -