Natural Joins Creating More Records Than Desired - sql

I have the following tables populated with these records:
I have created a view that looks like this and have selected all records from it:
However, the results are not as expected. Each store location is matched with each craft item, even if they are not supplied to that store.
Even regions that don't have recorded stores display records:
I imagine this has something to do with the natural join being mixed with the left outer join, but I don't understand why.

And based on all the comments others have provided, and you may not be comfortable explicitly with the syntax, think of LEFT side as the first table of a query and right is the second. So a left join implies everything from the left-side table regardless of a match on the other, but if one exists, it only exists based on the matching criteria/condition. For what you have, you are probably looking for something like...
create or replace view detailedCraftRegaion as
select
cr.CraftRegionDescription,
cs.StoreAddress,
cs.StoreCity,
cs.StoreState,
cs.StoreZipCode,
csi.CraftItemName
from
CraftStore cs
JOIN CraftRegion cr
on cs.CraftRegionID = cr.CraftRegionID
JOIN CraftShipItems csi
on cs.CraftStoreID = csi.CraftStoreID

Related

Duplicate Rows when self joining tables in SQL

I am trying to self join a table together based on the column "Warehouse Number". The goal is to list part numbers, descriptions, and item class of any pairs of parts that are in the same item class and same warehouse. Below is an example of the desired output and starting data.
STARTING DATA
EXAMPLE OF SOME DESIRED DATA
However, when that self join happens, there aren't "exact" duplicates but the pairs appear twice in the table.
EXAMPLE OF OUTPUT WITH PROBLEMS (HIGHLIGHTED)
I have tried most iterations of UNION, INNER JOIN, and other join methods. Is it possible to remove the pairs since it isn't technically an exact duplicate of another row?
Current SQL Code
You may alter your join condition to check that the first part number is strictly less than the second one:
SELECT
t1.PARTNUMB, t1.PARTDESC, t1.ITEMCLSS, t2.PARTNUMB, t2.PARTDESC, t2.ITEMCLSS
FROM PARTFIRST t1
INNER JOIN PARTSECOND t2
ON t1.WRHSNUMB = t2.WRHSNUMB AND
t1.ITEMCLSS = t2.ITEMCLSS AND
t1.PARTNUMB < t2.PARTNUMB;
The problem with using FIRST.PARTNUMB <> SECOND.PARTNUMB is that it would report two different part numbers twice, once on the left/right side and vice-versa. By using a strictly less than inequality, we exclude "duplicates," as you view them.

sql separate one field into columns depending on value of initial field

I am trying to separate one field in one table, into two columns in a report, populating each column depending on the value of that initial field. Here is how the tables are structured. TABLES VIEW I am quite new to sql, and am learning slowly, but have tried cases, and sub-queries, but no luck... I do hope some kind sole will be able to help me. :P
My database is structured like this:
This is the query I am using
SELECT
Insurance_Folder.code, Rating_Section.rating_section_type_id, Rating_Section.sum_insured, Rating_Section_Type.description
FROM
dbo.Rating_Section
Left Outer Join dbo.Rating_Section_Type ON
Rating_Section.rating_section_type_id = Rating_Section_Type.rating_section_type_id
Left Outer Join dbo.Insurance_Folder
Left Outer Join dbo.Insurance_File ON
Insurance_Folder.insurance_folder_cnt = Insurance_File.insurance_folder_cnt
Left Outer Join dbo.insurance_file_risk_link ON
Insurance_File.insurance_file_cnt = insurance_file_risk_link.insurance_file_cnt and insurance_file_risk_link.risk_cnt = Rating_Section.risk_cnt
WHERE
Rating_Section.rating_section_type_id = 219 or Rating_Section.rating_section_type_id = 228
This gives me the following result ( I can not post another image)
-All the codes from Insurance folder, with each rating section type for each code, on a row. I want to separate the row with second value, and have it put in the same row of the code, in a separate column, depending on the value of rating_section_type_id
And these are the results I am looking for:

Translating Oracle SQL to Access Jet SQL, Left Join

There must be something I'm missing here. I have this nice, pretty Oracle SQL statement in Toad that gives me back a list of all active personnel with the IDs that I want:
SELECT PERSONNEL.PERSON_ID,
PERSONNEL.NAME_LAST_KEY,
PERSONNEL.NAME_FIRST_KEY,
PA_EID.ALIAS EID,
PA_IDTWO.ALIAS IDTWO,
PA_LIC.ALIAS LICENSENO
FROM PERSONNEL
LEFT JOIN PERSONNEL_ALIAS PA_EID
ON PERSONNEL.PERSON_ID = PA_EID.PERSON_ID
AND PA_EID.PERSONNEL_ALIAS_TYPE_CD = 1086
AND PA_EID.ALIAS_POOL_CD = 3796547
AND PERSONNEL.ACTIVE_IND = 1
LEFT JOIN PERSONNEL_ALIAS PA_IDTWO
ON PERSONNEL.PERSON_ID = PA_IDTWO.PERSON_ID
AND PA_IDTWO.PERSONNEL_ALIAS_TYPE_CD = 3839085
AND PA_IDTWO.ACTIVE_IND = 1
LEFT JOIN PERSONNEL_ALIAS PA_LIC
ON PERSONNEL.PERSON_ID = PA_LIC.PERSON_ID
AND PA_LIC.PERSONNEL_ALIAS_TYPE_CD = 1087
AND PA_LIC.ALIAS_POOL_CD = 683988
AND PA_LIC.ACTIVE_IND = 1
WHERE PERSONNEL.ACTIVE_IND = 1 AND PERSONNEL.PHYSICIAN_IND = 1;
This works very nicely. Where I run into problems is when I put it into Access. I know, I know, Access Sucks. Sometimes one needs to use it, especially if one has multiple database types that they just want to store a few queries in, and especially if one's boss only knows Access. Anyway, I was having trouble with the ANDs inside the FROM, so I moved those to the WHERE, but for some odd reason, Access isn't doing the LEFT JOINs, returning only those personnel with EID, IDTWO, and LICENSENO's. Not everybody has all three of these.
Best shot in Access so far is:
SELECT PERSONNEL.PERSON_ID,
PERSONNEL.NAME_LAST_KEY,
PERSONNEL.NAME_FIRST_KEY,
PA_EID.ALIAS AS EID,
PA_IDTWO.ALIAS AS ID2,
PA_LIC.ALIAS AS LICENSENO
FROM ((PERSONNEL
LEFT JOIN PERSONNEL_ALIAS AS PA_EID ON PERSONNEL.PERSON_ID=PA_EID.PERSON_ID)
LEFT JOIN PERSONNEL_ALIAS AS PA_IDTWO ON PERSONNEL.PERSON_ID=PA_IDTWO.PERSON_ID)
LEFT JOIN PERSONNEL_ALIAS AS PA_LIC ON PERSONNEL.PERSON_ID=PA_LIC.PERSON_ID
WHERE (((PERSONNEL.ACTIVE_IND)=1)
AND ((PERSONNEL.PHYSICIAN_IND)=1)
AND ((PA_EID.PRSNL_ALIAS_TYPE_CD)=1086)
AND ((PA_EID.ALIAS_POOL_CD)=3796547)
AND ((PA_IDTWO.PRSNL_ALIAS_TYPE_CD)=3839085)
AND ((PA_IDTWO.ACTIVE_IND)=1)
AND ((PA_LIC.PRSNL_ALIAS_TYPE_CD)=1087)
AND ((PA_LIC.ALIAS_POOL_CD)=683988)
AND ((PA_LIC.ACTIVE_IND)=1));
I think that part of the problem could be that I'm using the same alias (lookup) table for all three joins. Maybe there's a more efficient way of doing this? Still new to SQL land, so any tips as far as that goes would be great. I feel like these should be equivalent, but the Toad query gives me back many many tens of thousands of imperfect rows, and Access gives me fewer than 500. I need to find everybody so that nobody is left out. It's almost as if the LEFT JOINs aren't working at all in Access.
To understand what you are doing, let's look at simplified version of your query:
SELECT PERSONNEL.PERSON_ID,
PA_EID.ALIAS AS EID
FROM PERSONNEL
LEFT JOIN PERSONNEL_ALIAS AS PA_EID ON PERSONNEL.PERSON_ID=PA_EID.PERSON_ID
WHERE PERSONNEL.ACTIVE_IND=1
AND PERSONNEL.PHYSICIAN_IND=1
AND PA_EID.PRSNL_ALIAS_TYPE_CD=1086
AND PA_EID.ALIAS_POOL_CD=3796547
If the LEFT JOIN finds match, your row might look like this:
Person_ID EID
12345 JDB
If it doesn't find a match, (disregard the WHERE clause for a second), it could look like:
Person_ID EID
12345 NULL
When you add the WHERE clauses above, you are telling it to only find records in the PERSONNEL_ALIAS table that meet the condition, but if no records are found, then the values are considered NULL, so they will never satisfy the WHERE condition and no records will come back...
As Joe Stefanelli said in his comment, adding a WHERE clause to a LEFT JOIN'ed table make it act as an INNER JOIN instead...
Further to #Sparky's answer, to get the equivalent of what you're doing in Oracle, you need to filter rows from the tables on the "outer" side of the joins before you join them. One way to do this might be:
For each table on the "outer" side of a join that you need to filter rows from (that is, the three instances of PERSONNEL_ALIAS), create a query that filters the rows you want. For example, the first query (say, named PA_EID) might look something like this:SELECT PERSONNEL_ALIAS.* FROM PERSONNEL_ALIAS WHERE PERSONNEL_ALIAS.PERSONNEL_ALIAS_TYPE_CD = 1086 AND PERSONNEL_ALIAS.ALIAS_POOL_CD = 3796547
In your "best shot in Access so far" query in the original post: a) replace each instance of PERSONNEL_ALIAS with the corresponding query created in Step 1, and, b) remove the corresponding conditions (on PA_EID, PA_IDTWO, and PA_LIC) from the WHERE clause.

joining more tables makes me get less data from the query

I have one problem with one SP, when I am joining some specific tables, I am getting less data from the SP then I am getting when they are not included in the SP.
I am not getting any data from them yet, I am just joining them and only that makes the SP to send me less data.
Any idea what the problem can be? Thanks
It sounds like there are no matching rows in the tables you're joining to.
If you change the join to a LEFT OUTER JOIN, you should get the rows you are expecting (but, obviously, check the output to make sure you do!)
Joins usually have a join condition in the "ON" clause. That condition says how to match rows between the tables being joined. If, for a particular row on one side, there is no matching row on the other side, then we need to consider what type of join we're dealing with:
For an INNER JOIN, the row will be discarded.
For a LEFT JOIN, and if the row comes from the "LEFT" table source, then this row will appear, but with NULLs present for all columns from the "RIGHT" table source.
RIGHT JOIN is similar to left join, with the directions swapped over.
regardless if you are asking for data from those tables or not, they have been included as part of the join, and the resultset is going to return rows that meet the criteria you have specified.
You may want to post 2 versions of the SP, one with few tables, then a second with one or more of the joins so that it can be better explained what is happening behind the scenes.
Sounds like you're doing an INNER JOIN. This will only return a record if whatever property you're joining on is in both tables. As an example:
Customers
ID Name
1 Mike
2 Steve
3 Amy
Address
ID Address
1 123 Main
3 456 Oak
If you
SELECT Name, Adddress FROM NAME N
Join Address A ON N.Id = A.Id
Only The records for Mike and Amy will be returned because Steve doesn't have an Address record.
I don't know what kind of join you are doing but it exists three kind of join
INNER JOIN : Retrieves datas that matches on both side
LEFT (OUTER) JOIN : Retrieves datas that only match on the left side, even if right is null
RIGHT (OUTER) JOIN Retrieves datas that only mach on the right side, even if left is null
According to which one you are using, datas can be retrieved or not.
But posting your query will let us tell you what might be the real problem.
Hope I could help,
See this blog post by Jeff Atwood. It explains SQL Joins very well. I think it will answer your question about why certain sets of data may or may not be missing.

What are the uses of the different join operations?

What are the uses of the different join operations in SQL? Like I want to know why do we need the different inner and outer joins?
The only type of join you really need is LEFT OUTER JOIN. Every other type of join can be rewritten in terms of one or more left outer joins, and possibly some filtering. So why do we need all the others? Is it just to confuse people? Wouldn't it be simpler if there were only one type of join?
You could also ask: Why have both a <= b and b >= a? Don't these just do the same thing? Can't we just get rid of one of them? It would simplify things!
Sometimes it's easier to swap <= to >= instead of swapping the arguments round. Similarly, a left join and a right join are the same thing just with the operands swapped. But again it's practical to have both options instead of requiring people to write their queries in a specific order.
Another thing you could ask is: In logic why do we have AND, OR, NOT, XOR, NAND, NOR, etc? All these can be rewritten in terms of NANDs! Why not just have NAND? Well it's awkward to write an OR in terms of NANDs, and it's not as obvious what the intention is - if you write OR, people know immediately what you mean. If you write a bunch of NANDs, it is not obvious what you are trying to achieve.
Similarly, if you want to do a FULL OUTER JOIN b you could make a left join and a right join, remove duplicated results, and then union all. But that's a pain and so there's a shorthand for it.
When do you use each one? Here's a simplified rule:
If you always want a result row for each row in the LEFT table, use a LEFT OUTER JOIN.
If you always want a result row for each row in the RIGHT table, use a RIGHT OUTER JOIN.
If you always want a result row for each row in either table, use a FULL OUTER JOIN.
If you only want a result row when there's a row in both tables, use an INNER JOIN.
If you want all possible pairs of rows, one row from each table, use a CROSS JOIN.
inner join - joins rows from both sets of the match based on specified criteria.
outer join - selects all of one set, along with matching or empty (if not matched) elements from the other set. Outer joins can be left or right, to specify which set is returned in its entirety.
To make the other answers clearer - YOU GET DIFFERENT RESULTS according to the join you choose, when the columns you're joining on contain null values - for example.
So - for each Real-life scenario there is a join that suits it (either you want the lines without the data or not in the null values example).
My answer assumes 2 tables joined on a single key:
INNER JOIN - get the results that are in both join tables (according to the join rule)
FULL OUTER JOIN - get all results from both table (Cartesian product)
LEFT OUTER JOIN - get all the results from left table and the matching results from the right
You can add WHERE clauses in order to further constrain the results.
Use these in order to only get what you want to get.