how to use View function in SQL - sql

I have a question for an assignment and it is listed below here.
"List a query that list the film genres and gross revenue for that genre, conditional to the gross revenue for that genre being higher than average gross revenue per genre. Hint: Use a View to simplify the query."
My code is as follows:
CREATE VIEW grossrevenue as (
SELECT category.name, SUM(payment.amount) as sumpay
FROM payment
JOIN rental ON payment.rental_id = rental.rental_id
JOIN inventory ON rental.inventory_id = inventory.inventory_id
JOIN film_category ON inventory.film_id = film_category.film_id
JOIN category ON film_category.category_id = category.category_id
GROUP by category.name
);
Then:
Select sumpay
FROM grossrevenue
WHERE sumpay > AVG(sumpay);
What is wrong with it and why is it not running?

Syntax wise, AVG() does not make sense without a group of records. It’s for aggregating multiple rows.
Try putting a sub query to calculate the average, or rethink your view.
Requested Edits
People generally shouldn't give answers to school assignments, so I didn't dig into your view SQL too much, and my answer was somewhat vague on purpose.
But here's some info to clarify my above answer so you can go the right direction:
Select sumpay
FROM grossrevenue
WHERE sumpay > AVG(sumpay);
You can't do sumpay > AVG(sumpay) as they both operate on just one row. AVG() of one row doesn't make sense.
If AVG(sumpay) was the only thing in the select clause like this, then it makes sense as it will average all the rows and give you literally just the average.
Select AVG(sumpay)
FROM grossrevenue
But in your where clause, its literally just operating on the current row and doesn't mean anything. There is nothing to average; that's not how it works.
You can use a "subquery" to get the average (literally replace AVG(sumpay) with a subquery after googling it). That would be one option.

Related

SQL Query - select multiple rows from 2 tables

I'm new to SQL and recently saw this question, which is described on the [attached picture]
. Any suggestions on how to solve it? Thanks in advance.
In most cases such requirements are better to resolve by starting from the end. Let's try that: "have more than 3 items ... and total price".
select InvoiceId, sum(price)
from InvoiceItem
group by InvoiceId
having count(1) > 3;
This query gives you the overall price for every invoice that has more than 3 items. You might be wondering why there is that funny "having" clause and not the "where" clause.
The database executes first "from" and "where" parts of the query to get the data and only after that using aggregations (sum, count etc.) is possible, so they are to be specified afterwards.
The query above actually returns all the data from requirement, but I assume that whoever gave you this task (that was a teacher, right?) was asking you to retrieve all the data from Invoices table that correspond to the records within the InvoiceItem table that has more than 3 items and so on.
So, for now all you have left is to join the Invoice table with a query from above
select i.id, i.customername, i.issuedate, sum(it.price)
from InvoiceItem it
join Invoice i on it.invoiceid = i.id
group by i.id, i.customername, i.issuedate
having count(1) > 3;
Teacher might ask you why did you use count(1) and not count(*) or count(id) or something. Just tell him/her all these things are equal so you picked just one.
Now it should be working fine presumably. I did not tested it at all as you did not provide the data to test it on and it is late so I am pretty tired. Because of this you might needed to fix some typos or syntax errors I probably made - but hey let's keep in mind you still have to do something on your own with this task.

Sum matching entries in SQL

In this database I need to find the total amount that each customer paid for books in a category, and then sort them by their customer ID. The code appears to run correctly but I end up with approximately 20 extra rows than I should, although the sum appears to be correct in the right rows.
The customer ID is part of customer, but is not supposed to appear in the select clause, when I try and ORDER BY it, I get strange errors. The DB engine is DB2.
SELECT distinct customer.name, book.cat, sum(offer.price) AS COST
FROM offer
INNER JOIN purchase ON purchase.title=offer.title
INNER JOIN customer ON customer.cid=purchase.cid
INNER JOIN member ON member.cid=customer.cid
INNER JOIN book ON book.title=offer.title
WHERE
member.club=purchase.club
AND member.cid=purchase.cid AND purchase.club=offer.club
GROUP BY customer.name, book.cat;
You should fix your join conditions to include the ones in the where clause (between table relationships usually fit better into an on clause).
SELECT DISTINCT is almost never appropriate with a GROUP BY.
But those are not your question. You can use an aggregation function:
GROUP BY customer.name, book.cat
ORDER BY MIN(customer.id)

Correlated Subquery to find AVG of certain groups

Question! I'm trying to list all books and their corresponding book subject, average cost and regular cost.
So far my query is...
SELECT BOOK_SUBJECT, AVG( BOOK_COST )
FROM BOOK
GROUP BY BOOK_SUBJECT
This query gives me the avg of the four groups total cost. Final out put should look like this I need to bring in BOOK_NUM, BOOK_TITLE, BOOK_SUBJECT, BOOK_COST, but I'm unable to figure it out. Can someone help? Correlated subquery?
Please try the following...
SELECT BOOK_NUM AS Number,
BOOK_TITLE AS Title,
BOOK.BOOK_SUBJECT AS Subject,
BOOK_COST AS Cost,
AVG_BOOK_COST AS 'Avg Cost'
FROM BOOK
JOIN ( SELECT BOOK_SUBJECT AS BOOK_SUBJECT,
AVG( BOOK_COST ) AS AVG_BOOK_COST
FROM BOOK
GROUP BY BOOK_SUBJECT
) AS SUBJECT_AVG_FINDER ON BOOK.BOOK_SUBJECT = SUBJECT_AVG_FINDER.BOOK_SUBJECT
ORDER BY BOOK_NUM;
To calculate the average for each Subject we have to group the contents of BOOK by BOOK_SUBJECT and use AVG( BOOK_COST ) to find the mean average for each group. But we also wish to avoid grouping the other fields in BOOK, instead having the specified fields from each record in Book displayed with their BOOK_SUBJECT's average cost tacked on the end. This suggests that an INNER JOIN between BOOK and a subquery that is used to find the mean average of cost for each subject.
I used the following code to find the mean average cost for each subject listed in BOOK...
SELECT BOOK_SUBJECT AS BOOK_SUBJECT,
AVG( BOOK_COST ) AS AVG_BOOK_COST
FROM BOOK
GROUP BY BOOK_SUBJECT
We need to select BOOK_SUBJECT partly because the GROUP BY clause requires it and partly because we will need it to join the table generated by this subquery to the ungrouped listing of BOOK.
Giving AVG( BOOK_COST ) the alias of AVG_BOOK_COST makes referring to this generated field much easier.
In the absence of a join type before the word JOIN most versions of SQL will assume an INNER JOIN, although all allow INNER JOIN to be used and some require you to do so. By default I and many others simply use JOIN.
Once the join is performed each record from from BOOK will have a copy of it's corresponding record from our subquery (which I have given an alias of SUBJECT_AVG_FINDER), leaving each record with two fields called BOOK_SUBJECT. So as not to confuse your version of SQL, we must specify the table / subquery along with the field name where such duplication occurs, hence BOOK.BOOK_SUBJECT in the third line of the overall statement.
Each field has been given an alias as per your desired final output image.
I have assumed that there is no need to replicate the row number field. If that is incorrect, then please state otherwise.
Finally, I have sorted the results as per your desired output by adding the line ORDER BY BOOK_NUM.
As a tip, although it's allowed, you should avoid using shouting (i.e. full uppercase) your field names, table names, and alias' (unless you are required to do so), but still shout the SQL stuff (like SELECT, FROM, AS, etc.). This can make a statement easier to read and debug by providing a visual clue as to how you are trying to use each word. I suggest the following way of presenting our SQL statement instead...
SELECT book_num AS Number,
book_title AS Title,
book.book_subject AS Subject,
book_cost AS Cost,
avg_book_cost AS 'Avg Cost'
FROM book
JOIN ( SELECT book_subject AS book_subject,
AVG( book_cost ) AS avg_book_cost
FROM book
GROUP BY book_subject
) AS subject_avg_finder ON book.book_subject = subject_avg_finder.book_subject
ORDER BY book_num;
If you have any questions or comments, then please feel free to post a Comment accordingly.
Use a subquery to do this:
SELECT BOOK.BOOK_NUM, BOOK.BOOK_TITLE, BOOK.BOOK_SUBJECT, BOOK.BOOK_COST, T.AVG_COST
FROM BOOK
INNER JOIN (
SELECT BOOK_SUBJECT, AVG(BOOK_COST) AVG_COST
FROM BOOK
GROUP BY BOOK_SUBJECT
) T ON BOOK.BOOK_SUBJECT = T.BOOK_SUBJECT
Use this code
SELECT BOOK_NUM, BOOK_TITLE, BOOK_SUBJECT, BOOK_COST,
AVG(BOOK_COST) OVER(PARTITION BY BOOK_SUBJECT) AS AVG_COST
FROM BOOK

sql join query not returning data, just blank

I am trying to pull data from 2 separate tables but only specific columns, then I do a join so that only one row per client is displaying with the total sum of their payments but the information is not displaying. Code is below. It is for a reports page so think about geting the sum of all payments. I know what I am looking for, I just think that maybe there is a bug in the query that I can't seem to catch. I could use an extra pair of eyes to point out the flaw if possible. Thanks
SELECT pre.id, pre.loanAmount, pre.custId,
SUM(pay.amount) AS amount,
DISTINCT(pay.company) AS company,
DISTINCT(pay.loanId) AS loanId
FROM preQualForm pre INNER JOIN
payments pay
ON pre.custId=pay.custId
The DISTINCT Keyword applies to all the columns you SELECT,
so if you need to also do aggregate functions like SUM,
then it is better achieved using a GROUP BY clause on non-aggregate columns.
The following should work.
SELECT
pre.id
, pre.loanAmount
, pre.custId
, SUM(pay.amount) AS Amount
, pay.company AS Company
, pay.loanId AS LoanId
FROM preQualForm pre
INNER JOIN payments pay
ON pre.custId = pay.custId
GROUP BY
pre.id
, pre.loanAmount
, pre.custId
, pay.company
, pay.loanId
for starters you are Missing the GROUP BY clause. (There might be other issues but for that we need data and expected output)
SELECT pre.id, pre.loanAmount, pre.custId, SUM(pay.amount) AS amount,
DISTINCT(pay.company) AS company,
DISTINCT(pay.loanId) AS loanId
FROM preQualForm pre
INNER JOIN payments pay
ON pre.custId=pay.custId
GROUP BY pre.id, pre.loanAmount, pre.custId
DISTINCT() is not a function in SQL (at least not in any dialect I am familiar with). I would start with this query:
SELECT pre.custId, SUM(pay.amount) AS amount
FROM preQualForm pre INNER JOIN
payments pay
ON pre.custId = pay.custId
GROUP BY pre.custId;
It would seem to return what you want. You can enhance it if this does not return all the information you really want.

SQL Counting and Joining

I'm taking a database course this semester, and we're learning SQL. I understand most simple queries, but I'm having some difficulty using the count aggregate function.
I'm supposed to relate an advertisement number to a property number to a branch number so that I can tally up the amount of advertisements by branch number and compute their cost. I set up what I think are two appropriate new views, but I'm clueless as to what to write for the select statement. Am I approaching this the correct way? I have a feeling I'm over complicating this bigtime...
with ad_prop(ad_no, property_no, overseen_by) as
(select a.ad_no, a.property_no, p.overseen_by
from advertisement as a, property as p
where a.property_no = p.property_no)
with prop_branch(property_no, overseen_by, allocated_to) as
(select p.property_no, p.overseen_by, s.allocated_to
from property as p, staff as s
where p.overseen_by = s.staff_no)
select distinct pb.allocated_to as branch_no, count( ??? ) * 100 as ad_cost
from prop_branch as pb, ad_prop as ap
where ap.property_no = pb.property_no
group by branch_no;
Any insight would be greatly appreciated!
You could simplify it like this:
advertisement
- ad_no
- property_no
property
- property_no
- overseen_by
staff
- staff_no
- allocated_to
SELECT s.allocated_to AS branch, COUNT(*) as num_ads, COUNT(*)*100 as ad_cost
FROM advertisement AS a
INNER JOIN property AS p ON a.property_no = p.property_no
INNER JOIN staff AS s ON p.overseen_by = s.staff_no
GROUP BY s.allocated_to;
Update: changed above to match your schema needs
You can condense your WITH clauses into a single statement. Then, the piece I think you are missing is that columns referenced in the column definition have to be aggregated if they aren't included in the GROUP BY clause. So you GROUP BY your distinct column then apply your aggregation and math in your column definitions.
SELECT
s.allocated_to AS branch_no
,COUNT(a.ad_no) AS ad_count
,(ad_count * 100) AS ad_cost
...
GROUP BY s.allocated_to
i can tell you that you are making it way too complicated. It should be a select statement with a couple of joins. You should re-read the chapter on joins or take a look at the following link
http://www.sql-tutorial.net/SQL-JOIN.asp
A join allows you to "combine" the data from two tables based on a common key between the two tables (you can chain more tables together with more joins). Once you have this "joined" table, you can pretend that it is really one table (aliases are used to indicate where that column came from). You understand how aggregates work on a single table right?
I'd prefer not to give you the answer so that you can actually learn :)