SQL query join conditions - sql

I have a query (exert from a stored procedure) that looks something like this:
SELECT S.name
INTO #TempA
from tbl_Student S
INNER JOIN tbl_StudentHSHistory TSHSH on TSHSH.STUD_PK=S.STUD_PK
INNER JOIN tbl_CODETAILS C
on C.CODE_DETL_PK=S.GID
WHERE TSHSH.Begin_date < #BegDate
Here is the issue, the 2nd inner join and corresponding where statement should only happen if only a certain variable (#UseArchive) is true, I don't want it to happen if it is false. Also, in TSHSH certain rows might have no corresponding entries in S. I tried splitting it into 2 separate queries based on #UseArchive but studio refuses to compile that because of the INTO #TempA statement saying that there is already an object named #TempA in the database. Can anyone tell me of a way to fix the query or a way to split the queries with the INTO #TempA statement?

Looks like you're asking 2 questions here.
1- How to fix the SELECT INTO issue:
SELECT INTO only works if the target table does not exist. You need to use INSERT INTO...SELECT if the table already exists.
2- Conditional JOIN:
You'll need to do a LEFT JOIN if the corresponding row may not exist. Try this.
SELECT S.name
FROM tbl_Student S
INNER JOIN tbl_StudentHSHistory TSHSH
ON TSHSH.STUD_PK=S.STUD_PK
LEFT JOIN tbl_CODETAILS C
ON C.CODE_DETL_PK=S.GID
WHERE TSHSH.Begin_date < #BegDate
AND CASE WHEN #UseArchive = 1 THEN c.CODE_DETL_PK ELSE 0 END =
CASE WHEN #UseArchive = 1 THEN S.GID ELSE 0 END
Putting the CASE statement in the WHERE clause and not the JOIN clause will force it to act like an INNER JOIN when #UseArchive and a LEFT JOIN when not.

I'd replace it with LEFT JOIN
LEFT JOIN tbl_CODETAILS C ON #UseArchive = 1 AND C.CODE_DETL_PK=S.GID

You can split the queries and then insert into a temp table easily.
SELECT * INTO #TempA FROM
(
SELECT * FROM Q1
UNION ALL
SELECT * FROM Q2
) T

SELECT S.name
INTO #TempA
from tbl_Student S
INNER JOIN tbl_StudentHSHistory TSHSH
on TSHSH.STUD_PK = S.STUD_PK
INNER JOIN tbl_CODETAILS C
on C.CODE_DETL_PK = S.GID
and #UseArchive = true
WHERE TSHSH.Begin_date < #BegDate
But putting #UseArchive = true in the join in this case is the same as where
Your question does not make much sense to me
So what if TSHSH certain rows might have no corresponding entries in S?
If you want just one of the joins to match
SELECT S.name
INTO #TempA
from tbl_Student S
LEFT OUTER JOIN tbl_StudentHSHistory TSHSH
on TSHSH.STUD_PK = S.STUD_PK
LEFT OUTER JJOIN tbl_CODETAILS C
on C.CODE_DETL_PK = S.GID
and #UseArchive = true
WHERE TSHSH.Begin_date < #BegDate
and ( TSHSH.STUD_PK is not null or C.CODE_DETL_PK id not null )

Related

SQL Query Select from 1 table and return data based on 2 columns

I'm working on a SQL query where I have data stored in table r. Based on the columns of give or receive, I need to store the data in a temp table to then store in a new table.
Essentially, the data is pulling from 3 tables and the end goal is to get the binary code for an image and store to display in .net
I'm trying to figure out the multi select at this time
So give or receive in r equals Username in S, display all the data that pertains and get the image if employee equals employee
I've tried a good amount of code and I feel like an OR would do the trick but it doesn't seem to.
Thanks for any help you may provide.
SELECT
r.id, r.give, r.[receive], r.[type], r.[description], r.isApproved,
r.photoGive, r.photoReceive
INTO
#temp2
FROM
Intranet.dbo.Recgonize r
SELECT s.Employee, s.Username
INTO #temp3
FROM Vision7.dbo.SEUser s
SELECT p.Photo, p.Employee
INTO #temp4
FROM Vision7.dbo.EMPhoto p
SELECT *
FROM #temp2 AS a
INNER JOIN #temp3 b ON a.give = b.Username
INNER JOIN #temp4 c ON b.Employee = c.Employee
DROP TABLE #temp2
DROP TABLE #temp3
DROP TABLE #temp4
Why are you using temporary tables for this? These just make code harder to debug and maintain, more expensive to run, and more complicated to understand.
JOINs will work without temporary tables. But you do have to additional logic to get the give and receive values in separate columns, so more JOINs are necessary:
SELECT r.id, r.give, r.[receive], r.[type], r.[description],
r.isApproved, r.photoGive, r.photoReceive,
pg.Photo as give_photo, pg.Employee as give_employee,
pr.Photo as receive_photo, pr.Employee as receive_employee
FROM Intranet.dbo.Recognize r LEFT JOIN
Vision7.dbo.SEUser sg
ON r.give = sg.Username LEFT JOIN
Vision7.dbo.SEUser sr
ON r.receive = sr.Username LEFT JOIN
Vision7.dbo.EMPhoto pg
ON sg.Employee = pg.Employee LEFT JOIN
Vision7.dbo.EMPhoto pr
ON sr.Employee = pr.Employee
Try with a single script as below-
SELECT a.id,
a.give,
a.[receive],
a.[type],
a.[description],
a.isApproved,
a.photoGive,
a.photoReceive,
b.Employee,
b.Username,
c.Photo,
c.Employee
FROM Intranet.dbo.Recgonize A
INNER JOIN Vision7.dbo.SEUser B ON a.give = b.Username
INNER JOIN Vision7.dbo.EMPhoto C ON b.Employee = c.Employee;
You may want try following:
-- Include only required columns select rather than "*"
SELECT *
FROM #temp2 AS a
INNER JOIN #temp3 b ON a.give = b.Username
INNER JOIN #temp3 b2 ON a.receive = b2.Username
INNER JOIN #temp4 c ON b.Employee = c.Employee
INNER JOIN #temp4 c2 ON b2.Employee = c2.Employee
or
-- Include only required columns in select rather than "*"
SELECT *
FROM
(select r.id, r.give as UserName, r.[type], r.[description], r.isApproved, r.photoGive from #temp2
union
select r.id, r.[receive], r.[type], r.[description], r.isApproved, r.photoReceive from #temp2
) AS a
INNER JOIN #temp3 b ON a.UserName = b.Username
INNER JOIN #temp4 c ON b.Employee = c.Employee
If temp tables are NOT used for necessary need by application, same logic can work with actual tables, just replace #Temp2, #Temp3, #Temp4 with appropriate table names.

SQL select results not appearing if a value is null

I am building a complex select statement, and when one of my values (pcf_auto_key) is null it will not disipaly any values for that header entry.
select c.company_name, h.prj_number, h.description, s.status_code, h.header_notes, h.cm_udf_001, h.cm_udf_002, h.cm_udf_008, l.classification_code
from project_header h, companies c, project_status s, project_classification l
where exists
(select company_name from companies where h.cmp_auto_key = c.cmp_auto_key)
and exists
(select status_code from project_status s where s.pjs_auto_key = h.pjs_auto_key)
and exists
(select classification_code from project_classification where h.pcf_auto_key = l.pcf_auto_key)
and pjm_auto_key = 11
--and pjt_auto_key = 10
and c.cmp_auto_key = h.cmp_auto_key
and h.pjs_auto_key = s.pjs_auto_key
and l.pcf_auto_key = h.pcf_auto_key
and s.status_type = 'O'
How does my select statement look? Is this an appropriate way of pulling info from other tables?
This is an oracle database, and I am using SQL Developer.
Assuming you want to show all the data that you can find but display the classification as blank when there is no match in that table, you can use a left outer join; which is much clearer with explicit join syntax:
select c.company_name, h.prj_number, h.description, s.status_code, h.header_notes,
h.cm_udf_001, h.cm_udf_002, h.cm_udf_008, l.classification_code
from project_header h
join companies c on c.cmp_auto_key = h.cmp_auto_key
join project_status s on s.pjs_auto_key = h.pjs_auto_key
left join project_classification l on l.pcf_auto_key = h.pcf_auto_key
where pjm_auto_key = 11
and s.status_type = 'O'
I've taken out the exists conditions as they just seem to be replicating the join conditions.
If you might not have matching data in any of the other tables you can make the other inner joins into outer joins in the same way, but be aware that if you outer join to project_status you will need to move the statatus_type check into the join condition as well, or Oracle will convert that back into an inner join.
Read more about the different kinds of joins.

including a condition dynamically based on another condition

I have a query as below
select --------
from table a
left outer join ....c
where
(a.column='123') and (c.column='456')
I would like to
include "(c.column='456')" only when (a.column='123') is not null
how do I do that in a single query ? or do I need to write two separate queries ?
Should be pretty straightforward :
select --------
from table
left outer join....
where (Condition A IS NULL) OR (condition A AND condition B)
UPDATED: For your conditions:
where (a.column is null) or (a.column='123' and c.column='456')
It will include a a row if it's a.column is null or if bot a.column and c.column have valid values.
As I understand your requirement this is the sql you want
select distinct cm.credit_amt,e.credit_lifetime,e.credit_desc,e.icom_code,e.entry_hint,
e.credit_id,e.credit_type_id,e.recontract_period,a.class_desc,a.offer_id,
a.offer_class_id
from rti_retention.package a
left outer join rti_retention.offer_class_credit b on (a.offer_id=b.offer_id
and a.offer_class_id=b.offer_class_id
and a.customer_type_id=b.customer_type_id)
left outer join rti_retention.credit_pre_bundle c on (b.credit_id=c.credit_id)
left outer join rti_retention.credit e on (c.credit_id=e.credit_id)
left outer join rti_retention.credit_mix_amount cm on (cm.credit_id=c.credit_id and cm.prod_mix_id=a.prod_mix_id)
where a.offer_class_id not in (1,2,16)
and a.channel_id=5 and a.customer_type_id=1
and a.offer_id='6055'
and c.prod_mix_id = case when (select count(*)
from rti_retention.credit_pre_bundle c1
where c1.prod_mix_id='1000' ) > 1 then '1000' else c.prod_mix_id end
and e.icom_code is not null
some time there will be some sql syntax errors. due to i havent full data base i wrote sql on mind. cant test it.

Using left join and inner join in the same query

Below is my query using a left join that works as expected. What I want to do is add another table filter this query ever further but having trouble doing so. I will call this new table table_3 and want to add where table_3.rwykey = runways_updatable.rwykey. Any help would be very much appreciated.
SELECT *
FROM RUNWAYS_UPDATABLE
LEFT JOIN TURN_UPDATABLE
ON RUNWAYS_UPDATABLE.RWYKEY = TURN_UPDATABLE.RWYKEY
WHERE RUNWAYS_UPDATABLE.ICAO = 'ICAO'
AND (RUNWAYS_UPDATABLE.TORA > 4000 OR LDA > 0)
AND (TURN_UPDATABLE.AIRLINE_CODE IS NULL OR TURN_UPDATABLE.AIRLINE_CODE = ''
OR TURN_UPDATABLE.AIRLINE_CODE = '')
'*************EDIT To CLARIFY *****************
Here is the other statement that inner join i would like to use and I would like to combine these 2 statements.
SELECT *
FROM RUNWAYS_UPDATABLE A, RUNWAYS_TABLE B
WHERE A.RWYKEY = B.RWYKEY
'***What I have so far as advice taken below, but getting syntax error
SELECT RUNWAYS_UPDATABLE.*, TURN_UPDATABLE.*, AIRPORT_RUNWAYS_SELECTED.*
FROM RUNWAYS_UPDATABLE
INNER JOIN AIRPORT_RUNWAYS_SELECTED
ON RUNWAYS_UPDATABLE.RWYKEY = AIRPORT_RUNWAYS_SELECTED.RWYKEY
LEFT JOIN TURN_UPDATABLE
ON RUNWAYS_UPDATABLE.RWYKEY = TURN_UPDATABLE.RWYKEY
NOTE: If i comment out the inner join and leave the left join or vice versa, it works but when I have both of joins in the query, thats when im getting the syntax error.
I always come across this question when searching for how to make LEFT JOIN depend on a further INNER JOIN. Here is an example for what I am searching when I am searching for "using LEFT JOIN and INNER JOIN in the same query":
SELECT *
FROM foo f1
LEFT JOIN (bar b1
INNER JOIN baz b2 ON b2.id = b1.baz_id
) ON
b1.id = f1.bar_id
In this example, b1 will only be included if b2 is also found.
Remember that filtering a right-side table in left join should be done in join itself.
select *
from table1
left join table2
on table1.FK_table2 = table2.id
and table2.class = 'HIGH'
I finally figured it out. Thanks for all your help!!!
SELECT * FROM
(AIRPORT_RUNWAYS_SELECTED
INNER JOIN RUNWAYS_UPDATABLE
ON AIRPORT_RUNWAYS_SELECTED.RWYKEY = RUNWAYS_UPDATABLE.RWYKEY)
LEFT JOIN TURN_UPDATABLE ON RUNWAYS_UPDATABLE.RWYKEY = TURN_UPDATABLE.RWYKEY
Add your INNER_JOIN before your LEFT JOIN:
SELECT *
FROM runways_updatable ru
INNER JOIN table_3 t3 ON ru.rwykey = t3.rwykey
LEFT JOIN turn_updatable tu
ON ru.rwykey = tu.rwykey
AND (tu.airline_code IS NULL OR tu.airline_code = '' OR tu.airline_code = '')
WHERE ru.icao = 'ICAO'
AND (ru.tora > 4000 OR ru.lda > 0)
If you LEFT JOIN before your INNER JOIN, then you will not get results from table_3 if there is no matching row in turn_updatable. It's possible this is what you want, but since your join condition for table_3 only references runways_updatable, I would assume that you want a result from table_3, even if there isn't a matching row in turn_updatable.
EDIT:
As #NikolaMarkovinović pointed out, you should filter your LEFT JOIN in the join condition itself, as you see above. Otherwise, you will not get results from the left-side table (runways_updatable) if that condition isn't met in the right-side table (turn_updatable).
EDIT 2: OP mentioned this is actually Access, and not MySQL
In Access, perhaps it's a difference in the table aliases. Try this instead:
SELECT [ru].*, [tu].*, [ars].*
FROM [runways_updatable] AS [ru]
INNER JOIN [airport_runways_selected] AS [ars] ON [ru].rwykey = [ars].rwykey
LEFT JOIN [turn_updatable] AS [tu]
ON [ru].rwykey = [tu].rwykey
AND ([tu].airline_code IS NULL OR [tu].airline_code = '' OR [tu].airline_code = '')
WHERE [ru].icao = 'ICAO'
AND ([ru].tora > 4000 OR [ru].lda > 0)
If it is just an inner join that you want to add, then do this. You can add as many joins as you want in the same query. Please update your answer if this is not what you want, though
SELECT *
FROM RUNWAYS_UPDATABLE
LEFT JOIN TURN_UPDATABLE
ON RUNWAYS_UPDATABLE.RWYKEY = TURN_UPDATABLE.RWYKEY
INNER JOIN table_3
ON table_3.rwykey = runways_updatable.rwykey
WHERE RUNWAYS_UPDATABLE.ICAO = 'ICAO'
AND (RUNWAYS_UPDATABLE.TORA > 4000 OR LDA > 0)
AND (TURN_UPDATABLE.AIRLINE_CODE IS NULL OR TURN_UPDATABLE.AIRLINE_CODE = ''
OR TURN_UPDATABLE.AIRLINE_CODE = '')
I am not really sure what you want. But maybe something like this:
SELECT RUNWAYS_UPDATABLE.*, TURN_UPDATABLE.*
FROM RUNWAYS_UPDATABLE
JOIN table_3
ON table_3.rwykey = runways_updatable.rwykey
LEFT JOIN TURN_UPDATABLE
ON RUNWAYS_UPDATABLE.RWYKEY = TURN_UPDATABLE.RWYKEY
WHERE RUNWAYS_UPDATABLE.ICAO = 'ICAO'
AND (RUNWAYS_UPDATABLE.TORA > 4000 OR LDA > 0)
AND (TURN_UPDATABLE.AIRLINE_CODE IS NULL OR TURN_UPDATABLE.AIRLINE_CODE = ''
OR TURN_UPDATABLE.AIRLINE_CODE = '')
For Postgres, query planner does not guarantee order of execution of join. To Guarantee one can use #Gajus solution but the problem arises if there are Where condition for inner join table's column(s). Either one would to require to carefully add the where clauses in the respective Join condition or otherwise it is better to use subquery the inner join part, and left join the output.

SQL JOIN WIth null

What can I do do make my statement return Null when there is no row with D.MetaDataID = '580c215f-54cb-4449-8368-7d740be71973' and the Data Table?
I've tried Left JOIN But nothing changes... :(
SELECT
D.Value
FROM dbo.Item I
JOIN dbo.Data D ON D.ItemID = I.ID
WHERE I.ItemTypeID = '14ea6709-1bf8-4d5c-9090-3ace3cc42874' --Instance.album
AND D.MetaDataID = '580c215f-54cb-4449-8368-7d740be71973' --freepacks
You need a LEFT JOIN and to move the condition on D into the ON clause rather than WHERE. In the WHERE clause this converts your query back into an inner join.
SELECT D.Value
FROM dbo.Item I
LEFT JOIN dbo.Data D
ON D.ItemID = I.ID
AND D.MetaDataID = '580c215f-54cb-4449-8368-7d740be71973'
--freepacks
WHERE I.ItemTypeID = '14ea6709-1bf8-4d5c-9090-3ace3cc42874' --Instance.album
Make it a LEFT JOIN. Left joins will preserve every row from the original table (dbo.Item), even if the table being joined (dbo.Data) would be NULL. Of course, then you also can't require dbo.Data.anything to be nonzero in your on clause so you should probably remove that criterion.