SQL JOIN WIth null - sql

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.

Related

ORA-00933: SQL command not properly ended with INSERT INTO...SELECT statement

I fix my problem by chance, but I really want to know why it works :),
Here's the thing:
I get the ORA-00933: SQL command not properly ended Error when I execute the following SQL statement:
INSERT INTO BASP_DX.QLR#GT(BDCDYH, QSZT)
SELECT NVL(e.BDCDYH, ' '),b.LIFECYCLE AS QSZT
FROM DJ_DY a
LEFT JOIN DJ_XGDJGL d
ON d.ZSLBH = a.SLBH
LEFT JOIN DJ_DJB e
ON e.SLBH = d.FSLBH
AND e.SLBH = '0123456789'
LEFT JOIN DJ_QLRGL f
ON f.SLBH = e.SLBH
AND f.QLRLX = 'Person1'
LEFT JOIN DJ_QLRGL b
ON b.SLBH = a.SLBH
AND (b.QLRLX = 'Person2' OR (b.QLRLX = 'Person3' AND b.QLRID = f.QLRID))
WHERE a.SLBH = '12345'
AND e.SLBH IS NOT NULL
-- add the condition to ensure that
-- this statement and the second statement get the same result
AND b.QLRID IS NOT NULL
AND (a.LIFECYCLE = '0' OR a.LIFECYCLE IS NULL);
I remove all the unnecessary insert value, related table and condition from the original SQL statement, to focus on the problem part.
Then I google it, from this post I know the causes may be:
An INSERT statement with an ORDER BY clause or an INNER JOIN
A DELETE statement with an INNER JOIN or ORDER BY clause
An UPDATE statement with an INNER JOIN
Apparently, these are not my type. I didn't use the INNER JOIN and ORDER BY, all I use is LEFT JOIN statement, so I wonder it might be reason that I set too many conditions with the LEFT JOIN statement (such as LEFT JOIN DJ_QLRGL b), so I try move the conditions after WHERE clause, it looks like this:
INSERT INTO BASP_DX.QLR#GT(BDCDYH, QSZT)
SELECT NVL(e.BDCDYH, ' '),b.LIFECYCLE AS QSZT
FROM DJ_DY a
LEFT JOIN DJ_XGDJGL d
ON d.ZSLBH = a.SLBH
LEFT JOIN DJ_DJB e
ON e.SLBH = d.FSLBH
AND e.SLBH = '0123456789'
LEFT JOIN DJ_QLRGL f
ON f.SLBH = e.SLBH
AND f.QLRLX = 'Person1'
LEFT JOIN DJ_QLRGL b
ON b.SLBH = a.SLBH
-- this conditions move to WHERE clause
WHERE a.SLBH = '12345'
AND e.SLBH IS NOT NULL
-- here is the original LEFT JOIN condition
AND (b.QLRLX = 'Person2' OR (b.QLRLX = 'Person3' AND b.QLRID = f.QLRID))
AND (a.LIFECYCLE = '0' OR a.LIFECYCLE IS NULL);
Then it works!
But why?
I just want to know the reason for this situation.
Solution
the problem is triangular join, the LEFT JOIN conditions can't contain the condition concerning both the self join table, in this case, it's b.QLRID = f.QLRID, so when I remove the b.QLRID = f.QLRID condition, it works.
Firstly, the join of "DJ_QLRGL b" is not LEFT any more,
as WHERE condition excludes rows with no b counterpart found

Skipping an item from being checked in where clause

In the code below, in the WHERE clause, all the items are checked against that condition "bcp.value = cm.id". Hence if item has no value in bcp table it wont show up, how do i make it show up?
I have tried my best using the likes of sub query without success.
Please help
SELECT DISTINCT
u.firstname,
u.lastname,
u.id,
c.shortname,
c.fullname,
cs.name AS 'Units Code/s Covered',
m.name,
MIN(FROM_UNIXTIME(cmc.timemodified)) AS 'Start Time',
MAX(FROM_UNIXTIME(bgi.dateissued))AS 'Time Completed'
FROM
mdl_course_modules_completion cmc
LEFT JOIN mdl_course_modules cm
ON (cmc.coursemoduleid =cm.id)
LEFT JOIN mdl_course_sections cs
ON (cs.id = cm .section)
LEFT JOIN mdl_modules m
ON (m.id= cm.module )
LEFT JOIN mdl_course c
ON c.id = cm.course AND c.shortname = 'DOM_2015_1'
LEFT JOIN mdl_user u
ON u.id = cmc.userid AND (u.firstname = 'bambo' OR u.firstname = 'Test bambo')
LEFT JOIN mdl_badge_issued bgi
ON bgi.userid = cmc.userid
LEFT JOIN mdl_badge bg
ON bg.id = bgi.badgeid
LEFT JOIN mdl_badge_criteria bc
ON bc.badgeid = bg.id
LEFT JOIN mdl_badge_criteria_param bcp
ON bcp.critid = bc.id AND bcp.value = cm.id
GROUP BY u.firstname, cs.name, FROM_UNIXTIME(bgi.dateissued)
Try this:
AND (bcp.value is null or bcp.value = cm.id)
Just add OR Inside your Where Clause like this
WHERE c.shortname = 'DOM_2015_1' AND (bcp.value = cm.id OR bcp.value IS NULL)
or if it string bcp.value = ""
Update
Before to adding this in Where clause you have to get correct Join maybe it will be better use FULL OUTER JOIN or RIGHT JOIN(Is it possible? It depends on your logic) instead of using LEFT JOIN
WHERE conditions are being applied to entire resultset, thus discarding any of those rows from table mdl_course_modules_completion that don't meet this criteria.
If you only need to check for NULL value that could come from mdl_badge_criteria_param bcp table, then adding additional (or bcp.value is null) would suffice.
This is because your mdl_course_modules cm table is being joined to mdl_badge_criteria_param bcp, and not the main table. If we had the case of joining directly with the main table, making bcp independent from cm, query could sometimes yield wrong results, when cm.id would be holding NULL, and bcp.value was a non-null value.
Keeping that in mind, your solution would be
WHERE c.shortname = 'DOM_2015_1' AND ( bcp.value = cm.id OR bcp.value is null )
Edit You may also consider dropping the entire condition considering bcp.value = cm.id since it seems like you want to allow every record, that has a matching cm.id with the main table to appear and instead applying a cm.id is not null to your where condition.

LEFT JOIN ON COALESCE(a, b, c) - very strange behavior

I have encountered very strange behavior of my query and I wasted a lot of time to understand what causes it, in vane. So I am asking for your help.
SELECT count(*) FROM main_table
LEFT JOIN front_table ON front_table.pk = main_table.fk_front_table
LEFT JOIN info_table ON info_table.pk = front_table.fk_info_table
LEFT JOIN key_table ON key_table.pk = COALESCE(info_table.fk_key_table, front_table.fk_key_table_1, front_table.fk_key_table_2)
LEFT JOIN side_table ON side_table.fk_front_table = front_table.pk
WHERE side_table.pk = (SELECT MAX(pk) FROM side_table WHERE fk_front_table = front_table.pk)
OR side_table.pk IS NULL
Seems like a simple join query, with coalesce, I've used this technique before(not too many times) and it worked right.
In this query I don't ever get nulls for side_table.pk. If I remove coalesce or just don't use key_table, then the query returns rows with many null side_table.pk, but if I add coalesce join, I can't get those nulls.
It seems key_table and side_table don't have anything in common, but the result is so weird.
Also, when I don't use side_table and WHERE clause, the count(*) result with coalesce and without differs, but I can't see any pattern in rows missing, it seems random!
Real query:
SELECT ECHANGE.EXC_AUTO_KEY, STOCK_RESERVATIONS.STR_AUTO_KEY FROM EXCHANGE
LEFT JOIN WO_BOM ON WO_BOM.WOB_AUTO_KEY = EXCHANGE.WOB_AUTO_KEY
LEFT JOIN VIEW_WO_SUB ON VIEW_WO_SUB.WOO_AUTO_KEY = WO_BOM.WOO_AUTO_KEY
LEFT JOIN STOCK stock3 ON stock3.STM_AUTO_KEY = EXCHANGE.STM_AUTO_KEY
LEFT JOIN STOCK stock2 ON stock2.STM_AUTO_KEY = EXCHANGE.ORIG_STM
LEFT JOIN CONSIGNMENT_CODES con2 ON con2.CNC_AUTO_KEY = stock2.CNC_AUTO_KEY
LEFT JOIN CONSIGNMENT_CODES con3 ON con3.CNC_AUTO_KEY = stock3.CNC_AUTO_KEY
LEFT JOIN CI_UTL ON CI_UTL.CUT_AUTO_KEY = EXCHANGE.CUT_AUTO_KEY
LEFT JOIN PART_CONDITION_CODES pcc2 ON pcc2.PCC_AUTO_KEY = stock2.PCC_AUTO_KEY
LEFT JOIN PART_CONDITION_CODES pcc3 ON pcc3.PCC_AUTO_KEY = stock3.PCC_AUTO_KEY
LEFT JOIN STOCK_RESERVATIONS ON STOCK_RESERVATIONS.STM_AUTO_KEY = stock3.STM_AUTO_KEY
LEFT JOIN WAREHOUSE wh2 ON wh2.WHS_AUTO_KEY = stock2.WHS_ORIGINAL
LEFT JOIN SM_HISTORY ON (SM_HISTORY.STM_AUTO_KEY = EXCHANGE.ORIG_STM AND SM_HISTORY.WOB_REF = EXCHANGE.WOB_AUTO_KEY)
LEFT JOIN RC_DETAIL ON stock3.RCD_AUTO_KEY = RC_DETAIL.RCD_AUTO_KEY
LEFT JOIN RC_HEADER ON RC_HEADER.RCH_AUTO_KEY = RC_DETAIL.RCH_AUTO_KEY
LEFT JOIN WAREHOUSE wh3 ON wh3.WHS_AUTO_KEY = COALESCE(RC_DETAIL.WHS_AUTO_KEY, stock3.WHS_ORIGINAL, stock3.WHS_AUTO_KEY)
WHERE STOCK_RESERVATIONS.STR_AUTO_KEY = (SELECT MAX(STR_AUTO_KEY) FROM STOCK_RESERVATIONS WHERE STM_AUTO_KEY = stock3.STM_AUTO_KEY)
OR STOCK_RESERVATIONS.STR_AUTO_KEY IS NULL
Removing LEFT JOIN WAREHOUSE wh3 gives me about unique EXC_AUTO_KEY values with a lot of NULL STR_AUTO_KEY, while leaving this row removes all NULL STR_AUTO_KEY.
I recreated simple tables with numbers with the same structure and query works without any problems o.0
I have a feeling COALESCE is acting as a REQUIRED flag for the joined table, hence shooting the LEFT JOIN to become an INNER JOIN.
Try this:
SELECT COUNT(*)
FROM main_table
LEFT JOIN front_table ON front_table.pk = main_table.fk_front_table
LEFT JOIN info_table ON info_table.pk = front_table.fk_info_table
LEFT JOIN key_table ON key_table.pk = NVL(info_table.fk_key_table, NVL(front_table.fk_key_table_1, front_table.fk_key_table_2))
LEFT JOIN (SELECT fk_, MAX(pk) as pk FROM side_table GROUP BY fk_) st ON st.fk_ = front_table.pk
NVL might behave just the same though...
I undertood what was the problem (not entirely though): there is a LEFT JOIN VIEW_WO_SUB in original query, 3rd line. It causes this query to act in a weird way.
When I replaced the view with the other table which contained the information I needed, the query started returning right results.
Basically, with this view join, NVL, COALESCE or CASE join with combination of certain arguments did not work along with OR clause in WHERE subquery, all rest was fine. ALthough, I could get the query to work with this view join, by changing the order of joined tables, I had to place table participating in where subquery to the bottom.

SQL JOIN two tables with null values

I am having a hard time figuring this query out. I need records from issueMaster based on userId and visible, joined to issueActionDetails that are visible, but there may not be any issueActionDetails. I am only getting issues that have actions.
SELECT
b.AssignedTo,
b.Visible,
c.ONEKEY_ID,
C.PHYS_NAME[Doctor],
B.IssueDescription[Issue to Address],
CASE WHEN A.ActionDescription IS NULL THEN 'To Be Assigned' ELSE A.ActionDescription END as [Action],
CASE WHEN A.AssignedTo IS NULL THEN 'To Be Assigned' ELSE A.AssignedTo END as [Assigned To],
CASE WHEN D.[Description] IS NULL THEN 'To Be Assigned' ELSE D.[Description] END As [Status]
FROM [dbo].[tbl_IssueMaster] B
LEFT JOIN [dbo].[tbl_IssueActionDetails] A ON A.IssueID =B.IssueID
INNER JOIN [dbo].[tbl_DoctorsNew] C ON B.OnekeyID =C.ONEKEY_ID
INNER JOIN [dbo].[Action_Status] D ON A.ActionStatus = D.ID
WHERE B.AssignedTo = #UserId AND B.Visible =1 AND A.Visible =1
ORDER BY c.ONEKEY_ID,B.DisplayOrder ,A.DisplayOrder
The "outerness" of the join to tbl_IssueActionDetails is negated by two things:
The inner join to Action_Status:
INNER JOIN [dbo].[Action_Status] D ON A.ActionStatus = D.ID
And the predicate in the WHERE clause
AND A.Visible =1
For any rows returned where there isn't a matching row in tbl_IssueActionDetails, the values in the columns for that table will all be NULL. (The database is essentially creating a row from tbl_IssueActionDetails that consists of all NULLs, and "matching" that row to the row from the table on the left side.
Any predicate that excludes NULL values from columns in that table will exclude that row. If we specify to only return rows where "A.Visible=1", that will exclude any rows that have a NULL value in that column. Which is what I meant when I said the "outerness" of the LEFT JOIN operation was negated.
The fix is to move the predicate to the ON clause of the join to tbl_IssueActionDetail
and change that INNER JOIN to an outer join LEFT JOIN
LEFT JOIN [dbo].[tbl_IssueActionDetails] A
ON A.IssueID = B.IssueID
AND A.Visible = 1
remove "AND A.Visible = 1" from the where clause, add it as a join condition instead
OR, alter the where clause to permit a NULL condition for the LEFT JOIN
WHERE B.AssignedTo = #UserId
AND B.Visible = 1
AND ( A.Visible = 1 OR A.Visible IS NULL)
If you always insist that A.Visible = 1 in the where clause you suppress the NULLs that a LEFT JOIN can provide. Be on guard for this whenever you use an outer join.

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.