Order of join operations: would these two FROM clauses produce the same results? [closed] - sql

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
Would these two FROM clauses produce the same results? And if not, is there a way to write the the first one so that no parenthesis are needed?
FROM SALESTAX
RIGHT JOIN ( ITEMS
RIGHT JOIN ( PINVOICE
INNER JOIN PINVDET ON PINVOICE.PNV_INVOICENO = PINVDET.PND_INVOICENO AND PINVOICE.PNV_Site = PINVDET.PND_Site
) ON ITEMS.ITE_INVNO = PINVDET.PND_INVNO
) ON SALESTAX.STX_GroupID = PINVDET.PND_TAX1
FULL JOIN ( CUSTMS
RIGHT JOIN CUSMER ON CUSTMS.TMS_CODE = CUSMER.CUS_TERM
) ON PINVDET.PND_CUSTID = CUSMER.CUS_CustID
FROM CUSTMS RIGHT JOIN
CUSMER ON TMS_CODE = CUS_TERM FULL JOIN
PINVDET ON PND_CUSTID = CUS_CustID LEFT JOIN
PINVOICE ON PNV_INVOICENO = PND_INVOICENO AND PNV_Site = PND_Site LEFT JOIN
SALESTAX on STX_GROUPID = PND_TAX1 left join
ITEMS on ITE_INVNO = PND_INVNO
EDIT: While I'd like to know the answer to the first question, I'm more immediately interested in just having a more straightforward version of the first FROM clause that doesn't need parenthesis so if you'd rather just rewrite it than compare the two then feel free to just do that.

I have no idea if the 1st is equivalent to the 2nd (first because the queries are unfriendly formatted, to say the least and second because RIGHT joins are kind of confusing, since many are used to write using LEFT joins.) But to answer the question:
Is there a way to write the the first one so that no parenthesis are needed?
Yes, you can simply remove the parentheses from the 1st query.
Keeping the parentheses and formatted with some white space:
FROM
SALESTAX
RIGHT JOIN
( ITEMS
RIGHT JOIN
( PINVOICE
INNER JOIN
PINVDET
ON PINVOICE.PNV_INVOICENO = PINVDET.PND_INVOICENO
AND PINVOICE.PNV_Site = PINVDET.PND_Site
)
ON ITEMS.ITE_INVNO = PINVDET.PND_INVNO
)
ON SALESTAX.STX_GroupID = PINVDET.PND_TAX1
FULL JOIN
( CUSTMS
RIGHT JOIN
CUSMER
ON CUSTMS.TMS_CODE = CUSMER.CUS_TERM
)
ON PINVDET.PND_CUSTID = CUSMER.CUS_CustID
Without parentheses and white-space formatted:
FROM
SALESTAX
RIGHT JOIN
ITEMS
RIGHT JOIN
PINVOICE
INNER JOIN
PINVDET
ON PINVOICE.PNV_INVOICENO = PINVDET.PND_INVOICENO
AND PINVOICE.PNV_Site = PINVDET.PND_Site
ON ITEMS.ITE_INVNO = PINVDET.PND_INVNO
ON SALESTAX.STX_GroupID = PINVDET.PND_TAX1
FULL JOIN
CUSTMS
RIGHT JOIN
CUSMER
ON CUSTMS.TMS_CODE = CUSMER.CUS_TERM
ON PINVDET.PND_CUSTID = CUSMER.CUS_CustID
To answer the other question, about the 2nd query, no it isn't equivalent. You missed the table aliases and changed an inner join to left join. This is equivalent to the 1st:
FROM CUSMER
LEFT JOIN
CUSTMS ON CUSTMS.TMS_CODE = CUSMER.CUS_TERM
FULL JOIN
PINVDET
INNER JOIN -- this is changed
PINVOICE ON PINVOICE.PNV_INVOICENO = PINVDET.PND_INVOICENO
AND PINVOICE.PNV_Site = PINVDET.PND_Site
LEFT JOIN
ITEMS ON ITEMS.ITE_INVNO = PINVDET.PND_INVNO
LEFT JOIN
SALESTAX ON SALESTAX.STX_GroupID = PINVDET.PND_TAX1
ON PINVDET.PND_CUSTID = CUSMER.CUS_CustID

I encourage you to write your from clauses by placing all left joins first followed by inner joins. This greatly simplifies trying to figure out what queries are doing. A series of left joins says "keep all the rows in the first table". A series of inner joins says "keep only rows where there are matches between tables." (Occasionally, you might need subqueries as in the first example.)
It is unlikely in this example that the two are the same. In the first, the full join is the "outermost" join. In the second, the full join is embedded in a series of joins. These are interpreted sequentially from the first to the last. One of these is probably converting the full join to an inner join or left join. Of course, the two could produce equivalent results if all the tables match.
The second example could probably be written as:
FROM CUSMER LEFT JOIN
CUSTMS ON TMS_CODE = CUS_TERM LEFT JOIN
PINVDET ON PND_CUSTID = CUS_CustID LEFT JOIN
PINVOICE ON PNV_INVOICENO = PND_INVOICENO AND PNV_Site = PND_Site LEFT JOIN
SALESTAX on STX_GROUPID = PND_TAX1 left join
ITEMS on ITE_INVNO = PND_INVNO
(assuming that something after the full join is converting it to a left join anyway).

Related

'or' operator in left join

select
evm.case_id, evm.close_ts, evm.cm_promise_utc_ts, evm.cm11, evm.cm13, evm.creat_id, evm.creat_ts, evm.creat_type,
evm.event_act, evm.event_act_perf, evm.event_dt, evm.event_id, evm.event_orig, evm.event_srce, evm.event_sta, evm.event_sub_type, evm.event_type,
evm.fol_pref_mthd, evm.incdnt_no,
evm.lst_updt_id, evm.lst_updt_ts, evm.lst_updt_type,
evm.main_sta, evm.new_act_note, evm.orig_id, evm.own_type, evm.prod_type, evm.req_chan, evm.srvc_arm,
crm.case_nm,
evg.req_add_info as req_add_info_general, evg.rslt_add_info,
evt.add_info, evt.other_ds, evt.req_add_info as req_add_info_ticketing,
eve.event_iss, eve.event_rev,
eve.req_cm_commentary, eve.req_event_nm, eve.rslt_err_dt, eve.rslt_root_cause, eve.rslt_rslv_dtl_cnfr, eve.rslt_rslv_dtl_outcm,
tlsopus.agnt_emply_sta, tlsopus.dlvr_mthd, tlsopus.dm_ctry,
tlsopus.event_subtype as event_sub_type_tlsarpt,
tlsopus.mkt_alpha_cd, tlsopus.own_id, tlsopus.prod_full_nm,
tlsopus.repr_locat, tlsopus.req_pref_spec_dt, tlsopus.req_vend, tlsopus.rslt_rec_loctr,
tlsopus.trvl_prod, tlsopus.trvl_type, tlsopus.user_role,
tlssales.trip_id, tlssales.inv_dt, tlssales.refd_exch_in,
tlssales.trip_type, tlssales.trans_usd_am, tlssales.mkt_cd, tlssales.chan_type,tlssales.exp_trip_id
from cstonedb3.opus_event_master as evm
left join cstonedb3.opus_crm_cases as crm
on evm.case_id = crm.case_id
left join cstonedb3.opus_event_general as evg
on evm.event_id = evg.event_id
left join cstonedb3.opus_event_ticketing as evt
on evm.event_id = evt.event_id
left join cstonedb3.opus_event_escalation as eve
on evm.event_id = eve.event_id
left join cstonedb3.tlsarpt_opus_case_detail as tlsopus
on evm.event_id = tlsopus.event_id
left join cstonedb3.tlsarpt_travel_sales as tlssales
on tlsopus.rslt_rec_loctr = tlssales.trip_id
or tlsopus.rslt_rec_loctr = tlssales.exp_trip_id
where evm.creat_ts between '2022-07-01' and '2022-07-31'
and tlsopus.mkt_alpha_cd = 'US';
tlssales table has two columns that correspond to one column in tlsopus
i.e the values for "tlsopus.rslt_rec_loctr" can be present in either "tlssales.trip_id" or "tlssales.exp_trip_id".
I want the join to first search through the "tlssales.trip_id" column. If there's no match here in this column, then look for a match in "tlssales.exp_trip_id" column.
For this I applied the or condition in the last join statement. But this query gives the following error :
FAILED: SemanticException Cartesian products are disabled for safety
reasons. If you know what you are doing, please
sethive.strict.checks.cartesian.product to false and that
hive.mapred.mode is not set to 'strict' to proceed. Note that if you
may get errors or incorrect results if you make a mistake while using
some of the unsafe features.
Can someone please explain where I'm going wrong? I tried to look through other pages and found out that we can apply or in join.

Can this Oracle SQL query be simplified?

Is there a way I can write this better? The way it's currently written is taking a long time to pull the data. The results of the data also repeat data multiple lines with the same info. Any suggestions? I tried changing the join clauses but that didn't help much. I'm not sure what else I could use to shorten the query to make it run smoother and get better results.
select
PT_IDENTIFIER.PT_IDENTIFIER_VALUE,
PT_STUDY.FK_SOCRD_ID,
patient.PTLASTNAME || ', ' || patient.PTFIRSTNAME as "Patient name",
patient.DOB,
PT_STUDY.SUBJECT_NUMBER,
CR_imaging.CR_IMAGING as "CR_Imaging",
CR_imaging.CR_IMAGING_SPEC,
CR_IMAGING.CR_IMAGING_DT,
CR_imaging.CR_IMG_SITE,
CR_IMAGING.CR_IMG_SITE_SPEC,
CR_IMAGING.CR_IMAGING_CT,
CR_IMAGING.CR_IMAGING_CN,
CR_IMAGING.CR_IMAGING_CM,
CR_WORKUPPROC.CR_WORKUPPROC,
CR_WORKUPPROC.CR_WORKUPPROC_DT,
CR_DISEASE_HISTORY.CR_DISEASE_HISTORY,
CR_DISEASE_HISTORY.CR_DISEASE_HISTORY_DT,
CR_MDT.CR_MDT_DT,
CR_MDT.CR_MDT_DIAG,
CR_MDT.CR_MDT_PHYS,
CR_MDT.CR_MDT_PRESENTED,
CR_MDT.CR_MDT_HISTTYPE,
CR_MDT.CR_MDT_STAGE,
CR_MDT.CR_MDT_CT,
CR_MDT.CR_MDT_CN,
CR_MDT.CR_MDT_CM,
CR_MDT.CR_MDT_PT,
CR_MDT.CR_MDT_PN,
CR_MDT.CR_MDT_PM,
CR_MDT.CR_MDT_LOOKBACK,
CR_MDT_PATH_REVIEW_DT,
CR_MDT_PATH_REVIEW,
CR_MDT_RECOM.CR_MDT_RECOM,
CR_MDT_RECOM.CR_MDT_RECOM_SPEC,
TUMORSITE.DIAGNOSIS_DT,
TUMORSITE.TUMORSITE,
TUMORSITE.TUMORSITE_SPEC,
TUMORSITE.RECURRENCE_DT,
TUMORSITE.RECURRENCE_DT_EST,
TUMORSITE.METASTASIS_DT,
TUMORSITE.METASTASIS_DT_EST,
CR_SYSTEMIC.CR_AGENT,
CR_SYSTEMIC.CR_AGENT_SPEC,
CR_SYSTEMIC.CR_SYS_CYCLE,
CR_SYSTEMIC.CR_SYS_DOSE_DAY,
CR_SYSTEMIC.CR_SYS_DOSE_TOTAL,
CR_SYSTEMIC.CR_SYS_START_DT,
CR_SYSTEMIC.CR_SYS_START_DT_EST,
CR_SYSTEMIC.CR_SYS_END_DT,
CR_SYSTEMIC.CR_SYS_END_DT_EST,
CR_RADIATION.CR_RAD_START_DT,
CR_RADIATION.CR_RAD_START_DT_EST,
CR_RADIATION.CR_RAD_END_DT,
CR_RADIATION.CR_RAD_END_DT_EST,
CR_RADIATION.CR_RAD_PHYS,
CR_RADIATION.CR_RAD_DOSE,
CR_RADIATION.CR_RAD_NOTES,
CR_SURGERY.CR_SURGERY_DT,
CR_SURGERY.CR_SURGERY,
CR_SURGERY.CR_SURGEON,
CR_SURGERY.CR_SURGERY_DT_EST,
CR_SURGERY.CR_SURG_APPROACH,
CR_SURGERY.CR_SURGERY_SPEC,
CR_PATHOLOGY.CR_SURG_PT,
CR_PATHOLOGY.CR_SURG_PN,
CR_PATHOLOGY.CR_SURG_PM,
CR_PATHOLOGY.CR_SURG_HISTTYPE,
CR_PATHOLOGY.CR_SURG_TME,
CR_PATHOLOGY.CR_SURG_TME_REASON,
CR_PATHOLOGY.CR_SURG_TME_REASON_SPEC,
CR_PATHOLOGY.CR_SURG_DISTAL,
CR_PATHOLOGY.CR_SURG_MSI,
CR_PATHOLOGY.CR_SURG_CRM,
CR_PATHOLOGY.CR_SURG_PROX_DIST,
FU_STATUS.FU_DT,
FU_STATUS.FU_STATUS,
FU_STATUS.FU_CANCERSTATUS,
CR_LAB.CR_LAB_DT,
CR_LAB_TUMORMARKER.CR_LAB_TUMORMARKER,
CR_DISEASE_HISTORY.CR_FAM_HISTORY,
CR_GENTEST.CR_GENTEST,
CR_GENTEST.CR_GENTEST_SPEC,
CR_GENTEST.CR_GENTEST_DT,
CR_GENTEST.CR_GENTEST_RESULT
from
CR_IMAGING
left join patient
on CR_IMAGING.fk_SOCRD_ID=patient.SOCRD_ID
left join PT_IDENTIFIER
on patient.socrd_id=PT_IDENTIFIER.FK_SOCRD_ID
left join PT_STUDY
on patient.SOCRD_ID=PT_STUDY.FK_SOCRD_ID
left join CR_DISEASE_HISTORY
on CR_DISEASE_HISTORY.FK_SOCRD_ID=patient.SOCRD_ID
left join CR_MDT
on CR_MDT.FK_SOCRD_ID=PATIENT.SOCRD_ID
left join CR_MDT_RECOM
on CR_MDT.CR_MDT_ID=CR_MDT_RECOM.FK_CR_MDT_ID
left join tumorsite
on tumorsite.FK_SOCRD_ID=PATIENT.SOCRD_ID
left join CR_SYSTEMIC
on CR_SYSTEMIC.FK_SOCRD_ID=PATIENT.SOCRD_ID
left join CR_RADIATION
on CR_RADIATION.FK_SOCRD_ID=PATIENT.SOCRD_ID
left join CR_SURGERY
on CR_SURGERY.FK_SOCRD_ID=PATIENT.SOCRD_ID
LEFT JOIN FU_STATUS
ON FU_STATUS.FK_SOCRD_ID=PATIENT.SOCRD_ID
LEFT JOIN CR_LAB
ON CR_LAB.FK_SOCRD_ID=PATIENT.SOCRD_ID
LEFT JOIN CR_LAB_TUMORMARKER
ON CR_LAB_TUMORMARKER.FK_CR_LAB_ID=CR_LAB.CR_LAB_ID
left join CR_PATHOLOGY
on CR_PATHOLOGY.FK_CR_SURGERY_ID=CR_SURGERY.CR_SURGERY_ID,
cr_workupproc CR_WORKUPPROC
where cr_workupproc.FK_SOCRD_ID=patient.SOCRD_ID
and CR_DISEASE_HISTORY.FK_SOCRD_ID=patient.SOCRD_ID
and PT_STUDY=3
GROUP BY PT_STUDY.SUBJECT_NUMBER,
patient.PTLASTNAME, patient.PTFIRSTNAME,
CR_imaging.CR_IMAGING,
CR_IMAGING.CR_IMAGING_DT, patient.DOB,
CR_imaging.CR_IMG_SITE,
CR_IMAGING.CR_IMG_SITE_SPEC,
CR_imaging.CR_IMAGING_SPEC,
CR_IMAGING.CR_IMAGING_CT,
CR_IMAGING.CR_IMAGING_CN,
CR_IMAGING.CR_IMAGING_CM,
CR_WORKUPPROC.CR_WORKUPPROC,
CR_WORKUPPROC.CR_WORKUPPROC_DT,
CR_DISEASE_HISTORY.CR_DISEASE_HISTORY,
CR_DISEASE_HISTORY.CR_DISEASE_HISTORY_DT,
CR_MDT_RECOM.CR_MDT_RECOM,
CR_MDT.CR_MDT_DT,
CR_MDT.CR_MDT_PHYS,
CR_MDT.CR_MDT_PRESENTED,
CR_MDT.CR_MDT_HISTTYPE,
CR_MDT.CR_MDT_STAGE,
CR_MDT.CR_MDT_CT,
CR_MDT.CR_MDT_CN,
CR_MDT.CR_MDT_CM,
CR_MDT.CR_MDT_LOOKBACK,
CR_MDT.CR_MDT_PT,
CR_MDT.CR_MDT_PN,
CR_MDT.CR_MDT_PM,
CR_MDT_PATH_REVIEW_DT,
CR_MDT_PATH_REVIEW,
TUMORSITE.TUMORSITE,
TUMORSITE.TUMORSITE_SPEC,
TUMORSITE.RECURRENCE_DT,
TUMORSITE.RECURRENCE_DT_EST,
TUMORSITE.METASTASIS_DT,
TUMORSITE.METASTASIS_DT_EST,
CR_SYSTEMIC.CR_AGENT,
CR_SYSTEMIC.CR_AGENT_SPEC,
CR_SYSTEMIC.CR_SYS_CYCLE,
CR_SYSTEMIC.CR_SYS_DOSE_DAY,
CR_SYSTEMIC.CR_SYS_DOSE_TOTAL,
CR_SYSTEMIC.CR_SYS_START_DT,
CR_SYSTEMIC.CR_SYS_START_DT_EST,
CR_SYSTEMIC.CR_SYS_END_DT,
CR_SYSTEMIC.CR_SYS_END_DT_EST,
CR_RADIATION.CR_RAD_START_DT,
CR_RADIATION.CR_RAD_START_DT_EST,
CR_RADIATION.CR_RAD_END_DT,
CR_RADIATION.CR_RAD_END_DT_EST,
CR_RADIATION.CR_RAD_PHYS,
CR_RADIATION.CR_RAD_DOSE,
CR_RADIATION.CR_RAD_NOTES,
CR_SURGERY.CR_SURGERY_DT,
CR_SURGERY.CR_SURGERY,
CR_SURGERY.CR_SURGEON,
CR_SURGERY.CR_SURGERY_DT_EST,
CR_SURGERY.CR_SURG_APPROACH,
CR_PATHOLOGY.CR_SURG_PT,
CR_PATHOLOGY.CR_SURG_PN,
CR_PATHOLOGY.CR_SURG_PM,
CR_PATHOLOGY.CR_SURG_HISTTYPE,
CR_PATHOLOGY.CR_SURG_TME,
CR_PATHOLOGY.CR_SURG_TME_REASON,
CR_PATHOLOGY.CR_SURG_TME_REASON_SPEC,
CR_PATHOLOGY.CR_SURG_DISTAL,
CR_PATHOLOGY.CR_SURG_MSI,
CR_PATHOLOGY.CR_SURG_CRM,
CR_PATHOLOGY.CR_SURG_PROX_DIST,
PT_STUDY.FK_SOCRD_ID,
CR_MDT.CR_MDT_DIAG,
FU_STATUS.FU_DT,
FU_STATUS.FU_STATUS,
FU_STATUS.FU_CANCERSTATUS,
PT_IDENTIFIER_VALUE,
CR_MDT_RECOM.CR_MDT_RECOM_SPEC,
TUMORSITE.DIAGNOSIS_DT,
CR_LAB.CR_LAB_DT,
CR_LAB_TUMORMARKER.CR_LAB_TUMORMARKER,
CR_SURGERY.CR_SURGERY_SPEC
difficult to say without knowing more about your tables and data.
Its probably better (if only for readability) not to mix your join methods, so i'd convert the inner join to
inner join cr_workupproc on cr_workupproc.FK_SOCRD_ID=patient.SOCRD_ID
and CR_DISEASE_HISTORY.FK_SOCRD_ID
your only filter in the query is
and PT_STUDY=3
but pt_study seems to be a table or is this also a column on some table? if so its probably better to be explicit as to where it is with a table qualifier.
If this is not a column on cr_imaging table, then you probably need to check your table order, as you are probably doing a number of full table scans.
Also you should get an explain plan for the query to see what it is doing which may help you to optimise the query.

MS Access SQL - How do I fix my Joins?

I'm not familiar with MS Access 2003-2007 SQL, but I have to maintain/extend a project that uses it. (The original author has left the company. Hooray for legacy code.) What I'm trying to do is join a number of related tables so that the query gives me the number of transactions for a particular user within a particular time range. The end result of this is that I want to see how many hours passed between an OUT event and the previous IN event for that user.
The code I have so far is as follows:
SELECT Directions.DirectionText, Transactions.Timestamp
FROM Users
LEFT JOIN AccessNumbers ON Users.AccessNumberID = AccessNumbers.AccessNumberID
LEFT JOIN Transactions ON AccessNumbers.Number = Transactions.Number
LEFT JOIN Events ON Transactions.Event = Events.EventNumber
LEFT JOIN Readers ON Transactions.ReaderID = Readers.ReaderID
LEFT JOIN Directions ON Readers.Direction = Direction.Direction
WHERE
(Events.EventNum IN (1, 22)) AND
(Users.[Name] = "firstName") AND
(Users.Surname = "Surname") AND
(Transactions.Timestamp >=#2017-04-10 01:00:00#) AND
(Transactions.Timestamp <=#2017-05-09 14:57:30#)
ORDER BY Transactions.Timestamp
The error I receive is "Syntax Error (missing operator in query expression 'Users.AccessNumberID = ... Direction.Direction'
I have also tried the following, to receive "Syntax Error on JOIN operation':
SELECT Directions.DirectionText, Transactions.Timestamp
FROM Users
LEFT JOIN (AccessNumbers ON Users.AccessNumberID =
AccessNumbers.AccessNumberID)
ON (AccessNumbers.Number = Transactions.Number)
ON (Transactions.Event = Events.EventNumber)
ON (Transactions.ReaderID = Readers.ReaderID)
ON (Readers.Direction = Direction.Direction)
WHERE ...
I'm aware that the SQL needs parentheses, but I don't know where to place them.
I've had issues with Access trying to put in my parentheses for me in the past... especially with LEFT joins. I'd normally parenthesize your first query like so:
SELECT Directions.DirectionText, Transactions.Timestamp
FROM ((((Users
LEFT JOIN AccessNumbers ON Users.AccessNumberID = AccessNumbers.AccessNumberID)
LEFT JOIN Transactions ON AccessNumbers.Number = Transactions.Number)
LEFT JOIN Events ON Transactions.Event = Events.EventNumber)
LEFT JOIN Readers ON Transactions.ReaderID = Readers.ReaderID)
LEFT JOIN Directions ON Readers.Direction = Directions.Direction
WHERE
(Events.EventNum IN (1, 22)) AND
(Users.[Name] = "firstName") AND
(Users.Surname = "Surname") AND
(Transactions.Timestamp >=#2017-04-10 01:00:00#) AND
(Transactions.Timestamp <=#2017-05-09 14:57:30#)
ORDER BY Transactions.Timestamp
Your second query would need more LEFT JOIN clauses thrown in to function.
A simple trick is the following:
Add a closing parenthesis before each LEFT beyond the first.
Add an opening parenthesis after FROM for each LEFT beyond the first.
Result:
SELECT Directions.DirectionText, Transactions.Timestamp
FROM ((((Users
LEFT JOIN AccessNumbers ON Users.AccessNumberID = AccessNumbers.AccessNumberID
) LEFT JOIN Transactions ON AccessNumbers.Number = Transactions.Number
) LEFT JOIN Events ON Transactions.Event = Events.EventNumber
) LEFT JOIN Readers ON Transactions.ReaderID = Readers.ReaderID
) LEFT JOIN Directions ON Readers.Direction = Direction.Direction
WHERE
(Events.EventNum IN (1, 22)) AND
(Users.[Name] = "firstName") AND
(Users.Surname = "Surname") AND
(Transactions.Timestamp >=#2017-04-10 01:00:00#) AND
(Transactions.Timestamp <=#2017-05-09 14:57:30#)
ORDER BY Transactions.Timestamp
The result is the same as Sturgus says, but adding them this way makes sense to me. For layout purposes, you might move each closing parenthesis to the line above it.

Ignore null values in select statement

I'm trying to retrieve a list of components via my computer_system, BUT if a computer system's graphics card is set to null (I.e. It has an onboard), the row isn't returned by my select statement.
I've been trying to use COALESCE without results. I've also tried with and OR in my WHERE clause, which then just returns my computer system with all different kinds of graphic cards.
Relevant code:
SELECT
computer_system.cs_id,
computer_system.cs_name,
motherboard.name,
motherboard.price,
cpu.name,
cpu.price,
gfx.name,
gfx.price
FROM
public.computer_case ,
public.computer_system,
public.cpu,
public.gfx,
public.motherboard,
public.ram
WHERE
computer_system.cs_ram = ram.ram_id AND
computer_system.cs_cpu = cpu.cpu_id AND
computer_system.cs_mb = motherboard.mb_id AND
computer_system.cs_case = computer_case.case_id AND
computer_system.cs_gfx = gfx.gfx_id; <-- ( OR computer_system.cs_gfx IS NULL)
Returns:
1;"Computer1";"Fractal Design"; 721.00; "MSI Z87"; 982.00; "Core i7 I7-4770K "; 2147.00; "Crucial Gamer"; 1253.00; "ASUS GTX780";3328.00
Should I use Joins? Is there no easy way to say return the requested row, even if there's a bloody NULL value. Been struggling with this for at least 2 hours.
Tables will be posted if needed.
EDIT: It should return a second row:
2;"Computer2";"Fractal Design"; 721.00; "MSI Z87"; 982.00; "Core i7 I7-4770K "; 2147.00; "Crucial Gamer"; 1253.00; "null/nothing";null/nothing
You want a LEFT OUTER JOIN.
First, clean up your code so you use ANSI joins so it's readable:
SELECT
computer_system.cs_id,
computer_system.cs_name,
motherboard.name,
motherboard.price,
cpu.name,
cpu.price,
gfx.name,
gfx.price
FROM
public.computer_system
INNER JOIN public.computer_case ON computer_system.cs_case = computer_case.case_id
INNER JOIN public.cpu ON computer_system.cs_cpu = cpu.cpu_id
INNER JOIN public.gfx ON computer_system.cs_gfx = gfx.gfx_id
INNER JOIN public.motherboard ON computer_system.cs_mb = motherboard.mb_id
INNER JOIN public.ram ON computer_system.cs_ram = ram.ram_id;
Then change the INNER JOIN on public.gfx to a LEFT OUTER JOIN:
LEFT OUTER JOIN public.gfx ON computer_system.cs_gfx = gfx.gfx_id
See PostgreSQL tutorial - joins.
I very strongly recommend reading an introductory tutorial to SQL - at least the PostgreSQL tutorial, preferably some more material as well.
It looks like it's just a bracket placement issue. Pull the null check and the graphics card id comparison into a clause by itself.
...
computer_system.cs_case = computer_case.case_id AND
(computer_system.cs_gfx IS NULL OR computer_system.cs_gfx = gfx.gfx_id)
Additionally, you ask if you should use joins. You are in fact using joins, by virtue of having multiple tables in your FROM clause and specifying the join criteria in the WHERE clause. Changing this to use the JOIN ON syntax might be a little easier to read:
FROM sometable A
JOIN someothertable B
ON A.somefield = B.somefield
JOIN somethirdtable C
ON A.somefield = C.somefield
etc
Edit:
You also likely want to make the join where you expect the null value to be a left outer join:
SELECT * FROM
first_table a
LEFT OUTER JOIN second_table b
ON a.someValue = b.someValue
If there is no match in the join, the row from the left side will still be returned.

Need help optimizing this tSQL Query

I'm definitely not a DBA and unfortunately we don't have a DBA to consult within at our company. I was wondering if someone could give me a recommendation on how to improve this query, either by changing the query itself or adding indexes to the database.
Looking at the execution plan of the query it seems like the outer joins are killing the query. This query only returns 350k results, but it takes almost 30 seconds to complete. I don't know much about DB's, but I don't think this is good? Perhaps I'm wrong?
Any suggestions would be greatly appreciated. Thanks in advance.
As a side note this is obviously being create by an ORM and not me directly. We are using Linq-to-SQL.
SELECT
[t12].[value] AS [DiscoveryEnabled],
[t12].[value2] AS [isConnected],
[t12].[Interface],
[t12].[Description] AS [InterfaceDescription],
[t12].[value3] AS [Duplex],
[t12].[value4] AS [IsEnabled],
[t12].[value5] AS [Host],
[t12].[value6] AS [HostIP],
[t12].[value7] AS [MAC],
[t12].[value8] AS [MACadded],
[t12].[value9] AS [PortFast],
[t12].[value10] AS [PortSecurity],
[t12].[value11] AS [ShortHost],
[t12].[value12] AS [SNMPlink],
[t12].[value13] AS [Speed],
[t12].[value14] AS [InterfaceStatus],
[t12].[InterfaceType],
[t12].[value15] AS [IsUserPort],
[t12].[value16] AS [VLAN],
[t12].[value17] AS [Code],
[t12].[Description2] AS [Description],
[t12].[Host] AS [DeviceName],
[t12].[NET_OUID],
[t12].[DisplayName] AS [Net_OU],
[t12].[Enclave]
FROM (
SELECT
[t1].[DiscoveryEnabled] AS [value],
[t1].[IsConnected] AS [value2],
[t0].[Interface],
[t0].[Description],
[t2].[Duplex] AS [value3],
[t0].[IsEnabled] AS [value4],
[t3].[Host] AS [value5],
[t6].[Address] AS [value6],
[t3].[MAC] AS [value7],
[t3].[MACadded] AS [value8],
[t2].[PortFast] AS [value9],
[t2].[PortSecurity] AS [value10],
[t4].[Host] AS [value11],
[t0].[SNMPlink] AS [value12],
[t2].[Speed] AS [value13],
[t2].[InterfaceStatus] AS [value14],
[t8].[InterfaceType],
[t0].[IsUserPort] AS [value15],
[t2].[VLAN] AS [value16],
[t9].[Code] AS [value17],
[t9].[Description] AS [Description2],
[t7].[Host], [t7].[NET_OUID],
[t10].[DisplayName],
[t11].[Enclave],
[t7].[Decommissioned]
FROM [dbo].[IDB_Interface] AS [t0]
LEFT OUTER JOIN [dbo].[IDB_InterfaceLayer2] AS [t1] ON [t0].[IDB_Interface_ID] = [t1].[IDB_Interface_ID]
LEFT OUTER JOIN [dbo].[IDB_LANinterface] AS [t2] ON [t1].[IDB_InterfaceLayer2_ID] = [t2].[IDB_InterfaceLayer2_ID]
LEFT OUTER JOIN [dbo].[IDB_Host] AS [t3] ON [t2].[IDB_LANinterface_ID] = [t3].[IDB_LANinterface_ID]
LEFT OUTER JOIN [dbo].[IDB_Infrastructure] AS [t4] ON [t0].[IDB_Interface_ID] = [t4].[IDB_Interface_ID]
LEFT OUTER JOIN [dbo].[IDB_AddressMapIPv4] AS [t5] ON [t3].[IDB_AddressMapIPv4_ID] = ([t5].[IDB_AddressMapIPv4_ID])
LEFT OUTER JOIN [dbo].[IDB_AddressIPv4] AS [t6] ON [t5].[IDB_AddressIPv4_ID] = [t6].[IDB_AddressIPv4_ID]
INNER JOIN [dbo].[ART_Asset] AS [t7] ON [t7].[ART_Asset_ID] = [t0].[ART_Asset_ID]
LEFT OUTER JOIN [dbo].[NSD_InterfaceType] AS [t8] ON [t8].[NSD_InterfaceTypeID] = [t0].[NSD_InterfaceTypeID]
INNER JOIN [dbo].[NSD_InterfaceCode] AS [t9] ON [t9].[NSD_InterfaceCodeID] = [t0].[NSD_InterfaceCodeID]
INNER JOIN [dbo].[NET_OU] AS [t10] ON [t10].[NET_OUID] = [t7].[NET_OUID]
INNER JOIN [dbo].[NET_Enclave] AS [t11] ON [t11].[NET_EnclaveID] = [t10].[NET_EnclaveID]
) AS [t12]
WHERE ([t12].[Enclave] = 'USMC') AND (NOT ([t12].[Decommissioned] = 1))
LINQ-TO-SQL Query:
return from t in db.IDB_Interfaces
join v in db.IDB_InterfaceLayer3s on t.IDB_Interface_ID equals v.IDB_Interface_ID
join u in db.ART_Assets on t.ART_Asset_ID equals u.ART_Asset_ID
join c in db.NET_OUs on u.NET_OUID equals c.NET_OUID
join w in
(from d in db.IDB_InterfaceIPv4s
select new { d.IDB_InterfaceIPv4_ID, d.IDB_InterfaceLayer3_ID, d.IDB_AddressMapIPv4_ID, d.IDB_AddressMapIPv4.IDB_AddressIPv4.Address })
on v.IDB_InterfaceLayer3_ID equals w.IDB_InterfaceLayer3_ID
join h in db.NET_Enclaves on c.NET_EnclaveID equals h.NET_EnclaveID into enclaveLeftJoin
from i in enclaveLeftJoin.DefaultIfEmpty()
join m in
(from z in db.IDB_StandbyIPv4s
select new
{
z.IDB_InterfaceIPv4_ID,
z.IDB_AddressMapIPv4_ID,
z.IDB_AddressMapIPv4.IDB_AddressIPv4.Address,
z.Preempt,
z.Priority
})
on w.IDB_InterfaceIPv4_ID equals m.IDB_InterfaceIPv4_ID into standbyLeftJoin
from k in standbyLeftJoin.DefaultIfEmpty()
where t.ART_Asset.Decommissioned == false
select new NetIDBGridDataResults
{
DeviceName = u.Host,
Host = u.Host,
Interface = t.Interface,
IPAddress = w.Address,
ACLIn = v.InboundACL,
ACLOut = v.OutboundACL,
VirtualAddress = k.Address,
VirtualPriority = k.Priority,
VirtualPreempt = k.Preempt,
InterfaceDescription = t.Description,
Enclave = i.Enclave
};
As a rule (and this is very general), you want an index on:
JOIN fields (both sides)
Common WHERE filter fields
Possibly fields you aggregate
For this query, start with checking your JOIN criteria. Any one of those missing will force a table scan which is a big hit.
Looking at the execution plan of the query it seems like the outer joins are killing the query.
This query only returns 350k results, but it takes almost 30 seconds to complete. I don't know
much about DB's, but I don't think this is good? Perhaps I'm wrong?
A man has got to do waht a mana has got to do.
The joins may kill you, but when you need them YOU NEED THEM. Some tasks take long.
Make sure you ahve all indices you need.
Make sure your sql server is not a sad joke hardware wise.
All you can do.
I woudl bet someone has no clue about SQL and needs to be enlighted to the power of indices.