How to join Multiple - sql

This is the code example
for three tables and I made a link on them
Now I want to add the age column from table D
SELECT A.COD,a.namee, B.NAMEE,C.NAMEE
FROM ((A INNER JOIN B ON A.COD = B.COD)
LEFT JOIN C ON A.COD = C.COD)
I mean, this code is expected
SELECT A.COD, a.name , B.NAME,C.NAME ,D.Age
FROM ((A INNER JOIN B ON A.COD = B.COD)
LEFT JOIN C ON A.COD = C.COD) , D
But in access, an error message appears, the text of the message says that the JOIN method is not supported
Is there a way to solve this?

Access does not allow to do a direct cross-join (operator ",") involving an SQL expression that includes a different type of join. The solution is as simple as enclosing the first operation between parentheses and add another SELECT, as follows:
SELECT T_A.COD, T_A.Name_ , T_B.Name_, T_C.Name_, T_D.Age
FROM
(
SELECT T_A.COD, T_A.Name_ , T_B.Name_, T_C.Name_
FROM
( T_A
INNER JOIN
T_B
ON T_A.COD = T_B.COD)
LEFT JOIN
T_C
ON T_A.COD = T_C.COD
)
, T_D
My advice is that you always enclose in a SELECT every individual join operation (with the exception of cross-joins) as good programming practice. There is no problem in doing a series of cross-joins because the cross-join operator is associative.

Related

How to include column values as null even when condition is not met?

Write a query to show ALL building names, their metering company name and meter type for all buildings that do not have postpaid meters.
The image 1 is the result that I should get and image 2 is the results that i am getting:
USE Ultimate_DataBase
GO
SELECT [Bld_Name], [Elec_company_name], [Mtype_Name]
FROM [dbo].[Metering_Company] A
FULL OUTER JOIN [dbo].[Metering_Type] D
ON A.[MType_ID]= D.MType_ID
FULL OUTER JOIN [dbo].[Building_metering] B
ON A.[Elec_ID]= B.[Elec_ID]
FULL OUTER JOIN [dbo].[Building] C
ON C.[Bld_ID]= B.[Bld_ID]
WHERE [Mtype_Name] != 'POSTPAID'
Try moving the WHERE logic to the corresponding ON clause:
SELECT [Bld_Name], [Elec_company_name], [Mtype_Name]
FROM [dbo].[Metering_Company] A
FULL OUTER JOIN [dbo].[Metering_Type] D
ON A.[MType_ID]= D.MType_ID AND
[Mtype_Name] != 'POSTPAID' -- change is here
FULL OUTER JOIN [dbo].[Building_metering] B
ON A.[Elec_ID]= B.[Elec_ID]
FULL OUTER JOIN [dbo].[Building] C
ON C.[Bld_ID]= B.[Bld_ID];
Note: Please add aliases to your select clause. They are not mandatory, assuming no two tables ever have columns by the same name, but just having aliases would have made your question easier to answer.
FULL JOIN isn't seem necessary -- in fact FULL JOIN is almost never needed, and especially not for routine JOINs in a well-structured database.
The structure of the question suggests NOT EXISTS:
SELECT b.*
FROM dbo.Building b
WHERE NOT EXISTS (SELECT 1
FROM dbo.Building_metering bm JOIN
dbo.Metering_Company mc
ON bm.Elec_ID = mc.Elec_ID JOIN
dbo.Metering_Type mt
ON mt.MType_ID = mc.MType_ID
WHERE bm.Bld_ID = b.Bld_ID AND mt.Mtype_Name = 'POSTPAID'
);
You can also express this as a LEFT JOIN and filtering:
SELECT b.*
FROM dbo.Building b LEFT JOIN
dbo.Building_metering bm
ON bm.Bld_ID = b.Bld_ID LEFT JOIN
dbo.Metering_Company mc
ON bm.Elec_ID = mc.Elec_ID LEFT JOIN
dbo.Metering_Type mt
ON mt.MType_ID = mc.MType_ID AND
mt.Mtype_Name = 'POSTPAID'
WHERE mt.MType_ID IS NULL;
This allows you to select columns from any of the tables.
Notes:
FULL JOIN is almost never needed.
Use meaningful table aliases! Arbitrary letters mean nothing. Use table abbreviations.
Escaping column and table names with square braces just makes code harder to write and to read.
USE Ultimate_DataBase
GO
SELECT [Bld_Name], [Elec_company_name], [Mtype_Name]
FROM [dbo].[Metering_Company] A
LEFT JOIN [dbo].[Metering_Type] D
ON A.[MType_ID]= D.MType_ID
LEFT JOIN [dbo].[Building_metering] B
ON A.[Elec_ID]= B.[Elec_ID]
LEFT JOIN [dbo].[Building] C
ON C.[Bld_ID]= B.[Bld_ID]
Use this

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.

Using "With" SQL on Oracle 10g causing errors

First ill tell you what the logic in my code is, after my last post it was pointed out to me that my procedure was inefficient and that i should think about logic of my approach..
To put it simply, i want to join a bunch of tables and filter them out to reflect a certain scheme, the process in "Z" in the bellow code
And then parse through that data using y on z...
Looking at the examples online i cant see why this code dosnt work, i have read in a few places that it may be a oracle 10g issue but note sure.. any recommendations would be great
The error i get is "ORA-00904: "Z"."COMMENTS": invalid identifier"
with
z as
(
Select *
FROM
(
iacd_note c
inner join iacd_ncr_note e on C.NOTE_ID=E.NOTE_ID
inner join iacd_ncr f on E.NCR_ID=F.NCR_ID
inner join iacd_ncr_iac g on F.NCR_ID=G.NCR_ID
)
WHERE c.create_date >= date'2014-01-01'
AND c.create_date < date'2014-12-31'
AND G.SCHEME_ID in (36,37,38,25,26,27,28,29,30,31,32,33,34,35,39,40,44,42,43,45, 48,49,50,51,52,55,56,57,58,68,69,70,71)
),
y as
(
Select *
From iacd_asset
)
SELECT y.bridge_no, COUNT(*) AS comment_cnt
FROM y INNER JOIN z
ON REGEXP_LIKE(z.comments, '(^|\W)BN' || y.bridge_no || '(\W|$)', 'i')
GROUP BY y.bridge_no
ORDER BY comment_cnt;
Z.COMMENTS should be part of the merges happening in z
This subquery is invalid SQL syntax:
Select *
FROM
(
iacd_note c
inner join iacd_ncr_note e on C.NOTE_ID=E.NOTE_ID
inner join iacd_ncr f on E.NCR_ID=F.NCR_ID
inner join iacd_ncr_iac g on F.NCR_ID=G.NCR_ID
)
WHERE ...
You can't put parentheses around the FROM clause. Instead:
Select *
FROM iacd_note c
inner join iacd_ncr_note e on C.NOTE_ID=E.NOTE_ID
inner join iacd_ncr f on E.NCR_ID=F.NCR_ID
inner join iacd_ncr_iac g on F.NCR_ID=G.NCR_ID
WHERE ...
Looks like the output of a with clause may not have the same column names as the original tables, so i selected all of z and noticed there was an odd automated name for the row i was after...

How is resolved tables visibility in sql join

I have problems understanding the correct syntax of sql using explicit joins.
For example in the first snippet, in the second join "ec" is visible and the restriction works. But in the second snippet "op" cannot be resolved.
First snippet:
select im.*
from gestion_corte gc
join evento_corte ec
on ec.id_corte = gc.id_corte
join op_corte op
on op.id_corte = gc.id_corte
and op.fecha_evento = ec.fecha_evento
join img_corte im
on op.id_corte = im.id_corte
where ec.fecha_evento > '01092012'
Second snippet, "op" cannot be resolved in first join:
select im.*
from gestion_corte gc
join evento_corte ec
on ec.id_corte = gc.id_corte
and op.fecha_evento = ec.fecha_evento -- This condition has moved
join op_corte op
on op.id_corte = gc.id_corte
join img_corte im
on op.id_corte = im.id_corte
where ec.fecha_evento > '01092012'
In consequence, the visibility is resolved processing from top to bottom? are any other important thing to have in consideration?
In the SQL join syntax, an alias is not known until it is defined. So, you can do:
from A a join
B b
on a.val = b.val join
C c
on a.val = c.val
However, you cannot do:
from A a join
B b
on a.val = b.val and
a.id = c.id join
C c
on a.val = c.val
The SQL engine simply does not know what "c" is, because "c" has not been seen yet in the from statement.
You second query is easy to fix by moving the condition, as you discovered.
A join is between two virtual tables.
The join predicate can only refer to columns from these two virtual tables (though each virtual table may consist of columns from multiple base tables).
It is not necessarily the case that the order of valid usage is top down as the logical join order is determined by the order of the ON clauses. So for example in the following query (SQL Fiddle) the virtual table (a join b) is joined onto the virtual table (c join d join e)
SELECT *
FROM a
JOIN b
ON a.id = b.id /*Only a and b in scope here*/
JOIN c
JOIN d
ON c.id = d.id /*Only c and d in scope here*/
JOIN e
ON e.id = d.id /*Only c, d, e in scope here*/
ON d.id = a.id /*a,b,c,d,e all in scope*/
This query (SQL Fiddle) would give an error as a is not in scope there.
SELECT *
FROM a
JOIN b
ON a.id = b.id
JOIN c
JOIN d
ON c.id = d.id
JOIN e
ON e.id = a.id -- Can't reference a here
ON d.id = a.id
I don't get your second question, so I have only answer to first one.
Your joins can be imagined this way:
"result" = select "some columns" from "any source"
"any source" can be a table or a subquery (i.e. another "result") or "any source" join "any source":
"any source" = table | "result" | "any source" join "any source"
So if you want a "result" you should determine "any source" first then "some columns" (let's don't focus on it). Let's go to the "any source" definition to determine it. Table is determined, "result" recursively leads to prevprevious sentence and join construction has a rule - to determine it firstly get left "any source" then right.
join is a left associative operation and isn't a commutative operation generally (inner join and cross join are, but not the left join or right join).
So, look at your 2nd snippet. This part gestion_corte join evento_corte hasn't been calculated because of op_corte hasn't been determined yet

Alternatives to full outer join for logical OR in tree structure query

I hope the title is clear enough. I've been implementing logical AND/OR for tree structures which are kept in the database, using a simple nodes and a parent-child association table.
A sample tree has a structure like this:
A sample tree structure query is as follows:
The double lines in the query pattern mean that A has a child of type B (somewhere down its child nodes) OR C. I have implemented A -> HASCHILD -> C -> HASCHILD -> E with an inner join, and A -> HASCHILD -> B -> HASCHILD -> E is implemented like this.
The trick is joining these two branches on A. Since this is an OR operation, either B branch or C branch may not exist. The only method I could think of if to use full outer joins of two branches with A's node_id as the key. To avoid details, let me give this simplified snippet from my SQL query:
WITH A as (....),
B as (....),
C as (....),
......
SELECT *
from
A
INNER JOIN A_CONTAINS_B ON A.NODE_ID = A_CONTAINS_B.parent
INNER JOIN B ON A_CONTAINS_B.children #> ARRAY[B.NODE_ID]
INNER JOIN .....
full OUTER JOIN -- THIS IS WHERE TWO As ARE JOINED
(select
A2.NODE_ID AS A2_NODE_ID
from
A2
INNER JOIN A_CONTAINS_C ON A2.NODE_ID = C_CONTAINS_C.parent
INNER JOIN C ON A_CONTAINS_C.children #> ARRAY[C.NODE_ID]
INNER JOIN ....)
as other_branch
ON other_branch.A2_NODE_ID = A.NODE_ID
This query links two As which actually represent the same A using node_id, and if B or C does not exist, nothing breaks.
The result set has duplicates of course, but I can live with that. I can't however think of another way to implement OR in this context. ANDs are easy, they are inner joins, but left outer join is the only approach that lets me connect As. UNION ALL with dummy columns for both branches is not an option because I can't connect As in that case.
Do you have any alternatives to what I'm doing here?
UPDATE
TokenMacGuy's suggestion gives me a cleaner route than what I have at the moment. I should have remembered UNION.
Using the first approach he has suggested, I can apply a query pattern decomposition, which would be a consistent way of breaking down queries with logical operators. The following is a visual representation of what I'm going to do, just in case it helps someone else visualize the process:
This helps me do a lot of nice things, including creating a nice result set where query pattern components are linked to results.
I've deliberately avoided details of tables or other context, because my question is about how to join results of queries. How I handle the hierarchy in DB is a different topic which I'd like to avoid. I'll add more details into comments. This is basically an EAV table accomponied by a hierarchy table. Just in case someone would like to see it, here is the query I'm running without any simplifications, after following TokenMacGuy's suggestion:
WITH
COMPOSITION1 as (select comp1.* from temp_eav_table_global as comp1
WHERE
comp1.actualrmtypename = 'COMPOSITION'),
composition_contains_observation as (select * from parent_child_arr_based),
OBSERVATION as (select obs.* from temp_eav_table_global as obs
WHERE
obs.actualrmtypename = 'OBSERVATION'),
observation_cnt_element as (select * from parent_child_arr_based),
OBS_ELM as (select obs_elm.* from temp_eav_table_global as obs_elm
WHERE
obs_elm.actualrmtypename= 'ELEMENT'),
COMPOSITION2 as (select comp_node_tbl2.* from temp_eav_table_global as comp_node_tbl2
where
comp_node_tbl2.actualrmtypename = 'COMPOSITION'),
composition_contains_evaluation as (select * from parent_child_arr_based),
EVALUATION as (select eva_node_tbl.* from temp_eav_table_global as eva_node_tbl
where
eva_node_tbl.actualrmtypename = 'EVALUATION'),
eval_contains_element as (select * from parent_child_arr_based),
ELEMENT as (select el_node_tbl.* from temp_eav_table_global as el_node_tbl
where
el_node_tbl.actualrmtypename = 'ELEMENT')
select
'branch1' as branchid,
COMPOSITION1.featuremappingid as comprootid,
OBSERVATION.featuremappingid as obs_ftid,
OBSERVATION.actualrmtypename as obs_tn,
null as ev_ftid,
null as ev_tn,
OBS_ELM.featuremappingid as obs_elm_fid,
OBS_ELm.actualrmtypename as obs_elm_tn,
null as ev_el_ftid,
null as ev_el_tn
from
COMPOSITION1
INNER JOIN composition_contains_observation ON COMPOSITION1.featuremappingid = composition_contains_observation.parent
INNER JOIN OBSERVATION ON composition_contains_observation.children #> ARRAY[OBSERVATION.featuremappingid]
INNER JOIN observation_cnt_element on observation_cnt_element.parent = OBSERVATION.featuremappingid
INNER JOIN OBS_ELM ON observation_cnt_element.children #> ARRAY[obs_elm.featuremappingid]
UNION
SELECT
'branch2' as branchid,
COMPOSITION2.featuremappingid as comprootid,
null as obs_ftid,
null as obs_tn,
EVALUATION.featuremappingid as ev_ftid,
EVALUATION.actualrmtypename as ev_tn,
null as obs_elm_fid,
null as obs_elm_tn,
ELEMENT.featuremappingid as ev_el_ftid,
ELEMENT.actualrmtypename as ev_el_tn
from
COMPOSITION2
INNER JOIN composition_contains_evaluation ON COMPOSITION2.featuremappingid = composition_contains_evaluation.parent
INNER JOIN EVALUATION ON composition_contains_evaluation.children #> ARRAY[EVALUATION.featuremappingid]
INNER JOIN eval_contains_element ON EVALUATION.featuremappingid = eval_contains_element.parent
INNER JOIN ELEMENT on eval_contains_element.children #> ARRAY[ELEMENT.featuremappingid]
the relational equivalent to ∨ is &Union;. You could either use union to combine a JOIN b JOIN e with a JOIN c JOIN e or just use the union of b and c and join on the resulting, combined relation, something like a JOIN (b UNION c) JOIN e
More completely:
SELECT *
FROM a
JOIN (
SELECT
'B' source_relation,
parent,
b.child,
b_thing row_from_b,
NULL row_from_c
FROM a_contains_b JOIN b ON a_contains_b.child = b.node_id
UNION
SELECT
'C',
parent
c.child,
NULL,
c_thing
FROM a_contains_c JOIN c ON a_contains_c.child = c.node_id
) a_c ON A.NODE_ID = a_e.parent
JOIN e ON a_c.child = e.node_id;