SQL Query to do an INNER JOIN based on 3 different tables - sql

Initially, let me describe what I want my query to return. I want this query to return all of the records from the Address table which have an AddressTypeLookupID of either 3 or 5, which is set in the AddressType table. Second, as a further restriction, this must also include only companies with IndustryTypeID = 56, which is set in the IndustryType table. All records in the Address, AddressType, and IndustryType tables are linked by ID.
SELECT B.AddressTypeLookupID, A.Address1, A.Address2, A.City, A.State, A.Zip, A.ID
FROM Company.dbo.Address A
INNER JOIN Company.dbo.AddressType B ON A.AddressID = B.AddressID
WHERE B.Status = 'Active' AND
B.AddressTypeLookupID = 3 AND
A.AddressID = (SELECT MAX(Z.AddressID)
FROM Company.dbo.Address Z
INNER JOIN Company.dbo.AddressType X ON Z.AddressID = X.AddressID
WHERE B.Status = 'Active'
AND B.AddressTypeLookupID = 3
AND Z.ID = A.ID
)
INNER JOIN COMPANY.dbo.IndustryTypeCompanyName g ON g.ID = A.ID
WHERE g.IndustryTypeID = 56
UNION ALL
SELECT B.AddressTypeLookupID, A.Address1, A.Address2, A.City, A.State, A.Zip, A.ID
FROM Company.dbo.Address A
INNER JOIN Company.dbo.AddressType B ON A.AddressID = B.AddressID
WHERE B.Status = 'Active' AND
B.AddressTypeLookupID = 5 AND
A.AddressID = (SELECT MAX(Z.AddressID)
FROM Company.dbo.Address Z
INNER JOIN Company.dbo.AddressType X ON Z.AddressID = X.AddressID
WHERE B.Status = 'Active' AND
B.AddressTypeLookupID = 5 AND
Z.ID = A.ID
)
INNER JOIN COMPANY.dbo.IndustryTypeCompanyName j ON j.ID = A.ID
WHERE j.IndustryTypeID = 56
My issue is, I believe, with the inner joins called 'g' and 'j' above, where I try to restrict the query by IndustryTypeID = 56. The query works properly (as desired) without these lines. I am simply having trouble restricting the (full) query by IndustryTypeID to be 56. I either am wrong in my logic, am or I simply not understanding SQL syntax. I am using Microsoft SQL Management Studio 2008.

I'm not sure what the last join is supposed to mean, but as far as I can tell your query can be simplified to:
SELECT B.AddressTypeLookupID, A.Address1, A.Address2, A.City, A.State, A.Zip, A.ID
FROM Company.dbo.Address A
JOIN Company.dbo.AddressType B
ON A.AddressID = B.AddressID
JOIN COMPANY.dbo.IndustryTypeCompanyName g
ON g.ID = A.ID
WHERE B.Status = 'Active'
AND B.AddressTypeLookupID in (3,5)
AND A.AddressID = ( SELECT MAX(Z.AddressID)
FROM Company.dbo.Address Z
JOIN Company.dbo.AddressType X
ON Z.AddressID = X.AddressID
WHERE
-- redundant predicates removed
-- B.Status = 'Active'
-- AND B.AddressTypeLookupID = 3
-- AND
Z.ID = A.ID
)
AND g.IndustryTypeID = 56

I see the issue now that we know it is a syntax error. You have an inner join, a where, then another inner join, then another where. Each group can only occur once in the requried order, but you can use the keyword join more than once. So select, from, join, join where.
SELECT B.AddressTypeLookupID, A.Address1, A.Address2, A.City, A.State, A.Zip, A.ID
FROM Company.dbo.Address A
INNER JOIN Company.dbo.AddressType B
ON A.AddressID = B.AddressID
INNER JOIN COMPANY.dbo.IndustryTypeCompanyName g
ON g.ID = A.ID
WHERE B.Status = 'Active'
AND B.AddressTypeLookupID = 3
AND A.AddressID =
(SELECT MAX(Z.AddressID)
FROM Company.dbo.Address Z
INNER JOIN Company.dbo.AddressType X
ON Z.AddressID = X.AddressID
WHERE B.Status = 'Active'
AND B.AddressTypeLookupID = 3
AND Z.ID = A.ID
)
AND g.IndustryTypeID = 56

Since your already including the address table in your select rather than selecting max it would be easier to just use ROW_NUMBER() to solve your 1 per group problem
With cte as
(
SELECT B.addresstypelookupid,
A.address1,
A.address2,
A.city,
A.state,
A.zip,
A.id ,
ROW_NUMBER() OVER (Partition BY b.addresstypelookupid
order by addressid desc ) rn
FROM company.dbo.address A
INNER JOIN company.dbo.addresstype B
ON A.addressid = B.addressid
AND B.addresstypelookupid IN ( 3, 5 )
AND B.status = 'Active'
INNER JOIN company.dbo.industrytypecompanyname g
ON g.id = A.id
WHERE g.industrytypeid = 56
)
SELECT * FROM CTE WHERE Rn = 1

Related

How can I join these select statements into a single query?

I have the following select statements below that each have their own inner join to another table based on the same client_id. How can I combine these into a single query? The fact that each already relies on a inner join to a different table is what is giving me trouble.
The desired results are to have all the columns from each SELECT statement output from a single query based on the one client_id.
DECLARE client_id INT
SET client_id = {placeholder}
SELECT
N.first_name,
N.middle_name,
N.last_name
FROM Name N WITH(NOLOCK)
LEFT OUTER JOIN NameLink C WITH(NOLOCK)
ON N.name_id = C.name_id
WHERE C.client_id = #client_id
SELECT
A.street_name,
A.house_num,
A.city,
A.state_id,
A.zip,
S.state
FROM Address A
INNER JOIN AddressLink C
ON A.address_id = C.address_id
INNER JOIN State S
ON A.state_id = S.state_id
WHERE C.client_id = #client_id
SELECT
E.email
FROM Email E
INNER JOIN EmailLink C
ON E.email_id = C.email_id
WHERE C.client_id = #client_id
SELECT
P.phone_num
FROM Phone P
INNER JOIN PhoneLink C
ON P.phone_id = C.phone_id
WHERE C.client_id = #client_id
When you need to JOIN the output for 2 queries you'd use
WITH
cte1 AS ( { query 1 } ),
cte2 AS ( { query 2 } )
SELECT {columns list}
FROM cte1
JOIN cte2 ON { joining condition }
{ WHERE, GROUP BY and so on }
Use multiple CTE's, be sure to SELECT the client_id in each one then use the client_id for each CTE in a JOIN statement outside of the CTE:
DECLARE client_id INT
SET client_id = {placeholder}
WITH cteA AS (
SELECT
N.first_name,
N.middle_name,
N.last_name,
C.client_id
FROM Name N WITH(NOLOCK)
LEFT OUTER JOIN NameLink C WITH(NOLOCK)
ON N.name_id = C.name_id
WHERE C.client_id = #client_id
), cteB AS (
SELECT
A.street_name,
A.house_num,
A.city,
A.state_id,
A.zip,
S.state,
C.client_id
FROM Address A
INNER JOIN AddressLink C
ON A.address_id = C.address_id
INNER JOIN State S
ON A.state_id = S.state_id
WHERE C.client_id = #client_id
), cteC AS (
SELECT
E.email,
C.client_id
FROM Email E
INNER JOIN EmailLink C
ON E.email_id = C.email_id
WHERE C.client_id = #client_id
), cteD AS (
SELECT
P.phone_num,
C.client_id
FROM Phone P
INNER JOIN PhoneLink C
ON P.phone_id = C.phone_id
WHERE C.client_id = #client_id
)
SELECT
cteA.first_name,
cteA.middle_name,
cteA.last_name,
cteB.street_name,
cteB.house_num,
cteB.city,
cteB.state_id,
cteB.zip,
cteB.state,
cteC.email,
cteD.phone_num
FROM cteA
LEFT JOIN cteB ON cteA.client_id = cteB.client_id
LEFT JOIN cteC ON cteA.client_id = cteC.client_id
LEFT JOIN cteD ON cteA.client_id = cteD.client_id

SQL server alternative of OR in where condition

SELECT DISTINCT c.ID FROM tbl_Case c INNER JOIN
tbl_RequestBaseRequest b ON CaseId = c.ID
WHERE AreCalculationsCompleted = 0
AND b.IsApplicantRequest = 1
and c.IsArchived=0
AND (b.ID IN (SELECT DISTINCT ClientRequestId FROM tbl_Response)
OR b.OldClientRequestId IN (SELECT DISTINCT ClientRequestId FROM tbl_Response))
What should be the alternative of OR, this OR is making this query
really slow.
SELECT DISTINCT c.ID FROM tbl_Case c
INNER JOIN tbl_RequestBaseRequest b ON CaseId = c.ID
WHERE AreCalculationsCompleted = 0
AND b.IsApplicantRequest = 1
and c.IsArchived=0
AND exists (SELECT 1 FROM tbl_Response t
WHERE t.ClientRequestId = b.ID OR t.ClientRequestId = b.OldClientRequestId
)
You might try removing the distinct and being sure you have an index on tbl_Response(ClientRequestId):
SELECT DISTINCT c.ID
FROM tbl_Case c INNER JOIN
tbl_RequestBaseRequest b
ON CaseId = c.ID
WHERE AreCalculationsCompleted = 0 AND
b.IsApplicantRequest = 1 and
c.IsArchived = 0 AND
(b.ID IN (SELECT ClientRequestId FROM tbl_Response) OR
b.OldClientRequestId IN (SELECT ClientRequestId FROM tbl_Response)
);
Other indexes might help. Also, removing the outer DISTINCT (if it is not necessary will also boost performance). Other indexes might help, but it is not possible to specify because you haven't qualified AreCalculationsCompleted.
SELECT DISTINCT c.id
FROM tbl_Case c
JOIN tbl_RequestBaseRequest b ON CaseId = c.id
WHERE AreCalculationsCompleted = 0
AND b.IsApplicantRequest = 1
AND c.IsArchived = 0
AND EXISTS(
SELECT *
FROM tbl_Response r
WHERE r.ClientRequestId IN (b.id, b.OldClientRequestId)
)
SELECT DISTINCT c.ID
FROM tbl_Case c
INNER JOIN tbl_RequestBaseRequest b ON CaseId = c.ID
INNER JOIN tbl_Response r ON (b.ID = r.ClientRequestId OR b.OldClientRequestId = r.ClientRequestId)
Often rewriting OR as UNION helps.
SELECT c.ID
FROM tbl_Case c
INNER JOIN tbl_RequestBaseRequest b
ON CaseId = c.ID
WHERE AreCalculationsCompleted = 0
AND b.IsApplicantRequest = 1
AND c.IsArchived = 0
AND b.ID IN (SELECT ClientRequestId
FROM tbl_Response)
UNION
SELECT c.ID
FROM tbl_Case c
INNER JOIN tbl_RequestBaseRequest b
ON CaseId = c.ID
WHERE AreCalculationsCompleted = 0
AND b.IsApplicantRequest = 1
AND c.IsArchived = 0
AND b.OldClientRequestId IN (SELECT ClientRequestId
FROM tbl_Response)
You could tidy this up somewhat by encapsulating the join of c and b into a CTE and referencing that in both branches of the UNION instead of repeating it - or materialising into a temp table if that initial join is itself expensive.
SELECT DISTINCT c.ID
FROM tbl_Case c
INNER JOIN tbl_RequestBaseRequest b
ON CaseId = c.ID
AND AreCalculationsCompleted = 0
AND b.IsApplicantRequest = 1
AND c.IsArchived=0
AND EXISTS (SELECT NULL
FROM tbl_Response
WHERE ClientRequestId IN (b.ID, b.OldClientRequestId))

T-SQL force null value based on condition

This is my view
SELECT e.Text AS StatusText,
a.Created AS [DATE],
a.Username,
b.Name AS CustomerName,
c.Name AS ServiceName,
d.Message AS DeviationMessage
FROM dbo.StatusUpdate AS a
LEFT OUTER JOIN dbo.Customer AS b ON a.CustomerId = b.CustomerID
LEFT OUTER JOIN dbo.Service AS c ON a.ServiceId = c.ServiceID
LEFT OUTER JOIN dbo.Deviation AS d ON a.DeviationId = d.DeviationID
LEFT OUTER JOIN dbo.StatusText AS e ON a.Status = e.ID
What i would like to do is: When a.Status(int) is 2 or 3, i would like to force a.Username to show as NULL. How should i approach this?
Try this:
SELECT e.Text AS StatusText,
a.Created AS [DATE],
CASE a.status
WHEN 2 THEN NULL
WHEN 3 THEN NULL
ELSE a.Username
END,
b.Name AS CustomerName,
c.Name AS ServiceName,
d.Message AS DeviationMessage
FROM dbo.StatusUpdate AS a
LEFT OUTER JOIN dbo.Customer AS b ON a.CustomerId = b.CustomerID
LEFT OUTER JOIN dbo.Service AS c ON a.ServiceId = c.ServiceID
LEFT OUTER JOIN dbo.Deviation AS d ON a.DeviationId = d.DeviationID
LEFT OUTER JOIN dbo.StatusText AS e ON a.Status = e.ID
You could achieve this pretty easily with a case statment.
So something like
CASE WHEN Status = 3 THEN USERNAME IS NULL
This is untested but the idea is there.

Inner Join (Select . From)

I need to get the last record posted by users. The following query below would get the information I need if I want if I can do order by before group by
select a.client_id, a.client, b.title, b.type, b.created
from profile_users a, node b
where a.uid = b.uid
and b.type = 'event'
and a.status=1
and a.client_id in (select c.client_id
from profile_users c, follows d
where c.uid = d.followed_id
and d.following_id =3)
group by a.client_id
order by a.client_id,
b.created desc
I tried rewriting the query using inner join but not getting the desired result. I need to write this query so that I am getting the client_id after checking records on follows table. I need some assistance to fix this query.
select b.client_id, b.client, a.title, a.created
from node a
inner join profile_users b on a.uid=b.uid
inner join (select c.client_id
from profile_users c
inner join follows d on c.uid=d.followed_id
where c.status = 1
and d.following_id = 3
order by c.client_id
) as X1
Use sql "partition by " it will allow you to sort your records without group by.
http://learnsqlserver.in/2/Partition-By-Clause.aspx
This is best to use over group by.
You need to use a co-related subquery in order to determine the last post:
select a.client_id, a.client, b.title, b.type, b.created
from profile_users a
join node b on a.uid = b.uid
where b.type = 'event'
and a.status=1
and a.client_id in (select c.client_id
from profile_users c
join follows d on c.uid = d.followed_id
where d.following_id = 3)
and b.created = (select max(n2.created)
from node n2
where n2.uid = a.uid)
order by a.client_id,
b.created desc
I also changed your old-style implicit joins in the where clause to explicit ones using the 'JOIN' keyword.

Conditional INNER JOIN in SQL Server

I have a rather complex query that pretty much mimics a test query I have below:
SELECT C.*
FROM Customer C
INNER JOIN CustDetail CD ON C.CustomerId = CD.CustomerId
INNER JOIN Address A ON CD.DetailID = A.DetailID
INNER JOIN Group G ON C.CustomerId = G.CustomerId --Join only when C.code = 1
INNER JOIN GroupDetail D ON G.GroupId = D.DetailId --Join only when C.code = 1
WHERE G.Active = 1 AND --Only when C.code = 1
D.code = '1' AND --Only when C.code = 1
C.Id = #customerId
I'd like to do INNER JOINs on Group G and GroupDetail D (and ofcourse not have them in the WHERE conditions based on the table column C.code = 1
I replaced the INNER JOINs with LEFT OUTER JOINs for both the join conditions, but the result set is not what was expected
How do I conditionally do the JOIN
SELECT C.*
FROM Customer C
INNER JOIN CustDetail CD ON C.CustomerId = CD.CustomerId
INNER JOIN Address A ON CD.DetailID = A.DetailID
LEFT OUTER JOIN Group G ON C.CustomerId = G.CustomerId
LEFT OUTER JOIN GroupDetail D ON G.GroupId = D.DetailId
WHERE ((G.Active = 1 AND C.code = 1) OR G.Active IS NULL) AND
((D.code = '1' AND C.code = 1) OR D.code IS NULL) AND
C.Id = #customerId
I'm guessing you didn't include the IS NULL checks before so you never got to see rows where C.code <> 1 ?
You should check for NULL on a field that will never be null. This is almost always 'id', but it's not clear that you have a G.id or a D.id.
I'm guessing what you want is just a tighter ON clause, and a compound condition.
SELECT C.*
FROM Customer C
INNER JOIN CustDetail CD ON C.CustomerId = CD.CustomerId
INNER JOIN Address A ON CD.DetailID = A.DetailID
-- the next two joins happen only when c.code=1
-- their columns will be null when there is no match.
LEFT JOIN Group G ON C.CustomerId = G.CustomerId AND C.Code = 1
LEFT JOIN GroupDetail D ON G.GroupId = D.DetailId AND C.Code = 1
WHERE C.Id = #customerId AND --always check this
-- this condition is true if code is null or code isn't 1,
((C.code IS NULL or C.code <> 1)
-- or (if the code is 1), it is true if g.active and d.code
OR (G.Active = 1 AND D.code = '1'))
This will do a semi-join only when code is 1.
SELECT C.*
FROM Customer C
INNER JOIN CustDetail CD
ON C.CustomerId = CD.CustomerId
INNER JOIN Address A
ON CD.DetailID = A.DetailID
WHERE
C.Id = #customerId AND
(c.code != 1 OR
EXISTS(
SELECT NULL
FROM Group G
JOIN GroupDetail D ON G.GroupId = D.DetailId
WHERE
C.CustomerId = G.CustomerId AND
G.Active = 1 AND
D.code = '1'
))