sql natural join and cross join should give same output - sql

We're currently starting SQL in school ... so I'm very beginner.
Now we got a task that says:
Write a SQL-query which gives the same output like the following query. Use cross joins.
SELECT PRODUCT_NAME, QUANTITY_ON_HAND, WAREHOUSE_NAME
FROM WAREHOUSES
NATURAL JOIN INVENTORIES
NATURAL JOIN PRODUCT_INFORMATION
ORDER BY PRODUCT_NAME;
Now I don't know what to do. For me it doesn't make sense to replace natural join by cross join or isn't even possible?!
Please help.
Diagram:

The cross join can be seen also as a cartesian product: so every row of the first table is combined with a row on the second one, so the resulting number of rows will be rows(TableA) * rows(TableB).
To emulate a natural join with a cross join you'll need to compare the foreign/primary key of the different tables to see if they are the same like this:
SELECT PRODUCT_NAME, QUANTITY_ON_HAND, WAREHOUSE_NAME
FROM WAREHOUSES
CROSS JOIN INVENTORIES
CROSS JOIN PRODUCT_INFORMATION
WHERE WAREHOUSES.WAREHOUSES_ID = INVENTORIES.WAREHOUSE_ID AND
INVENTORIES.PRODUCT_ID = PRODUCT_INFORMATION.PRODUCT_ID
ORDER BY PRODUCT_NAME;
If you need more information about cross-join or natural join.
If it can help you try to think at it like this:
First you create a table with all the possible combination of rows
between the three tables
Than you start compare on each row the common and repetitive field, you've on each row 2 PRODUCT_ID and WAREHOUSE_ID columns, each of them coming from his specific table (try to execute the query taking all the columns with * to see this).
After that you take only the rows where the 2 type of columns have the same value (Emulating a natural join)
You're just doing a normal join....with extra steps.

Related

How to use a SQL table instead of a long string for a WHERE in (string) condition

I have the following SQL statement:
select customer_id, prod_id, prod_start, prod_price
from prod_table
where prod_id in (PRODLIST)
Unfortunately, PRODLIST contains about 68K 6-digit numbers. When I try to run this query on my server, I get an error that SQL can't handle so many prod_id as presented in a string.
My next thought was to put all the 68K 6-digit numbers into a single column table included_prodlist with column heading included_prod_id. The resulting included_prodlist table would then be a single column table with 68K rows, and each column would be a unique 6-digit number.
I could then do an inner join of the original query with included_prodlist as follows:
select customer_id, prod_id, prod_start, prod_price
from prod_table
where prod_id in (select included_prod_id from included_prodlist)
Unfortunately, this doesn't seem to be working i.e. the query returns no entries.
Is this the proper way to deal with long conditions?
Should I be using an inner join instead?
select customer_id, prod_id, prod_start, prod_price
from prod_table
inner join included_prodlist on prod_table.prod_id = included_prodlist.included_prod_id
Putting the values in to a table is highly recommended. The one column should be the primary key.
Then, I would go for exists rather than not in:
select p.customer_id, p.prod_id, p.prod_start, p.prod_price
from prod_table p
where exists (select 1
from included_prodlist ip
where ip.included_prod_id = p.prod_id
);
Of course using INNER JOIN can be more helpful with a better performance. For best practices create the index which is recommended in query execution plan :)
INNER JOIN on a single column table is preferable on a nested query
In a nested query the internal query runs 1st and its results are placed in the outer query
Using join, there is only one query, preferably on indexed columns
You will be able to see the differences adding EXPLAIN before the SELECT command
I would generate the product list table as a temp table, with an indexed column, that way the query would run with join even faster

SQL Server View tables not joining

I am incredibly new to SQL and am trying to create a view for a pizza store database. The sides ordered table and the sides names table have to be separate but need a view that combines them.
This is the code I have entered,
CREATE VIEW ordered_sides_view
AS
SELECT
ordered_side_id, side.side_id, side_name, number_ordered,
SUM(number_ordered * price) AS 'total_cost'
FROM
ordered_side
FULL JOIN
side ON ordered_side.side_id = side.side_id
GROUP BY
ordered_side_id, side.side_id, side_name, number_ordered;
The problem is that this is the resulting table.
Screenshot of view table:
How do I get the names to match the ordered sides?
You fail to understand what a FULL JOIN and an INNER JOIN operation does.
FULL JOIN returns at least every row from each table (plus any extra values from the ON clause).
INNER JOIN returns only matching row sets based on the ON clause.
OUTER JOIN returns every matching row set PLUS the side of the join that the OUTER JOIN is on (LEFT OUTER JOIN vs RIGHT OUTER JOIN).
In your picture, you can clearly see that there are no rows that match from the tables ordered_side and side...
That is why switching to an INNER JOIN returns zero rows...there are no matches on the COLUMNS YOU CHOSE TO USE.
Why in your SELECT operator do you have this:
SELECT ordered_side_id, side.side_id, side_name, number_ordered,
while your ON clause has this:
side ON ordered_side.side_id = side.side_id
ordered_side_id !=ordered_side.side_id
Investigate your columns and fix your JOIN clause to match the correct columns.
P.S. I like how you structure your queries. Very nice and what an
expert does! It makes reading MUCH, MUCH easier. :)
One suggestion I might add is structure your columns in the SELECT statement in its own row:
SELECT ordered_side_id
, side.side_id
, side_name
, number_ordered
, SUM(number_ordered * price) AS Total_Cost --or written [Total_Cost]/'Total_Cost'
FROM ordered_side
FULL JOIN side ON ordered_side.ordered_side_id = side.side_id
GROUP BY ordered_side_id
, side.side_id
, side_name
, number_ordered;

SQL ORACLE Joining two queries together as one?

thanks in advance for your help.
I have a set of tables like this.
Also, here is a semi-accurate ERD to see what's going on.
I need to list all donations made by individual Alumni, and businesses. I need the first/last name and IDs present.
The following code returns all I need about the Alumni donors:
SELECT DonationID, Donation.AlumniID, BusinessID_FK, DONATIONDATE, Value, Alumnus.FirstName, Alumnus.LastName
FROM DONATION
JOIN Alumnus
on Donation.AlumniID=Alumnus.alumniid;
And the following code returns all I need about the Business donors:
SELECT * FROM DONATION
JOIN BusinessSponser
on Donation.businessid_fk=businesssponser.businessid;
Furthermore, the following query returns all the IDs, however no First/Last names:
SELECT * FROM DONATION
LEFT JOIN BusinessSponser
on Donation.businessid_fk=businesssponser.businessid;
So my question is, how can I merge these queries together as one? My intention is to create a view that would display the final result.
Thanks in advance for your help.
The outer join is a SQL technique which allows us to join rows from one table with some rows from another table. In your case you have two optional tables so you need two left outer joins:
select donationid
, donation.donationdate
, donation.value
, donation.alumniid
, alumnus.firstname
, alumnus.lastname
, donation.businessid
, businesssponser.businessname
from donation
left outer join alumnus
on donation.alumniid=alumnus.alumniid;
left outer join businesssponser
on donation.businessid_fk=businesssponser.businessid;

Combining data from multiple tables issue Oracle 11g

TABLE // FIELD
Customer // Company
Stock // Description
Manufact // Manu_Name
Items // Quantity, total_price
I am using Oracle 11g Application Express. I need to display a list of each stock ordered for EACH CUSTOMER. I need to display the Manufacturer, quantity ordered, and total price paid.
When I run this query within my SQL*PLUS command prompt, it endlessly displays results from the tables mentioned until I force-quit (ctrl+c) the application. This is incredibly frustrating - I've tried joining tables, using the EXISTS clause, I just don't know what the hell to do. Any insight would be wonderful - not looking for someone to simply solve this for me, more-so just guide me.
SELECT c.company, s.description, m.manu_name, i.quantity, i.total_price
FROM db1.customer c JOIN db1.orders o USING (customer_num), db1.stock s, db1.manufact m, db1.items i
WHERE o.order_num = i.order_num;
This causes a never-ending display of what seems like the same results, over, and over, and over.
Essentially, I need to display the required information for EACH ORDER of stock. However, I don't need the order_num in my output display of columns, so I thought I needed to use the order_num (in db1.orders o & db1.items i) to essentially tell Oracle, "For each order_num (an order can't exist without an order_num), display (results)...
I am incredibly lost - I've tried outer joins, I've tried using an EXIST operator, I am just stumped and I feel like it's something easy that I'm overlooking.
EDIT: So, it seems I finally found it, after an enormous amount of pondering.
This is how I did it, in case anyone else runs into this issue:
SELECT c.company, s.description, m.manu_name, i.quantity, i.total_price
FROM db1.customer c JOIN db1.orders o USING (customer_num)
JOIN db1.items i USING (order_num)
JOIN db1.stock USING (stock_num)
JOIN db1.manufact m ON m.manu_code = s.manu_code
ORDER BY c.company, s.description;
If you JOIN db1.manufact m USING (manu_code), you get an ambiguously defined column error from Oracle - this is because I already joined the other tables and that column was in one of them (It was the db1.stock table). You can still join them, but you have to use JOIN ON instead.
This displayed the results I needed. Thanks anyways, and cheers if this helped anybody out!
You've only provided two joins (one USING and one in the WHERE) between 5 tables - in this case, you will get the cartesian product of all other rows in all other tables, hence the large number of rows.
(Edit, by implication you need to join all tables together, whether by USING or JOIN)
In order to use the USING join sugar, the same column must be present on the immediate lhs and rhs tables. For multiple joins, into a hierarchy, you may need to nest the USINGs like so:
SELECT c.company, s.description, m.manu_name, i.quantity, i.total_price
FROM customer c
JOIN orders o
JOIN stock s
JOIN items i
JOIN manufact m USING(manid)
USING(itemid)
USING (stockid)
USING (customer_num);
There where join isn't needed since we already have the USING join
I've assumed some columns and relationships between your table in this fiddle here:
You can also drop the USING and use explicit JOIN syntax, which will allow you to avoid the nesting (this is also more portable across the ANSI world):
SELECT c.company, s.description, m.manu_name, i.quantity, i.total_price
FROM customer c
INNER JOIN orders o on c.customer_num = o.customer_num
INNER JOIN stock s on o.stockid = s.stockid
INNER JOIN items i on i.itemid = s.itemid
INNER JOIN manufact m on m.manid = i.manid;
Edit
As OP has demonstrated, no requirement to nest the USING joins, provided that the join ordering is sensible, and provided that the FK JOIN column isn't duplicated across multiple tables.
http://sqlfiddle.com/#!4/91ef6/9

How to select all attributes in sql Join query

The following sql query below produces the specified result.
select product.product_no,product_type,salesteam.rep_name,salesteam.SUPERVISOR_NAME
from product
inner join salesteam
on product.product_rep=salesteam.rep_id
ORDER BY product.Product_No;
However my intensions are to further produce a more detailed result which will include all the attributes in the PRODUCT table. my approach is to list all the attributes in the first line of the query.
select product.product_no,product.product_date,product.product_colour,product.product_style,
product.product_age product_type,salesteam.rep_name,salesteam.SUPERVISOR_NAME
from product
inner join salesteam
on product.product_rep=salesteam.rep_id
ORDER BY product.Product_No;
Is there another way it can be done instead of listing all the attributes of PRoduct table one by one?
You can use * to select all columns from all tables, or you can use [table/alias].* to select all columns from the specified table. In your case, you can use product.*:
select product.*,salesteam.rep_name,salesteam.SUPERVISOR_NAME
from product
inner join salesteam
on product.product_rep=salesteam.rep_id
ORDER BY product.Product_No;
It is important to note that you should only do this if you are 100% sure you need every single column, and always will. There are performance implications associated with this; if you're selecting 100 columns from a table when you really only need 4 or 5 of them, you're adding a lot of overhead to the query. The DBMS has to work harder, and you're also sending more data across the wire (if your database is not on the same machine as your executing code).
If any columns are later added to the product table, those columns will also be returned by this query in the future.
select
product.*,
salesteam.rep_name,
salesteam.SUPERVISOR_NAME
from product inner join salesteam on
product.product_rep=salesteam.rep_id
ORDER BY
product.Product_No;
This should do.
You can write like this
select P.* --- all Product columns
,S.* --- all salesteam columns
from product P
inner join salesteam S
on P.product_rep=S.rep_id
ORDER BY P.Product_No;