Use JOIN on multiple columns multiple times - sql

I am trying to figure out the best way to use a JOIN in MSSQL in order to do the following:
I have two tables. One table contains technician IDs and an example of one data set would be as follows:
+--------+---------+---------+---------+---------+
| tagid | techBid | techPid | techFid | techMid |
+--------+---------+---------+---------+---------+
| 1-1001 | 12 | 0 | 11 | 6 |
+--------+---------+---------+---------+---------+
I have another table that stores the names of these technicians:
+------+-----------+
| TTID | SHORTNAME |
+------+-----------+
| 11 | Steven |
| 12 | Mark |
| 6 | Pierce |
+------+-----------+
If the ID of a technician in the first table is 0, there is no technician of that type for that row (types are either B, P, F, or M).
I am trying to come up with a query that will give me a result that contains all of the data from table 1 along with the shortnames from table 2 IF there is a matching ID, so the result would look something like the following:
+--------+---------+---------+---------+---------+----------------+----------------+----------------+----------------+
| tagid | techBid | techPid | techFid | techMid | techBShortName | techPShortName | techFShortName | techMShortName |
+--------+---------+---------+---------+---------+----------------+----------------+----------------+----------------+
| 1-1001 | 12 | 0 | 11 | 6 | Mark | NULL | Steven | Pierce |
+--------+---------+---------+---------+---------+----------------+----------------+----------------+----------------+
I am trying to use a JOIN to do this, but I cannot figure out how to join on multiple columns multiple times to where it would look something like
Select table1.tagid, table1.techBid, table1.techPid, table1.techFid, table1.techMid, table2.shortname
FROM table1
INNER JOIN table2 on //Dont know what to put here

You need to use left joins like this:
Select table1.tagid, table1.techBid, table1.techPid, table1.techFid, table1.techMid,
t2b.shortname, t2p.shortname, t2f.shortname, t2m.shortname,
FROM table1
LEFT JOIN table2 t2b on table1.techBid = t2b.ttid
LEFT JOIN table2 t2p on table1.techPid = t2p.ttid
LEFT JOIN table2 t2f on table1.techFid = t2f.ttid
LEFT JOIN table2 t2m on table1.techMid = t2m.ttid

you just do mutiple left join
select tech.techPid, techPname.SHORTNAME
, tech.techFid, techFname.SHORTNAME
from tech
left join techName as techPname
on tech.techPid = techPname.TTID
left join techName as techFname
on tech.techFid = techFname.TTID

Related

How to join multiple columns in one table to another lookup table?

I am unable to figure out how to join a couple of tables together when multiple columns in one table refer to another table.
For example, I have a "document_statuses" table:
document_statuses table:
+-----------+-------------+
| status_id | status_name |
+-----------+-------------+
| 1 | RECEIVED |
| 2 | MISSING |
| 3 | NOT_NEEDED |
+-----------+-------------+
Now in another table, I am tracking the status of multiple documents:
filings table:
+-----------+-------------+----------------+----------------+----------------+
| filing_id | filing_name | doc1_status_id | doc2_status_id | doc3_status_id |
+-----------+-------------+----------------+----------------+----------------+
| 1 | John | 1 | 3 | 2 |
| 2 | Mikaela | 2 | 3 | 2 |
| 3 | Sam | 1 | 2 | 1 |
+-----------+-------------+----------------+----------------+----------------+
How would I write a query that pulls the status_name in for each column and produce the following result:
+-------------+-------------+-------------+------------+
| Filing Name | Doc1 Status | Doc2 Status | Doc3Status |
+-------------+-------------+-------------+------------+
| John | RECEIVED | NOT_NEEDED | MISSING |
| Mikaela | MISSING | NOT_NEEDED | MISSING |
| Sam | RECEIVED | MISSING | RECEIVED |
+-------------+-------------+-------------+------------+
I'm aware of how to do this when looking up a single field from document_statuses per row, but not multiple. If I only had one column in documents that referred to document_statuses, I'd do a simple JOIN:
SELECT filing_name, status_name
FROM documents d
LEFT JOIN document_statuses ds ON d.doc1_status = ds.status_id
But how do I do that when I need more than one?
You will need to join the statuses table multiple times and then alias the columns in the select clause to be formatted to be what you want. Please note that you have to alias the tables in the join clause so that you can reference the columns in the select clause of the statement.
SELECT filing_name
, ds1.status_name AS 'Doc1 Status'
, ds2.status_name AS 'Doc2 Status'
, ds3.status_name AS 'Doc3 Status'
FROM documents d
LEFT JOIN document_statuses ds1 ON d.doc1_status = ds1.status_id
LEFT JOIN document_statuses ds2 ON d.doc2_status = ds2.status_id
LEFT JOIN document_statuses ds3 ON d.doc3_status = ds3.status_id
You'll need to do three times joins with same table using different aliases for table.
SELECT filing_name, ds.status_name, ds1.status_name,
ds2.status_name FROM documents d
LEFT JOIN document_statuses ds ON d.doc1_status
LEFT JOIN document_statuses ds1 ON d.doc1_status
LEFT JOIN document_statuses ds2 ON d.doc1_status
You can do this:
select t1.filing_name, t2.status_name as doc1_status, t3.status_name as doc2_status, t4.status_name as doc3_status
from filings_table t1
inner join statuses_table t2 on t1.doc1_status_id = t2.status_id
inner join statuses_table t3 on t1.doc2_status_id = t3.status_id
inner join statuses_table t4 on t1.doc3_status_id = t4.status_id

My query join from more than 2 TABLES return double values using same key reference

I'm trying to join more than 2 tables using 1 same key reference,
it works fine when I join two 2 tables using left join like this :
SELECT userProfile.UserProfileID, userProfile.name, jobPosition.levelname
FROM master.eliUserProfile userProfile
LEFT JOIN master.eliJobPosition jobPosition ON userProfile.UserProfileId = jobPosition.UserProfileID
where userProfile.UserProfileId = '5001'
Result :
userProfileid | name | levelName |
-----------------+---------+--------------+
5001 | dirdple | Direktur PLE |
5001 | dirdple | Direktur PLE |
But when I want to join another table into it, it return double values, I am using the master table reference (which is UserProfile) :
SELECT userProfile.UserProfileID, userProfile.name, jobPosition.levelname, userAcmMapping.UserAcmMappingId, userAcmMapping.RefID
FROM master.eliUserProfile userProfile
LEFT JOIN master.eliJobPosition jobPosition
ON userProfile.UserProfileId = jobPosition.UserProfileID
LEFT JOIN transactions.eliUserAcmMapping userAcmMapping
ON userProfile.UserProfileId = userAcmMapping.UserProfileID
where userProfile.UserProfileId = '5001'
and it turned out to resulted like this :
userProfileId | name | levelName | UserAcmMappingId | refId |
-----------------+---------+--------------+------------------+-------+
5001 | dirdple | Direktur PLE | 1 | 21 |
5001 | dirdple | Direktur PLE | 7 | 22 |
5001 | dirdple | Direktur PLE | 158 | 23 |
5001 | dirdple | Direktur PLE | 1 | 21 |
5001 | dirdple | Direktur PLE | 7 | 22 |
5001 | dirdple | Direktur PLE | 158 | 23 |
Is it because Iam using the same key(userProfile.UserProfileId)? Fyi, the 3rd table (userAcmMapping) have 3 values with UserProfileId=5001 and 2nd table (jobPosition) have 2 values with UserProfileId=5001.
And the table I want to be referenced is the second table with 2 values (userProfileId=5001)..
Thank you for any help..
It is because you are joining two different tables to one table with the same key. You are joining jobPositions and userAcmMapping to userProfile. I mean there are two joins on one table with the same field, so the result is doubled.
You should instead join jobPositions to userProfile and join userAcmMapping to jobPositions, like this:
SELECT userProfile.UserProfileID, userProfile.name, jobPosition.levelname, userAcmMapping.UserAcmMappingId, userAcmMapping.RefID
FROM master.eliUserProfile userProfile
LEFT JOIN master.eliJobPosition jobPosition
ON userProfile.UserProfileId = jobPosition.UserProfileID
LEFT JOIN transactions.eliUserAcmMapping userAcmMapping
ON jobPosition.UserProfileID = userAcmMapping.UserProfileID
where userProfile.UserProfileId = '5001'
Here it is one join per table.
Note: I didn't test the code, since I don't have actual tables, but it should work.

Using Left join sql query

I'm trying to retrieve DBName, DBNo, DBAmount, DBCountedAmount from Table A and include NewFormNo from Table B so I did this
Table A
|DBName |DBNo | DBAmount | DBCountedAmount |
|-------|--------|----------|---------------------|
|Derek |503456 | 2000 | 2000 |
|John |554422 | 40000 | 4000 |
Table B
|DBName |DBNo | DBAmount | DBCountedAmount | FormNo|
|-------|--------|----------|---------------------|-------|
|Derek |503456 | 2000 | 2000 |00001 |
|John |554422 | 40000 | 4000 |00002 |
So I did this , but it doesnt return the row I want
SELECT A.DBName,A.DBNo,A.DBAmount,A.DBCountedAmount,B.FormNo FROM Table A LEFT JOIN Table B ON A.DBNo=B.DBNo AND A.DBNo= '503456'
I want to retrieve this
|DBName |DBNo | DBAmount | DBCountedAmount | FormNo|
|-------|--------|----------|---------------------|-------|
|Derek |503456 | 2000 | 2000 |00001 |
Change this
AND A.DBNo= '503456'
to this
WHERE A.DBNo= '503456'
Also, what is the type of DBNo? If it's numeric, you can remove the ''
try this :
SELECT A.DBName, A.DBNo, A.DBAmount, A.DBCountedAmount
FROM Table A
LEFT JOIN Table B ON A.DBNo=B.DBNo
WHERE A.DBNo= '503456'
As per your question there is no need of left outer join. You can directly get by using inner join like this:
SELECT distinct a.DBname, a.DBno, a.Dbamount, a.Dbamountcount, b.FormNo
FROM tableA a inner join tableB b
on a.DBno = b.DBno
and a.DBno = 503456

Oracle 10 SQL: FULL JOIN through Cross Reference Table

http://sqlfiddle.com/#!4/24637/1
I have three tables, (better details/data shown in sqlfiddle link), one replacing another, and a cross reference table in between. One of the fields in each of the table uses the cross reference (version), and another one of the fields in each of the tables is the same (changeID).
I need a query that when passed a list of new_version + new_changeType, along with the equivalent original_version + old_changeType (if there is an old version equivalent) PLUS any old changeIDs that were 'missed' in the conversion of data.
TABLES (fields on the same line are equivalent)
OLD_table | XREF_table | NEW_Table
original_version | original_version |
changeID | | changeID
OLD_changeType | |
| new_version | new_version
| | NEW_changeType
DATA
111,1,CT1 | 111,AAA | AAA,1,ONE
111,2,CT2 | 222,BBB | AAA,2,TWO
222,1,CT1 | 333,DDD | BBB,1,ONE
222,2,CT2 | | BBB,2,TWO
222,3,CT3 | | CCC,1,ONE
333,1,CT1 | |
444,1,CT1 | |
If passed the following list, the result set should look like so. (order doesnt matter)
AAA,BBB,CCC
| NEW_VERSION | NEW_CHANGE_TYPE| ORIGINAL_VERSION | CHANGEID | OLD_CHANGE_TYPE |
|-------------|----------------|------------------|----------|-----------------|
| AAA | ONE | 111 | 1 | CT1 |
| AAA | TWO | 111 | 2 | CT2 |
| BBB | ONE | 222 | 1 | CT1 |
| BBB | TWO | 222 | 2 | CT2 |
| CCC | ONE | (null) | (null) | (null) |
| (null) | (null) | 222 | 3 | CT3 |
I'm having trouble getting ALL the data required. I've played with the following query, however I seem to either 1) miss a row or 2) get additional rows not matching the requirements.
The following queries I've played with are as follows.
select
a.new_version,
a.Change_type,
c.original_version,
c.changeID,
c.OLD_Change_type
from NEW_TABLE a
LEFT OUTER JOIN XREF_TABLE b on a.new_version = b.new_version
FULL OUTER JOIN OLD_TABLE c on
b.original_version = c.original_version and a.changeID = c.changeID
where (b.new_version in ('AAA','BBB','CCC') or b.new_version is null);
select
a.new_version,
a.Change_type,
c.original_version,
c.changeID,
c.OLD_Change_type
from NEW_TABLE a
FULL JOIN XREF_TABLE b on a.new_version = b.new_version
FULL JOIN OLD_TABLE c on
b.original_version = c.original_version and a.changeID = c.changeID
where (a.new_version in ('AAA','BBB','CCC'));
The first returns one 'extra' row with the 333,DDD data, which is not specified from the input.
The seconds returns one less row (with the changeID from the old table "missed" from when this data was converted over.
Any thoughts or suggestions on how to solve this?
First inner join old_table and xref_table, as you are not interested in any old_table entries without an xref_table entry. Then full outer join new_table. In your WHERE clause be aware that new_table.new_version can be null, so use coalesce to use xref_table.new_version in this case to limit your results to AAA, BBB and CCC. That's all.
select
coalesce(n.new_version, x.new_version) as new_version,
n.change_type,
o.original_version,
o.changeid,
o.old_change_type
from old_table o
inner join xref_table x
on x.original_version = o.original_version
full outer join new_table n
on n.new_version = x.new_version
and n.changeid = o.changeid
where coalesce(n.new_version, x.new_version) in ('AAA','BBB','CCC')
order by 1,2,3,4,5
;
Here is your fiddle: http://sqlfiddle.com/#!4/24637/11.
BTW: Better never use random aliases like a, b and c that don't indicate what table is meant. That makes the query harder to understand. Use the table's first letter(s) or an acronym instead.

SQL LEFT JOIN help

My scenario: There are 3 tables for storing tv show information; season, episode and episode_translation.
My data: There are 3 seasons, with 3 episodes each one, but there is only translation for one episode.
My objetive: I want to get a list of all the seasons and episodes for a show. If there is a translation available in a specified language, show it, otherwise show null.
My attempt to get serie 1 information in language 1:
SELECT
season_number AS season,number AS episode,name
FROM
season NATURAL JOIN episode
NATURAL LEFT JOIN episode_trans
WHERE
id_serie=1 AND
id_lang=1
ORDER BY
season_number,number
result:
+--------+---------+--------------------------------+
| season | episode | name |
+--------+---------+--------------------------------+
| 3 | 3 | Episode translated into lang 1 |
+--------+---------+--------------------------------+
expected result
+-----------------+--------------------------------+
| season | episode| name |
+-----------------+--------------------------------+
| 1 | 1 | NULL |
| 1 | 2 | NULL |
| 1 | 3 | NULL |
| 2 | 1 | NULL |
| 2 | 2 | NULL |
| 2 | 3 | NULL |
| 3 | 1 | NULL |
| 3 | 2 | NULL |
| 3 | 3 | Episode translated into lang 1 |
+--------+--------+--------------------------------+
Full DB dump
http://pastebin.com/Y8yXNHrH
I tested the following on MySQL 4.1 - it returns your expected output:
SELECT s.season_number AS season,
e.number AS episode,
et.name
FROM SEASON s
JOIN EPISODE e ON e.id_season = s.id_season
LEFT JOIN EPISODE_TRANS et ON et.id_episode = e.id_episode
AND et.id_lang = 1
WHERE s.id_serie = 1
ORDER BY s.season_number, e.number
Generally, when you use ANSI-92 JOIN syntax you need to specify the join criteria in the ON clause. In MySQL, I know that not providing it for INNER JOINs results in a cross join -- a cartesian product.
LEFT JOIN episode_trans
ON episode_trans.id_episode = episode.id_episode
AND episode_trans.id_lang = 1
WHERE id_serie=1
You probably need to move the id_lang = 1 into the LEFT JOIN clause instead of the WHERE clause. Think of it this way... for all of those rows with no translation the LEFT JOIN gives you back NULLs for all of those translation columns. Then in the WHERE clause you are checking to see if that is equal to 1 - which of course evaluates to FALSE.
It would probably be easier if you included your code in the question next time instead of in a link.
Can you try using
LEFT OUTER JOIN
instead of
NATURAL LEFT JOIN