SQL Lab Query Assistance - sql

CNum DNum RNum Quant Price
C100 D1 R10 2 8.99
C100 D1 R40 7 9.99
C200 D3 R10 4 16.99
C200 D3 R20 2 15.99
C200 D3 R30 2 17.99
C200 D3 R40 5 19.99
C200 D3 R50 6 18.99
Hey guys, the above table is Named "Orders." I have a few queries I'm trying to solve for a Lab for a Database Management class I'm currently taking. A few of these queries are giving me some issues, if some of you wouldn't mind helping me out or walking me through some that would be great. The one I'm stuck on now is stated
"Get customer numbers (CNum) for customers that ordered dish D1 from some restaurant in a quantity greater than the average quantity of dish D1 for that restaurant."
another that I am having some trouble with is quite similar
"Get restaurant numbers (RNum) for restaurants that have orders of dish D1 in an average quantity less than the greatest quantity for any dish ordered from restaurant R10"
I gave #2 here a shot and came up with the following:
SELECT DISTINCT O.RNum
FROM Orders AS O
WHERE (O.DNum = 'D1')
AND EXISTS
(SELECT AVG(O.Quant) AS AvgQuant
FROM Orders AS O
WHERE EXISTS
(SELECT MAX(O.Quant) AS MaxQuant
FROM Orders AS O
WHERE (O.RNum = 'R10')))
With that in mind I currently believe this query to be incorrect due to the fact that I have not specified that the AvgQuant must be LESS THAN the MaxQuant, and am unsure of what the correct syntax would be. So my question here would be, how do I express that the AvgQuant must be less than the MaxQuant, and we have not used joins yet in this class.

For the first question:
Build an aggregate query that returns the average quantity for each restaurant and dish.
Build an aggregate query that returns the sum quantity for each customer and restaurant and dish.
Build a query that joins the first two on the restaurant and dish fields.
SELECT Query2.CNum, Query2.RNum, Query2.DNum, Query2.Cust_Rest_Dish_Sum
FROM Query2 INNER JOIN Query1 ON (Query2.DNum = Query1.DNum) AND (Query2.RNum = Query1.RNum)
WHERE (((Query2.Cust_Rest_Dish_Sum)>[Rest_Dish_Avg]));
Without JOIN clause:
SELECT Query2.CNum, Query2.RNum, Query2.DNum, Query2.Cust_Rest_Dish_Sum, Query1.RNum, Query1.DNum
FROM Query2, Query1
WHERE (((Query2.Cust_Rest_Dish_Sum)>[Rest_Dish_Avg]) AND ((Query1.RNum)=[Query2].[RNum]) AND ((Query1.DNum)=[Query2].[DNum]));
The data sample seems inadequate to test the query. No records will return. So I added another record and it is the only customer returned in the query.
CNum DNum RNum Quant Price
C200 D1 R10 5 22.49
Consider this for question 2 - no join used but really should:
SELECT DISTINCT Query4.RNum, Query4.DNum, Query4.AvgOfQuant, Query3.MaxOfQuant
FROM (SELECT Orders.RNum, Max(Orders.Quant) AS MaxOfQuant
FROM Orders
GROUP BY Orders.RNum
HAVING (((Orders.RNum)="R10"))) AS Query3, (SELECT Orders.RNum, Orders.DNum, Avg(Orders.Quant) AS AvgOfQuant
FROM Orders
GROUP BY Orders.RNum, Orders.DNum) AS Query4
WHERE (((Query4.DNum)="D1") AND ((Query4.AvgOfQuant)<[MaxOfQuant]));

Related

How can I select multiple records from more that two tables

I am a complete beginner in SQL and need some help to learn. I have this learning material I found online and trying to write queries per the instructions. I did the first but got stuck on the rest of the queries. Can anyone please help me write any one of the queries below?
[]
Please help me learn how to do the rest.
b) Get aids and names of agents who have placed individual orders of at least $500 for any customer living
in Kyoto.
c) What cities do those customers live in, who enjoy discount under 10% and have ordered at least 1000
combs so far (in all their orders put together)?
d) What product names have been ordered by at least one customer based in Dallas through any agent based
in Tokyo?
e) Get the name, city, and total dollar amount of all orders placed by each customer, arranged in descending
order of the amounts.
Here is how I managed to do the first one.
a) Get pairs of all customer cids and agent aids, who live in the same city.
SELECT customer.cid, agent.aid FROM customers, agent WHERE customer.city = agent.city
RESULT
cid
aid
c001
a05
c004
a05
c002
a06
c003
a06
Try this one for b
SELECT distinct Agents.City -- Distinct becuase you dont want more then one of the same city being returned
FROM Agents
JOIN Orders
ON orders.aid = agents.aid
WHERE orders.cid = 'c002' -- Checks the orders table for any cid equal to c002

Need help to build a sales funnel report by sql query

I have created a view for sales.In this view, there are relations among lead, opportunity and quotation. We can see not every lead turns to opportunity and quotation.
LeadID OfferingID QuotationID Product Salesperson Department Date Salesprice
L1 O1 Q1 X001 Mr.X Machine Sales 11-01-2011 100
L2 O2 Q2 X002 Mr.Y Marine Sales 10-02-2011 200
L3 O3 X003 Mr.Z Engine Sales 11-03-2011 300
L4 O4 Q3 X004 Mr.P Parts Sales 13-04-2011 50
L5 X001 Mr.X Machine Sales 20-05-2012 100
L6 O5 X001 Mr.X Machine Sales 30-06-2012 100
My final output for the sales funnel for all department will be like [total number of leads (6)]->[total number of offering(5)]->[total number of quotations(3)].
If i want to filter it by 'Machine Sales' department ,the funnel will be like:
[total number of leads (3)]->[total number of offering(2)]->[total number of quotations(1)]..
i need to be able to filter the funnel by date,salesperson,product and department.please help me to build this sales funnel query.
i will then visualize the data in microsoft powerbi after implementing the query which will be in a funnel shape.
Is there anything stopping you from feeding this data directly into Power BI?
I think you might be over-engineering this problem, and creating another table/view on you database that you'll have to remember/manage.
Leads = COUNT('YourTableNameHere'[LeadID])
Offers = COUNT('YourTableNameHere'[OfferID])
Quotes = COUNT('YourTableNameHere'[QuoteID])
This is very straightforward conditional aggregation with a group by:
select date
,salesperson
,etc
,sum(case when LeadID <> '' then 1 end) as NumberOfLeads
,etc
from YoutTable
group by date
,salesperson
,etc
If your LeadID, OfferingID and QuotationID columns have null values where there is no data you don't even need the conditional within the aggregate and can instead just use count as the null values are ignored:
select ...
,count(LeadID) as NumberOfLeads
,...
etc
I think you want:
select department, count(leadid) as num_leads, count(offeringid) as numoffers,
count(distinct quotationid) as numquotations
from t
group by department;
I don't think count(distinct) is needed for the first two columns, but your data has no examples of duplicates so it is unclear.

JOIN the same table on two columns

I use JOINs to replace country and product IDs in import and export data with actual country and products names stored in separate tables. In the data source table (data), there are two columns with country IDs, for origin and destination, both of which I am replacing with country names.
The code I have come up with refers to the country_names table twice – as country_names, and country_names2, – which doesn’t seem to be very elegant. I expected to be able to refer to the table just once, by a single name. I would be grateful if someone pointed me to a more elegant and maybe more efficient way to achieve the same result.
SELECT
country_names.name AS origin,
country_names2.name AS dest,
product_names.name AS product,
SUM(data.export_val) AS export_val,
SUM(data.import_val) AS import_val
FROM
OEC.year_origin_destination_hs92_6 AS data
JOIN
OEC.products_hs_92 AS product_names
ON
data.hs92 = product_names.hs92
JOIN
OEC.country_names AS country_names
ON
data.origin = country_names.id_3char
JOIN
OEC.country_names AS country_names2
ON
data.dest = country_names2.id_3char
WHERE
data.year > 2012
AND data.export_val > 1E8
GROUP BY
origin,
dest,
product
The table to convert product IDs to product names has 6K+ rows. Here is a small sample:
id hs92 name
63215 3215 Ink
2130110 130110 Lac
21002 1002 Rye
2100200 100200 Rye
52706 2706 Tar
20902 902 Tea
42203 2203 Beer
42302 2302 Bran
178703 8703 Cars
The table to convert country IDs to country names (which is the table I have to JOIN on twice) has 264 rows for all countries in the world. (id_3char is the column used.) Here is a sample:
id id_3char name
euchi chi Channel Islands
askhm khm Cambodia
eublx blx Belgium-Luxembourg
eublr blr Belarus
eumne mne Montenegro
euhun hun Hungary
asmng mng Mongolia
nabhs bhs Bahamas
afsen sen Senegal
And here is a sample of data from the import and export data table with a total of 205M rows that has the two columns origin and dest that I am making a join on:
year origin dest hs92 export_val import_val
2009 can isr 300410 2152838.47 3199.24
1995 chn jpn 590190 275748.65 554154.24
2000 deu gmb 100610 1573508.44 1327.0
2008 deu jpn 540822 10000.0 202062.43
2010 deu ukr 950390 1626012.04 159423.38
2006 esp prt 080530 2470699.19 125291.33
2006 grc ind 844859 8667.0 3182.0
2000 ltu deu 630399 6018.12 5061.96
2005 usa zaf 290219 2126216.52 34561.61
1997 ven ecu 281122 155347.73 1010.0
I think you already have it done such that it can be considered good enough to just use as is :o)
Meantime, If for some reason you really-really want to avoid two joins on that country table - what you can do is to materialize below select statement into let's say `OEC.origin_destination_pairs` table
SELECT
o.id_3char o_id_3char,
o.name o_name,
d.id_3char d_id_3char,
d.name d_name
FROM `OEC.country_names` o
CROSS JOIN `OEC.country_names` d
Then you can just join on that new table as below
SELECT
country_names.o_name AS origin,
country_names.d_name AS dest,
product_names.name AS product,
SUM(data.export_val) AS export_val,
SUM(data.import_val) AS import_val
FROM OEC.year_origin_destination_hs92_6 AS data
JOIN OEC.products_hs_92 AS product_names
ON data.hs92 = product_names.hs92
JOIN OEC.origin_destination_pairs AS country_names
ON data.origin = country_names.o_id_3char
AND data.dest = country_names2.d_id_3char
WHERE data.year > 2012
AND data.export_val > 1E8
GROUP BY
origin,
dest,
product
The motivation behind above is cost of storing and querying in your particular case
Your `OEC.country_names` table is just about 10KB in size
Each time you query it you pay as if it is 10MB (Charges are rounded to the nearest MB, with a minimum 10 MB data processed per table referenced by the query, and with a minimum 10 MB data processed per query.)
So, if you will materialize above mentioned table - it will still be less than 10MB so no difference in querying charges
Similar situation with storing that table - no visible changes in charges
You can check more about pricing here

DB2 Select from two tables when one table requires sum

In a DB2 Database, I want to do the following simple mathematics using a SQL query:
AvailableStock = SupplyStock - DemandStock
SupplyStock is stored in 1 table in 1 row, let's call this table the Supply table.
So the Supply table has this data:
ProductID | SupplyStock
---------------------
109 10
244 7 edit: exclude this product from the search
DemandStock is stored in a separate table Demand, where demand is logged as each customer logs demand during a customer order journey. Example data from the Demand table:
ProductID | DemandStock
------------------------
109 1
244 4 edit: exclude this product
109 6
109 2
So in our heads, if I want to calculate the AvailableStock for product '109', Supply is 10, Demand for product 109 totals to 9, and so Available stock is 1.
How do I do this in one select query in DB2 SQL?
The knowledge I have so far of some of the imagined steps in PseudoCode:
I select SupplyStock where product ID = '109'
I select sum(DemandStock) where product ID = '109'
I subtract SupplyStock from DemandStock
I present this as a resulting AvailableStock
The results will look like this:
Product ID | AvailableStock
109 9
I'd love to get this selected in one SQL select query.
Edit: I've since received an answer (that was almost perfect) and realised the question missed out some information.
This information:
We need to exclude data from products we don't want to select data for, and we also need to specifically select product 109.
My apologies, this was omitted from the original question.
I've since added a 'where' to select the product and this works for me. But for future sake, perhaps the answer should include this information too.
You do this using a join to bring the tables together and group by to aggregate the results of the join:
select s.ProductId, s.SupplyStock, sum(d.DemandStock),
(s.SupplyStock - sum(d.DemandStock)) as Available
from Supply s left join
Demand d
on s.ProductId = d.ProductId
where s.ProductId = 109
group by s.ProductId, s.SupplyStock;

SQL SUM with Repeating Sub Entries - Best Practice?

I hit this issue regularly but here is an example....
I have a Order and Delivery Tables. Each order can have one to many Deliveries.
I need to report totals based on the Order Table but also show deliveries line by line.
I can write the SQL and associated Access Report for this with ease ....
SELECT xxx
FROM
Order
LEFT OUTER JOIN
Delivery on Delivery.OrderNO = Order.OrderNo
until I get to the summing element. I obviously only want to sum each Order once, not the 1-many times there are deliveries for that order.
e.g. The SQL might return the following based on 2 Orders (ignore the banalness of the report, this is very much simplified)
Region OrderNo Value Delivery Date
North 1 £100 12-04-2012
North 1 £100 14-04-2012
North 2 £73 01-05-2012
North 2 £73 03-05-2012
North 2 £73 07-05-2012
South 3 £50 23-04-2012
I would want to report:
Total Sales North - £173
Delivery 12-04-2012
Delivery 14-04-2012
Delivery 01-05-2012
Delivery 03-05-2012
Delivery 07-05-2012
Total Sales South - £50
Delivery 23-04-2012
The bit I'm referring to is the calculation of the £173 and £50 which the first of which obviously shouldn't be £419!
In the past I've used things like MAX (for a given Order) but that seems like a fudge.
Surely there must be a regular answer to this seemingly common problem but I can't find one.
I don't necessarily need the code - just a helpful point in the right direction.
Many thanks,
Chris.
A roll up operator may not look pretty. However, it would do the regular aggregates that you see now, and it show the subtotals of the order. This is what you're looking for.
SELECT xxx
FROM
Order
LEFT OUTER JOIN
Delivery on Delivery.OrderNO = Order.OrderNo
GROUP BY xxx
WITH ROLLUP;
I'm not exactly sure how the rest of your query is set up, but it would look something like this:
Region OrderNo Value Delivery Date
North 1 £100 12-04-2012
North 1 £100 14-04-2012
North 2 £73 01-05-2012
North 2 £73 03-05-2012
North 2 £73 07-05-2012
NULL NULL f419 NULL
I believe what you want is called a windowing function for your aggregate operation. It looks like the following:
SELECT xxx, SUM(Value) OVER (PARTITION BY Order.Region) as OrderTotal
FROM
Order
LEFT OUTER JOIN
Delivery on Delivery.OrderNO = Order.OrderNo
Here's the MSDN article. The PARTITION BY tells the SUM to be done separately for each distinct Order.Region.
Edit: I just noticed that I missed what you said about orders being counted multiple times. One thing you could do is SUM() the values before joining, as a CTE (guessing at your schema a bit):
WITH RegionOrders AS (
SELECT Region, OrderNo, SUM(Value) OVER (PARTITION BY Region) AS RegionTotal
FROM Order
)
SELECT Region, OrderNo, Value, DeliveryDate, RegionTotal
FROM RegionOrders RO
INNER JOIN Delivery D on D.OrderNo = RO.OrderNo