Joining two tables on a key and then left outer joining a table on a number of criteria - sql

I'm attempting to join 3 tables together in a single query. The first two have a key so each entry has a matching entry. This joined table will then be joined by a third table that could produce multiple entries for each entry from the first table (the joined ones).
select * from
(select a.bidentifier, a.bsession, a.symbol, b.jidentifier, b.JSession
from trade_monthly a, trade_monthly_second b
where
a.bidentifier = b.jidentifier AND
a.bsession = b.JSession)
left outer join
trade c
on c.symbol = a.symbol
order by a.bidentifier, a.bsession, a.symbol, b.jidentifier, b.JSession, c.symbol
There will be more criteria (not just c.symbol = a.symbol) on the left outer join but for now this should be useful. How can I nest the queries this way? I'm gettin gan SQL command not properly ended error.
Any help is appreciated.
Thanks

For what I know every derived table must be given a name; so try something like this:
SELECT * FROM
(SELECT a.bidentifier, ....
...
a.bsession = b.JSession) t
LEFT JOIN trade c
ON c.symbol = t.symbol
ORDER BY t.bidentifier, ...
Anyway I think you could use a simpler query:
SELECT a.bidentifier, a.bsession, a.symbol, b.jidentifier, b.JSession, c.*
FROM trade_monthly a
INNER JOIN trade_monthly_second b
ON a.bidentifier = b.jidentifier
AND a.bsession = b.JSession
LEFT JOIN trade c
ON c.symbol = a.symbol
ORDER BY a.bidentifier, a.bsession, a.symbol, b.jidentifier, b.JSession, c.symbol

Try this:
SELECT
`trade_monthly`.`bidentifier` AS `bidentifier`,
`trade_monthly`.`bsession` AS `bsession`,
`trade_monthly`.`symbol` AS `symbol`,
`trade_monthly_second`.`jidentifier` AS `jidentifier`,
`trade_monthly_second`.`jsession` AS `jsession`
FROM
(
(
`trade_monthly`
JOIN `trade_monthly_second` ON(
(
(
`trade_monthly`.`bidentifier` = `trade_monthly_second`.`jidentifier`
)
AND(
`trade_monthly`.`bsession` = `trade_monthly_second`.`jsession`
)
)
)
)
JOIN `trade` ON(
(
`trade`.`symbol` = `trade_monthly`.`symbol`
)
)
)
ORDER BY
`trade_monthly`.`bidentifier`,
`trade_monthly`.`bsession`,
`trade_monthly`.`symbol`,
`trade_monthly_second`.`jidentifier`,
`trade_monthly_second`.`jsession`,
`trade`.`symbol`

Why don't you just create a view of the two inner joined tables. Then you can build a query that joins this view to the trade table using the left outer join matching criteria.
In my opinion, views are one of the most overlooked solutions to a lot of complex queries.

Related

Oracle compare query results with multiple joins against a table

I need to compare query results against a table. I have the following query.
select
i.person_id,
a.appellant_first_name,
a.appellant_middle_name,
a.appellant_last_name,
s.*
from CWLEGAL.individuals i inner join CWLEGAL.tblappealsdatarevisionone a
on i.casenm = a.D_N_NUMBER1 and
i.first_name = a.appellant_first_name and
i.last_name = a.appellant_last_name
inner join CWLEGAL.tblappealstosupremecourt s
on a.DATABASEIDNUMBER = s.DBIDNUMBER
order by orclid21;
I need to see what orclid21's in cwlegal.tblappealstosupremecourt don't appear in the above query.
I was able to get this to work.
select
i.person_id,
a.appellant_first_name,
a.appellant_middle_name,
a.appellant_last_name,
s.*
from CWLEGAL.tblappealstosupremecourt s
join CWLEGAL.tblappealsdatarevisionone a
on a.DATABASEIDNUMBER = s.DBIDNUMBER
left outer join CWLEGAL.individuals i on
i.casenm = a.D_N_NUMBER1 and
i.first_name = a.appellant_first_name and
i.last_name = a.appellant_last_name
where person_id is null
order by orclid21
You are making the first inner join between i and a, the result of which you're joining with s.
Now, if you want to see which records won't join, that's known as anti-join, and in whatever database you're querying it, it may be achieved by either selecting a null result or taking those records as a new result.
Examples, with taking your query (the whole code in the question) as q, assuming you've kept all the needed keys in it:
Example 1:
with your_query as q
select s.orclid21 from q
left join CWLEGAL.tblappealstosupremecourt s
on q.DATABASEIDNUMBER = s.DBIDNUMBER
and s.orclid21 is null
Example 2:
with your_query as q
select s.orclid21 from q
right join CWLEGAL.tblappealstosupremecourt s
on q.DATABASEIDNUMBER != s.DBIDNUMBER
Example 3:
with your_query as q
select s.orclid21 from CWLEGAL.tblappealstosupremecourt s
where s.DBIDNUMBER not in (select distinct q.DATABASEIDNUMBER from q)

Join or match value from two tables

I have two tables . Based on the first table I need to check if it is locked or not.
In the below example , if the combination is present then I would pick else it should match with 'All' and bring that record.
Lock Table
Transaction Table
Output
Query tried - But it is doing a cross join . I understand the reason but could not solve it
SELECT a.GROUP,a.OFFICE,b.LOCK
FROM T_ITEMS a INNER JOIN LOCKED_T b
ON a.ORG=c.ORG
AND (a.OFFICE =b.OFFICE OR b.OFFICE='All')
AND a.GROUP=b.GROUP
What you want to do is match on group or use all as a "wildcard". The problem is that you are matching on both for one of the items -- so you get two results.
So what you do is the first join
SELECT a.GROUP, a.OFFICE, b.LOCK
FROM T_ITEMS a
LEFT JOIN LOCKED_T b ON a.ORG = c.ORG A
AND a.OFFICE = b.OFFICE
AND a.GROUP = b.GROUP
Now take those results and try to fill in the missing ones (missing ones will have a null in the lock column
SELECT
BASE.GROUP, BASE.OFFICE, COLLESCE(BASE.LOCK, L.LOCK) AS LOCK
FROM
(SELECT
a.GROUP, a.OFFICE, b.LOCK
FROM
T_ITEMS a
LEFT JOIN
LOCKED_T b ON a.ORG = c.ORG
AND a.OFFICE = b.OFFICE
AND a.GROUP = b.GROUP) BASE
LEFT JOIN
LOCKED_T L ON BASE.ORG = L.ORG
AND L.OFFICE = 'All'
AND base.GROUP = L.GROUP
AND BASE.LOCK IS NULL
I look at this as a "defaulting" problem. That can be solved with two left joins:
SELECT i.GROUP, i.OFFICE,
COALESCE(l.LOCK, l_default.LOCK)
FROM T_ITEMS i LEFT JOIN
LOCKED_T l
ON l.ORG = i.ORG AND l.OFFICE = i.OFFICE LEFT JOIN
LOCKED_T l_default
ON l_default.OFFICE = 'All' AND l_default.GROUP = i.GROUP AND l.ORG IS NULL;
As the number of combinations grows, this gets trickier. So a more generalizable alternative uses a correlated subquery:
SELECT i.*,
(SELECT MAX(l.LOCK) KEEP (DENSE_RANK FIRST ORDER BY NULLIF(l.OFFICE, 'All) NULLS LAST,NULLIF(l.GROUP, 'All) NULLS LAST
FROM LOCKED_T l
WHERE (l.OFFICE = i.OFFICE OR l.OFFICE = 'All') AND
(l.GROUP = i.GROUP OR l.GROUP = 'All')
) as LOCKED
FROM T_ITEMS i;
Oracle 12C supports lateral joins so this can actually be in the FROM clause instead.

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.

select columns from different tables with different data type columns

I want to know how to write a query, which selects specific columns(not common) from 2 different tables and combine them together.
I tried this, but didn't work:
SELECT ii.sequence
FROM Costs ii
WHERE ii.order_ID IN (SELECT book.order_ID
FROM BookInfo ci
WHERE ii.order_ID = ci.order_ID)
UNION
SELECT ft.released_title
FROM FinishedBook ft
WHERE ft.version IN (SELECT ii.iiversion
FROM Costs ii
WHERE ii.iiorder_ID IN (SELECT ci.order_ID
FROM BookInfo ci
WHERE ii.iiorder_ID = ci.order_ID))
ORDER BY sequence;
Isn't this a case of joining these tables and calling Distinct to avoid duplicates?
Try this:
select Distinct a.Sequence, b.RELEASED_TITLE
from IncludedIn a inner join FinishedTrack b
on a.OriginatesFrom = b.IIOriginatesFrom
Inner join CdInfo c on a.IIALBUM_ID = c.ALBUM_ID
Order By a.Sequence
For MSSQL Server, Use Join to get the result.
SELECT I.Sequence, F.Released_Title FROM FinishedTrack AS F
INNER JOIN IncludedIn AS I ON I.ORIGINATESFROM = F.IIORIGINATESFROM
INNER JOIN CdInfo AS A ON A.ALBUM_ID = I.IIALBUM_ID
ORDER BY I.Sequence DESC
You need to use a JOIN instead of a UNION:
SELECT ii.sequence, ft.released_title
FROM IncludedIn ii
INNER JOIN CdInfo ci ON ii.iialbumid = ci.album_id
INNER JOIN FinishedTrack ft on ft.originatesfrom = ii.iioriginatesfrom
ORDER BY ii.sequence;
This query might work for you
SELECT IncludedIn.SEQUENCE, FinishedTrack.RELEASED_TITLE
FROM FinishedTrack
INNER JOIN IncludedIn
ON FinishedTrack.ORIGINATESFROM=IncludedIn.IIORIGINATESFROM and
FinishedTrack.VERSION=IncludedIn.IIVERSION order by FinishedTrack.SEQUENCE;

Recursive query with outer joins?

I'm attempting the following query,
DECLARE #EntityType varchar(25)
SET #EntityType = 'Accessory';
WITH Entities (
E_ID, E_Type,
P_ID, P_Name, P_DataType, P_Required, P_OnlyOne,
PV_ID, PV_Value, PV_EntityID, PV_ValueEntityID,
PV_UnitValueID, PV_UnitID, PV_UnitName, PV_UnitDesc, PV_MeasureID, PV_MeasureName, PV_UnitValue,
PV_SelectionID, PV_DropDownID, PV_DropDownName, PV_DropDownOptionID, PV_DropDownOptionName, PV_DropDownOptionDesc,
RecursiveLevel
)
AS
(
-- Original Query
SELECT dbo.Entity.ID AS E_ID, dbo.EntityType.Name AS E_Type,
dbo.Property.ID AS P_ID, dbo.Property.Name AS P_Name, DataType.Name AS P_DataType, Required AS P_Required, OnlyOne AS P_OnlyOne,
dbo.PropertyValue.ID AS PV_ID, dbo.PropertyValue.Value AS PV_Value, dbo.PropertyValue.EntityID AS PV_EntityID, dbo.PropertyValue.ValueEntityID AS PV_ValueEntityID,
dbo.UnitValue.ID AS PV_UnitValueID, dbo.UnitOfMeasure.ID AS PV_UnitID, dbo.UnitOfMeasure.Name AS PV_UnitName, dbo.UnitOfMeasure.Description AS PV_UnitDesc, dbo.Measure.ID AS PV_MeasureID, dbo.Measure.Name AS PV_MeasureName, dbo.UnitValue.UnitValue AS PV_UnitValue,
dbo.DropDownSelection.ID AS PV_SelectionID, dbo.DropDown.ID AS PV_DropDownID, dbo.DropDown.Name AS PV_DropDownName, dbo.DropDownOption.ID AS PV_DropDownOptionID, dbo.DropDownOption.Name AS PV_DropDownOptionName, dbo.DropDownOption.Description AS PV_DropDownOptionDesc,
0 AS RecursiveLevel
FROM dbo.Entity
INNER JOIN dbo.EntityType ON dbo.EntityType.ID = dbo.Entity.TypeID
INNER JOIN dbo.Property ON dbo.Property.EntityTypeID = dbo.Entity.TypeID
INNER JOIN dbo.PropertyValue ON dbo.Property.ID = dbo.PropertyValue.PropertyID AND dbo.PropertyValue.EntityID = dbo.Entity.ID
INNER JOIN dbo.DataType ON dbo.DataType.ID = dbo.Property.DataTypeID
LEFT JOIN dbo.UnitValue ON dbo.UnitValue.ID = dbo.PropertyValue.UnitValueID
LEFT JOIN dbo.UnitOfMeasure ON dbo.UnitOfMeasure.ID = dbo.UnitValue.UnitOfMeasureID
LEFT JOIN dbo.Measure ON dbo.Measure.ID = dbo.UnitOfMeasure.MeasureID
LEFT JOIN dbo.DropDownSelection ON dbo.DropDownSelection.ID = dbo.PropertyValue.DropDownSelectedID
LEFT JOIN dbo.DropDownOption ON dbo.DropDownOption.ID = dbo.DropDownSelection.SelectedOptionID
LEFT JOIN dbo.DropDown ON dbo.DropDown.ID = dbo.DropDownSelection.DropDownID
WHERE dbo.EntityType.Name = #EntityType
UNION ALL
-- Recursive Query?
SELECT E2.E_ID AS E_ID, dbo.EntityType.Name AS E_Type,
dbo.Property.ID AS P_ID, dbo.Property.Name AS P_Name, DataType.Name AS P_DataType, Required AS P_Required, OnlyOne AS P_OnlyOne,
dbo.PropertyValue.ID AS PV_ID, dbo.PropertyValue.Value AS PV_Value, dbo.PropertyValue.EntityID AS PV_EntityID, dbo.PropertyValue.ValueEntityID AS PV_ValueEntityID,
dbo.UnitValue.ID AS PV_UnitValueID, dbo.UnitOfMeasure.ID AS PV_UnitID, dbo.UnitOfMeasure.Name AS PV_UnitName, dbo.UnitOfMeasure.Description AS PV_UnitDesc, dbo.Measure.ID AS PV_MeasureID, dbo.Measure.Name AS PV_MeasureName, dbo.UnitValue.UnitValue AS PV_UnitValue,
dbo.DropDownSelection.ID AS PV_SelectionID, dbo.DropDown.ID AS PV_DropDownID, dbo.DropDown.Name AS PV_DropDownName, dbo.DropDownOption.ID AS PV_DropDownOptionID, dbo.DropDownOption.Name AS PV_DropDownOptionName, dbo.DropDownOption.Description AS PV_DropDownOptionDesc,
(RecursiveLevel + 1)
FROM Entities AS E2
INNER JOIN dbo.Entity ON dbo.Entity.ID = E2.PV_ValueEntityID
INNER JOIN dbo.EntityType ON dbo.EntityType.ID = dbo.Entity.TypeID
INNER JOIN dbo.Property ON dbo.Property.EntityTypeID = dbo.Entity.TypeID
INNER JOIN dbo.PropertyValue ON dbo.Property.ID = dbo.PropertyValue.PropertyID AND dbo.PropertyValue.EntityID = E2.E_ID
INNER JOIN dbo.DataType ON dbo.DataType.ID = dbo.Property.DataTypeID
INNER JOIN dbo.UnitValue ON dbo.UnitValue.ID = dbo.PropertyValue.UnitValueID
INNER JOIN dbo.UnitOfMeasure ON dbo.UnitOfMeasure.ID = dbo.UnitValue.UnitOfMeasureID
INNER JOIN dbo.Measure ON dbo.Measure.ID = dbo.UnitOfMeasure.MeasureID
INNER JOIN dbo.DropDownSelection ON dbo.DropDownSelection.ID = dbo.PropertyValue.DropDownSelectedID
INNER JOIN dbo.DropDownOption ON dbo.DropDownOption.ID = dbo.DropDownSelection.SelectedOptionID
INNER JOIN dbo.DropDown ON dbo.DropDown.ID = dbo.DropDownSelection.DropDownID
)
SELECT E_ID, E_Type,
P_ID, P_Name, P_DataType, P_Required, P_OnlyOne,
PV_ID, PV_Value, PV_EntityID, PV_ValueEntityID,
PV_UnitValueID, PV_UnitID, PV_UnitName, PV_UnitDesc, PV_MeasureID, PV_MeasureName, PV_UnitValue,
PV_SelectionID, PV_DropDownID, PV_DropDownName, PV_DropDownOptionID, PV_DropDownOptionName, PV_DropDownOptionDesc,
RecursiveLevel
FROM Entities
INNER JOIN [dbo].[Entity] AS dE
ON dE.ID = PV_EntityID
The problem is the second query, the "recursive one" is getting the data I expect since I can't do the LEFT JOINs like in the first query. (At least to my understanding).
If I remove the fetching of the data that requires the LEFT (Outer) JOINs then the recursion works perfectly. My problem is I need both. Is there a way I can accomplish this?
Per http://msdn.microsoft.com/en-us/library/ms175972.aspx you can not have a left/right/outer join in a recursive CTE.
For a recursive CTE you can't use a subquery either so I sugest following this example.
They use two CTE's. The first is not recursive and does the left join to get the data it needs. The second CTE is recursive and inner joins on the first CTE. Since CTE1 is not recursive it can left join and supply default values for the missing rows and is guarenteed to work in the inner join.
However, you can also duplicate a left join with a union and subselect though it isn't really useful normally but it is interesting.
In that case, you would keep your first statement how it is. It will match all rows that join successfully.
Then UNION that query with another query that removes the join, but has a
NOT EXISTS(SELECT 1 FROM MISSING_ROWS_TABLE WHERE MAIN_TABLE.JOIN_CONDITION = MISSING_ROWS_TABLE.JOIN_CONDITION)
This gets all the rows that failed the previous join condition in query 1. You can replace the colmuns you would get from MISSING_ROWS_TABLE with NULL. I had to do this once using a coding framework that didn't support outer joins. Since recursive CTE's don't allow subqueries you have to use the first solution.