Designing query to select count from different tables - sql

This is the schema for my questions
Hi, I don't have experience in SQL Developer and I'm trying to build a query for the following question:
I need that for each DVD in the catalog, display the title, length, release_date, and how many times it has been checked out by all customers across all libraries.
Also I want to include those that have not been checked out yet displaying 0, and sort results by title.
So far I have this in the query but I'm stock here:
--Question C. ************* VERIFY
Select
Catalog_Item.Title,
DVD.Length,
Catalog_Item.Release_Date,
(
Select
Count(Transaction.Transaction_ID)
From Transaction
Where
DVD.Catalog_Item_ID = Physical_Item.Catalog_Item_ID
And Physical_Item.Physical_Item_ID = Transaction.Physical_Item_ID
) as "Total_DVD"
From
Catalog_Item,DVD,
Physical_Item
Group by
Catalog_Item.Title,
DVD.Length,
Catalog_Item.Release_Date
If I run this exact query I get error
Not a Group By Expression
And if I exclude the GROUP BY, I get results by doesn't look like the correct outputs.
Any suggestions on what syntax I can use to achieve the desired output? Thanks!

You put three tables to the query but you missed to link them. If you don't link them, you will see too much-duplicated rows.
Also, your sub-query links were wrong, I assume you tried to put the links here that you missed in the main query.
I believe you need something like that:
Select
CI.Title
,DVD.Length
,CI.Release_Date
,NVL(TR.TotalTransactions,0) TotalTransactions
From Catalog_Item CI
INNER JOIN DVD ON DVD.Catalog_Item_ID = CI.Catalog_Item_ID
LEFT JOIN Physical_Item PHI ON CI.Catalog_Item_ID = PHI.Catalog_Item_ID
LEFT JOIN (SELECT Physical_Item_ID
, Count(Transaction_ID) TotalTransactions
FROM Transaction
GROUP BY Physical_Item_ID
) TR ON PHI.Physical_Item_ID = TR.Physical_Item_ID

For a start, join Catalog_Item, Physical_Item and DVD together. Without appropriate join conditions, these three tables will join using a cartesian product join - which is probably one of the reasons why you are seeing unexpected results.

Related

How to Count records in query with association table in SQL Server?

I have three tables
PackingLists
ItemsToPackingLists
Items
I would like to have a list of all PackingLists with the Number of items per PackingList and the WeightInGramms for the PackingList.
I wrote the following query, but it gives wrong results. I guess I have to arrange the joins somehow different.
Any help how to refactor the query is appreciated.
SELECT p.ID,
p.NameOfPackingList,
COUNT(ItemsToP.ItemID) AS NumberOfDifferentItems,
SUM(items.WeightInGrams * ItemsToP.Quantity) AS WeightInGramms
FROM PackingLists AS p
LEFT OUTER JOIN ItemsToPackingLists AS ItemsToP
ON (ItemsToP.PackingListID = p.ID)
LEFT OUTER JOIN Items AS items
ON (ItemsToP.ItemID = items.ID)
GROUP BY p.ID,p.NameOfPackingList
Not really clear what you want to get, but two options to check.
Use COUNT(Distinct ItemsToP.ItemID) instead of COUNT(ItemsToP.ItemID), you might including the same item twice in one package (with different quantities), and naming of the col 'NumberOfDifferentItems' suggest using distinct as well.
However, your question is 'Number of items per PackingList'. To my understanding you should sum the quantities, SUM(ItemsToP.Quantity) instead of counting the IDs.

Duplicate results on inner join

I've written the below query but I'm getting multiple duplicate rows in the results, please can anyone see where I'm going wrong?
use Customers
select customer_details.Customer_ID,
customer_details.customer_name,
metering_point_details.MPAN_ID,
Agents.DA_DC_Charge
from Customer_Details
left join Metering_Point_Details
on customer_details.customer_id = Metering_Point_Details.Customer_ID
left join agents
on customer_details.Customer_ID = agents.customer_id
order by customer_id
It doesn't really matter, but you're not using an INNER JOIN. Regardless, your unexpected rows indicate that your JOIN criteria is not specific enough to return your expected output. You can use SELECT DISTINCT if your results are fully duplicative, and if you'd like to see why you're getting those duplicates you can just use SELECT * to see the full detail between the multiple rows that are returned using your JOIN criteria, which should help you either make your criteria more specific or show you that you've got duplicated records in one of the tables you're using in your JOIN.
With sample data we can dissect the problem more, but odds are you won't need it once you see why the rows are duplicated.

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

Unknown column on 'on clause' in sql joins?

Can you guys help me please in understanding the SQL specifications on join. I don't understand it. I kept getting errors called Unknown column list on on clause.
I got this error over my SQL syntax, I almost rubbed it in my face I just can't understand why it is not working, I have read some article regarding that it is because of precedence etc but I am really confused on what I have done wrong here.
select product.name , product.price from product inner join product_category on
(product_category.product_no = product.product_no ) where product_category.sub_category =
"COFFIN";
I know this question have been ask a hudred and million times here, but the ones I saw are complicated nowhere close in this very basic sql syntax.
THanks for helping me out.
EDIT:
I just had realize that I have product_category not a direct child to my product table so
I just have typed
select * from product
join specifications
join product_category on ( specifications.product_no = product_category.product_no);
But this still gave me an error, unknown column product_category.
I've read and followed some instruction similarly to this sites:
MYSQL unknown clause join column in next join
Unknown column {0} in on clause
MySQL "Unknown Column in On Clause"
I am really frustrated. I really can't get it to work.
For each new table you join in your query, each table must have at least one ON clause. It's hard to know exactly what you're trying to do without knowing the schema (table names, columns, etc), but here's an example
select *
from product p
join specifications s
on p.product_no = s.product_no
join product_category pc
on pc.spec_no = p.spec_no
Check out this link on table aliases as well. Gives a good example on joins + really useful info on how to increase the readability of your SQL
http://msdn.microsoft.com/en-us/library/ms187455(v=sql.90).aspx
I found this article useful as well as it visually displays the different types of joins
http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
You are missing the part where you specify the joining conditions between product and specifcations.
select * from product
join specifications YOU NEED SOMETHING HERE
join product_category on etc
I modified the SQL syntax to look like this, I have overlook a key that connects product_category onto specification so I made necessary link and it worked!!!
SELECT *
FROM product
JOIN specifications ON ( product.product_no = specifications.product_no )
JOIN product_category ON ( specifications.spec_no = product_category.spec_no )
WHERE product_category.sub_category = "COFFIN"
LIMIT 0 , 30
Also thanks for the heads up on missing joining condition on specifications. Heck this carelessness cost so much time.
Thank you so much!
The default join type is an inner join. So if you write join, the database reads inner join, and insist that you include an on clause.
If you'd like to join without a condition, specify the cross join explicitly:
select *
from product p
cross join
specifications s
inner join
product_category pc
on pc.product_no = p.product_no
left join
some_other_table sot
on 1=1
The last join, with the on 1=1 condition, is another way to do a cross join. It's subtly different in that it will return rows from the left table even if the right table is empty.
Example at SQL Fiddle.

SQL query involving group by and joins

I couldn't be more specific in the title part but I want to do something a little bit complex for me. I thought I did it but it turned out that it is buggy.
I have three tables as following:
ProjectTable
idProject
title
idOwner
OfferTable
idOffer
idProject
idAccount
AccountTable
idAccount
Username
Now in one query I aim to list all the projects with most offers made, and in the query I also want to get details like the username of the owner, username of the offerer* etc. So I don't have to query again for each project.
Here is my broken query, it's my first experiment with GROUP BY and I probably didn't quite get it.
SELECT Project.addDate,Project.idOwner ,Account.Username,Project.idProject,
Project.Price,COUNT(Project.idProject) as offercount
FROM Project
INNER JOIN Offer
ON Project.idProject= Offer.idProject
INNER JOIN Account
ON Account.idAccount = Project.idOwner
GROUP BY Project.addDate,Project.idOwner,
Account.Username,Project.idProject,Project.Price
ORDER BY addDate DESC
*:I wrote that without thinking I was just trying to come up with example extra information, that is meaningless thanks to Hosam Aly.
Try this (modified for projects with no offers):
SELECT
Project.addDate,
Project.idOwner,
Account.Username,
Project.idProject,
Project.Price,
ISNULL(q.offercount, 0) AS offercount
FROM
(
SELECT
o.idProject,
COUNT(o.idProject) as offercount
FROM Offer o
GROUP BY o.idProject
) AS q
RIGHT JOIN Project ON Project.idProject = q.idProject
INNER JOIN Account ON Account.idAccount = Project.idOwner
ORDER BY addDate DESC
I might switch the query slightly to this:
select p.addDate,
p.idOwner,
a.Username,
p.idProject,
p.price,
o.OfferCount
from project p
left join
(
select count(*) OfferCount, idproject
from offer
group by idproject
) o
on p.idproject = o.idproject
left join account a
on p.idowner = a.idaccount
This way, you are getting the count by the projectid and not based on all of the other fields you are grouping by. I am also using a LEFT JOIN in the event the projectid or other id doesn't exist in the other tables, you will still return data.
Your question is a bit vague, but here are some pointers:
To list the projects "with most offers made", ORDER BY offercount.
You're essentially querying for projects, so you should GROUP BY Project.idProject first before the other fields.
You're querying for the number of offers made on each project, yet you ask about offer details. It doesn't really make sense (syntax-wise) to ask for the two pieces of information together. If you want to get the total number of offers, repeated in every record of the result, along with offer information, you'll have to use an inner query for that.
An inner query can be made either in the FROM clause, as suggested by other answers, or directly in the SELECT clause, like so:
SELECT Project.idProject,
(SELECT COUNT(Offer.idOffer)
FROM Offer
WHERE Offer.idProject = Project.idProject
) AS OfferCount
FROM Project