Need help with a query (using joins) - sql-server

I have a three tables:
Checkbook table holds what I need to get
Receipts table holds a link to a owner table
Owner table knows what checkbook it is linked to
I need to get the checkbooks only when there are rows in the receipts that are linked to it (through the Owner table).
I don't know exactly how to do this, and it kinda seems circular. This is what I've tried:
SELECT chk.ID, chk.Description FROM tblCheckbook chk
LEFT JOIN tblOwner o
ON r.OwnerID = o.ID
INNER JOIN tblCashReceipts r
ON chk.ID = o.CheckbookID
But sql server complains that "The multi-part identifier "r.OwnerID" could not be bound."
What do I need to do to get this to work?

At the point you do the LEFT JOIN, the definition of r (tblCashReceipts) hasn't been encountered yet. You'll probably want something like:
SELECT chk.ID, chk.Description FROM tblCheckbook chk
LEFT JOIN tblOwner o
ON chk.ID = o.CheckbookID
INNER JOIN tblCashReceipts r
ON o.ID = r.OwnerID

Each join has a on clause that describes the relation. You just have to put the relations with the correct joins.
There is no point in using a left join here as you are using an inner join in the second step. That only causes a larger set for the database to work with to get the same result.
select c.ID, c.Description
from tblCheckBook c
inner join tlbOwner o on o.CheckbookID = c.ID
inner join tblCashReceipts r on r.OwnerID = o.ID

I think you're almost there, you just have your join conditions switched around. Try this:
SELECT chk.ID, chk.Description FROM tblCheckbook chk
LEFT JOIN tblOwner o ON o.CheckbookID = chk.ID
INNER JOIN tblCashReceipts r ON r.OwnerID = o.ID
Or:
SELECT chk.ID, chk.Description FROM tblCheckbook chk
LEFT JOIN tblOwner o ON o.CheckbookID = chk.ID
LEFT JOIN tblCashReceipts r ON r.OwnerID = o.ID
WHERE r.OwnerID IS NOT NULL
So what hapens if there are multiple reciepts for the same Owner? Using this query, you would return a checkbook for each reciept, which may be what you want, but it doesn't sound like it. You may want to throw a DISTINCT on there as well.

Do receipts know what checkbook they belong to?
Join checkbooks through the receipts table.
Owner -> Receipts -> Checkbook

Related

SQL to find which table has diag_code filled, and then look it up in lookup_table

I have a query and a diag_code is either in one table (UM_SERVICE) or the other (LOS), but I can't join both tables to get diag_code that isn't null, that I can think of. Does this look ok for finding if diag_code is in one of the tables and lookup table? It's possible to have both LOS and UM_SERVICE have a diag code on different rows, and they could be different, and both or one could be in the lookup table. I'm not seeing anything in internet search.
Here's a simplified stored procedure:
SELECT distinct
c.id
,uc.id
,c.person_id
FROM dbo.CASES c
INNER JOIN dbo.UM_CASE uc with (NOLOCK) ON uc.case_id = c.id
LEFT JOIN dbo.UM_SERVICE sv (NOLOCK) ON sv.case_id = omc.case_id
LEFT JOIN dbo.UM_SERVICE_CERT usc on usc.service_id = sv.id
LEFT JOIN dbo.LOS S WITH (NOLOCK) ON S.case_id = UC.case_id
LEFT JOIN dbo.LOS_EXTENSION SC WITH (NOLOCK) ON SC.los_id = S.id
INNER JOIN dbo.PERSON op with (NOLOCK) on op.id = c.Person_id
WHERE
(sv.diag_code is not null and c.case_id = sv.case_id
or
s.diag_code is not null and c.case_id = s.case_id)
and
(sv.diag_code is not null and sv.diag_code in (select diag_code from TABLE_LOOKUP)
or
s.diag_code is not null and s.diag_code in (select diag_code from TABLE_LOOKUP)
Table setups like this:
CASES
id person_id
UM_CASE
case_id
LOS
case_id id
LOS_EXTENSION
los_id
Person
id cid
UM_SERVICE
case_id diag_code
UM_SERVICE_CERT
service_id id
TABLE_LOOKUP
diag_code
Since you have two different searches being run, it is going to be much easier to write/read by writing the searches individually and then bringing your two results sets together using the UNION operator. The UNION will eliminate duplicates across the two result sets in a similar manner to what your usage of SELECT DISTINCT is doing for a single result set.
Like so:
/*first part of union performs seach using filter on dbo.UM_SERVICE*/
SELECT
c.id
,uc.id
,c.person_id
FROM
dbo.CASES AS c
INNER JOIN dbo.UM_CASE AS uc ON uc.case_id=c.id
LEFT JOIN dbo.UM_SERVICE AS sv ON sv.case_id = omc.case_id
LEFT JOIN dbo.UM_SERVICE_CERT AS usc on usc.service_id=sv.id
LEFT JOIN dbo.LOS AS S ON S.case_id = UC.case_id
LEFT JOIN dbo.LOS_EXTENSION AS SC ON SC.los_id= S.id
INNER JOIN dbo.PERSON AS op on op.id=c.Person_id
WHERE
sv.diag_code in (select diag_code from TABLE_LOOKUP) /*will eliminate null values in sv.diag_code*/
UNION /*deduplicate result sets*/
/*second part of union performs search using filter on dbo.LOS*/
SELECT
c.id
,uc.id
,c.person_id
FROM
dbo.CASES AS c
INNER JOIN dbo.UM_CASE AS uc ON uc.case_id=c.id
LEFT JOIN dbo.UM_SERVICE AS sv ON sv.case_id = omc.case_id
LEFT JOIN dbo.UM_SERVICE_CERT AS usc on usc.service_id=sv.id
LEFT JOIN dbo.LOS AS S ON S.case_id = UC.case_id
LEFT JOIN dbo.LOS_EXTENSION AS SC ON SC.los_id= S.id
INNER JOIN dbo.PERSON AS op on op.id=c.Person_id
WHERE
s.diag_code in (select diag_code from TABLE_LOOKUP); /*will eliminate null values in s.diag_code*/

Multi database search and update

I don't know where I made a mistake. My goal is to get 1 database of data and transfer it to another database. In doing this, I must use table 2.
Query:
UPDATE [VSRO_SHARD].[dbo].[_RefObjChar]
SET ID = (SELECT ID
FROM [SRO_VT_SHARD].[dbo].[_RefObjChar]
INNER JOIN
(SELECT Link
FROM [SRO_VT_SHARD].[dbo].[_RefObjCommon]
WHERE CodeName128 LIKE 'MOB_RM%')
)
Update
U
Set
U.ID = O.ID
From MyDatabase.dbo.MyTable AS U
INNER JOIN MyDatabase2.dbo.MyTable2 AS O ON U.ID = O.ID
INNER JOIN MyDatabase2.dbo.MyTable3 AS K ON U.ID = K.Link
Where
K.CodeName128 like '%%'
Problem solved.
INNER JOIN requires AS and ON. Thx #Barmar

SQL Query joining parent table with several children rows into one row

I'm trying to implement query to take setups information from database where one setup has link to several items types: Controller, platform and KVM device.
This way:
Rack
|
Setup
/ | \
controller Platform KVM
Connections between parent and children are stored in another table.
I tried the bellow query, but I got setup children in separated rows.
How can I improve query to solve this?
Query:
select R.Id as Rack_Id,
S.Id,C.Id as Setup_Id,
P.Id as Platform_Id,
K.Id as KVM_Id,
R.Capacity, R.[Rack location],
S.[Location in Rack], C.[Controller IP], P.ISMP, P.Platform
From #Racks R join LinksAre LR on LR.SourceId = R.Id
join #Setups S on LR.TargetId=S.Id
left join LinksAre LS on LS.SourceId = S.Id
left join #KVMs K on LS.TargetID = K.Id
left join #Controllers C on LS.TargetId=C.Id
left join #Platforms P on LS.TargetId = P.Id
order by R.Id, S.Id
Thanks!
Think you might need a subquery:
select R.Id as Rack_Id,
S.Id,C.Id as Setup_Id,
P.Id as Platform_Id,
K.Id as KVM_Id,
R.Capacity, R.[Rack location],
( SELECT S.[Location in Rack] FROM #Setups S
WHERE S.ID = LR.TargetId) AS ColumnA,
C.[Controller IP],
P.ISMP, P.Platform
From #Racks R join LinksAre LR on LR.SourceId = R.Id
left join LinksAre LS on LS.SourceId = S.Id
left join #KVMs K on LS.TargetID = K.Id
left join #Controllers C on LS.TargetId=C.Id
left join #Platforms P on LS.TargetId = P.Id
order by R.Id, S.Id

Ambiguous left joins in MS Access

I want to convert the following query from T-SQL
SELECT
*
FROM
A LEFT JOIN
B ON A.field1 = B.field1 LEFT JOIN
C ON C.field1 = A.field2 AND
C.field2 = B.field2
to Jet SQL. Now MS Access does not accept ambiguous queries. How can I do that? I can't put the second comparison in the WHERE clause. Why? Because my scenario is that I am selecting records that does not exist in C.
How to select all records from one table that do not exist in another table?
Now, how do you that in MS Access? Thanks in advance for your time and expertise.
You need a derived table to make this work in MS Access:
SELECT *
FROM (
SELECT A.Field1, A.Field2 As A2, B.Field2
FROM A
LEFT JOIN B ON A.field1 = B.field1) AS x
LEFT JOIN C ON x.A2 = C.field1 AND x.field2= C.field2
From Help LEFT JOIN, RIGHT JOIN Operations
You can link multiple ON clauses. See the discussion of clause linking
in the INNER JOIN topic to see how this is done.
You can also link several ON clauses in a JOIN statement, using the
following syntax:
SELECT fields
FROM table1
INNER JOIN table2 ON table1.field1 compopr table2.field1
AND ON table1.field2 compopr table2.field2)
OR ON table1.field3 compopr table2.field3)];
But works this (it seems there is an error in help):
SELECT *
FROM A
LEFT JOIN B ON A.field1 = B.field1
LEFT JOIN C ON (C.field1 = A.field2 AND C.field2 = B.field2)

Top 1 with a left join

Given the query below there might be multiple rows in dps_markers with the same marker key but we only want to join against the first. If I take this query and remove the top 1 and ORDER BY I get a value for mbg.marker_value but run as it is it always returns null
SELECT u.id, mbg.marker_value
FROM dps_user u
LEFT JOIN
(SELECT TOP 1 m.marker_value, um.profile_id
FROM dps_usr_markers um (NOLOCK)
INNER JOIN dps_markers m (NOLOCK)
ON m.marker_id= um.marker_id AND
m.marker_key = 'moneyBackGuaranteeLength'
ORDER BY m.creation_date
) MBG ON MBG.profile_id=u.id
WHERE u.id = 'u162231993'
Use OUTER APPLY instead of LEFT JOIN:
SELECT u.id, mbg.marker_value
FROM dps_user u
OUTER APPLY
(SELECT TOP 1 m.marker_value, um.profile_id
FROM dps_usr_markers um (NOLOCK)
INNER JOIN dps_markers m (NOLOCK)
ON m.marker_id= um.marker_id AND
m.marker_key = 'moneyBackGuaranteeLength'
WHERE um.profile_id=u.id
ORDER BY m.creation_date
) AS MBG
WHERE u.id = 'u162231993';
Unlike JOIN, APPLY allows you to reference the u.id inside the inner query.
The key to debugging situations like these is to run the subquery/inline view on its' own to see what the output is:
SELECT TOP 1
dm.marker_value,
dum.profile_id
FROM DPS_USR_MARKERS dum (NOLOCK)
JOIN DPS_MARKERS dm (NOLOCK) ON dm.marker_id= dum.marker_id
AND dm.marker_key = 'moneyBackGuaranteeLength'
ORDER BY dm.creation_date
Running that, you would see that the profile_id value didn't match the u.id value of u162231993, which would explain why any mbg references would return null (thanks to the left join; you wouldn't get anything if it were an inner join).
You've coded yourself into a corner using TOP, because now you have to tweak the query if you want to run it for other users. A better approach would be:
SELECT u.id,
x.marker_value
FROM DPS_USER u
LEFT JOIN (SELECT dum.profile_id,
dm.marker_value,
dm.creation_date
FROM DPS_USR_MARKERS dum (NOLOCK)
JOIN DPS_MARKERS dm (NOLOCK) ON dm.marker_id= dum.marker_id
AND dm.marker_key = 'moneyBackGuaranteeLength'
) x ON x.profile_id = u.id
JOIN (SELECT dum.profile_id,
MAX(dm.creation_date) 'max_create_date'
FROM DPS_USR_MARKERS dum (NOLOCK)
JOIN DPS_MARKERS dm (NOLOCK) ON dm.marker_id= dum.marker_id
AND dm.marker_key = 'moneyBackGuaranteeLength'
GROUP BY dum.profile_id) y ON y.profile_id = x.profile_id
AND y.max_create_date = x.creation_date
WHERE u.id = 'u162231993'
With that, you can change the id value in the where clause to check records for any user in the system.
Because the TOP 1 from the ordered sub-query does not have profile_id = 'u162231993'
Remove where u.id = 'u162231993' and see results then.
Run the sub-query separately to understand what's going on.
Damir is correct,
Your subquery needs to ensure that dps_user.id equals um.profile_id, otherwise it will grab the top row which might, but probably not equal your id of 'u162231993'
Your query should look like this:
SELECT u.id, mbg.marker_value
FROM dps_user u
LEFT JOIN
(SELECT TOP 1 m.marker_value, um.profile_id
FROM dps_usr_markers um (NOLOCK)
INNER JOIN dps_markers m (NOLOCK)
ON m.marker_id= um.marker_id AND
m.marker_key = 'moneyBackGuaranteeLength'
WHERE u.id = um.profile_id
ORDER BY m.creation_date
) MBG ON MBG.profile_id=u.id
WHERE u.id = 'u162231993'

Resources