Calculate value in the query by values from two tables - sql

I have product table like this
PRODUCT_ID PACK_SIZE PACK_PRIZE
3000 5 2.5
3001 5 2.5
3002 5 2.5
3003 5 2.5
Order table
order_id client_id
75001 1024
75002 1033
75003 1030
ITEMS Table
ORDER_ID PRODUCT_ID NUMBER_ORDERED
75001 3936 2
75001 3557 5
75001 3012 3
75001 3236 4
Client Table
CLIENT_ID LAST_NAME STATUS
1021 Smith private
1022 Williams corporate
1023 Browne private
1024 Tinsell corporate
These are sample data I just added these just to show sample data.
I want to select top 2 private clients who has done the orders which are having higher values.
I have problem in selecting orders with max sold amount.
Here's what I'm trying to do.
In this I'm trying to get the Client IDS
SELECT CLIENTS.CLIENT_ID
FROM ORDERS
INNER JOIN ITEMS ON ORDERS.ORDER_ID=ITEMS.ORDER_ID
INNER JOIN PRODUCTS ON ITEMS.PRODUCT_ID =PRODUCTS.PRODUCT_ID
INNER JOIN CLIENTS ON ORDERS.CLIENT_ID = CLIENTS.CLIENT_ID
WHERE ( )
In this i'm trying to select top 2 orders
SELECT TOP 2 ORDERS.ORDER_ID FROM ORDERS
INNER JOIN ITEMS ON ORDERS.ORDER_ID=ITEMS.ORDER_ID
INNER JOIN PRODUCTS ON ITEMS.PRODUCT_ID =PRODUCTS.PRODUCT_ID
WHERE ((PRODUCTS.PACK_PRIZE/PRODUCTS.PACK_SIZE)*(ITEMS.NUMBER_ORDERED));
Gives me errors
FROM Key word not found where expected.
What I want to do is select the order ids from orders which are having highest total and which are not from same client, total should be calculated by finding the unit price by dividing pack_price from pack_size and multiplying it by number_ordered from the items table which is having the matching order id. The ordered clients should be corporate clients.
I'm using oracle 11g.
pack_prize is number pack_size is number
number_ordered is number data type

Oracle doesn't support top 2. Instead use rownum and a subquery:
WITH CTE as (
SELECT ORDERS.ORDER_ID, PRODUCTS.PACK_PRIZE, PRODUCTS.PACK_SIZE, ITEMS.NUMBER_ORDERED
FROM ORDERS INNER JOIN
ITEMS
ON ORDERS.ORDER_ID = ITEMS.ORDER_ID INNER JOIN
PRODUCTS
ON ITEMS.PRODUCT_ID = PRODUCTS.PRODUCT_ID
)
SELECT ORDER_ID
FROM (SELECT CTE.*
FROM CTE
ORDER BY (PACK_PRIZE/PACK_SIZE) * NUMBER_ORDERED DESC
) t
WHERE rownum <= 2;
I'm guessing that the strange where expression is what you are using to determine the best rows.

TOP does not work in oracle. You can use the virtual column ROWNUM or the function ROW_NUMBER() OVER() to get similar functionality.

Related

Access subquery for Distinct Count and Count on same table

Hello I have browsed the forum for a while and am asking my first question here. I'm in a bit of a bind and was wondering if I could get some help out. I am using Access and have not found a good answer to the question on the Net yet.
I have a table called tblTransactions for transactions on Access 2013. It looks like this:
Transaction_ID
Customer_No
Prod_ID
Lıcence_ID
1
111
1
1
2
111
1
2
3
222
1
2
4
111
2
1
5
222
2
1
6
222
2
2
7
333
1
1
tblProd looks like:
Prod_ID
Prod_Name
Prod_Price
1
Prod 1
30
2
Prod 2
50
tblLicence looks like:
Lıcence_ID
Lıcence_Name
Lıcence_Price
1
Lıcence 1
80
2
Lıcence 2
100
The customer purchases the product once and may obtain multiple licenses for this product. The product is paid once, but for all licenses owned.
I want to create a summary list for transactions. I cannot print how many different prod it has and how many licenses it has in total next to the customer number.
The output I want should look like this:
Customer_No
Count_Uniq_Prods
Count_Licences
Sum_Prods_Price
Sum_Licences_Price
111
2
3
80
260
222
2
3
80
280
333
1
1
30
80
I tried different methods for the first 3 columns.
When I try with subquery, the Customer number and product count are correct, but it also removes duplicates from licenses.
SELECT C.Customer_No, T2.Count_Uniq_Prods, T2.Count_Licences" & _
FROM" & _
(SELECT T1.Customer_No, T1.Count_Uniq_Prods, Count(Lıcence_ID) As Count_Licences"
FROM" & _
(SELECT DISTINCT Customer_No, Lıcence_ID, Count(Prod_ID) As Count_Uniq_Prods
FROM tblTransactions GROUP BY Customer_No, Lıcence_ID ) AS T1
GROUP BY T1.Customer_No, T1.Count_Uniq_Prods) AS T2
INNER JOIN tblTransactions AS C
ON T2.Customer_No = C.Customer_No" & _
GROUP BY C.Customer_No, T2.Count_Uniq_Prods, T2.Count_Licences;
When I try the left join operation, I can successfully get results for the product and license separately, but when I want to get it in a single table, the results are not what I want.
It's work for Customer_No, Count_Uniq_Prods, Sum_Prods_Price:
SELECT T.Customer_No,
Count(T.Prod_ID), SUM(tblProd.Prod_Price) AS Sum_Prods_Price
FROM ((SELECT DISTINCT Customer_No, Prod_ID FROM tblTransactions ) AS T
LEFT JOIN tblProd ON tblProd.Prod_ID= T.Prod_ID)
GROUP BY T.Customer_No;
It's work for Customer_No, Count_Licences, Sum_Licences_Price:
SELECT T.Customer_No,
Count(T.Lıcence_ID), SUM(tblLicence.[Lıcence_Price]) AS Sum_Licences_Price
FROM ((SELECT Customer_No, Lıcence_ID FROM tblTransactions ) AS T
LEFT JOIN tblLicence ON tblLicence.Lıcence_ID = T.Lıcence_ID)
GROUP BY T.Customer_No
But when I take one as a subquery inside the other, I cannot reach the desired result in both results.
I hope I was able to explain clearly. Thanks in advance for any help.
This should work for you.
My approach was to take your problem and break it down into its constituent elements.
This query retrieves the products in the format that you
requested.
select customer_no, count(t.prod_id) as Count_Uniq_Prods,
sum(p.prod_price) as Sum_Prods_Price
from (
select customer_no, prod_id
from tblTransactions t
group by customer_no, prod_id
) t
inner join tblProd p on
t.prod_id = p.prod_id
group by customer_no
This query retrieves the licenses in the format that you
requested.
select customer_no, count(t. license_id) as Count_Licenses,
sum(l.license_price) as Sum_Licenses_Price
from tblTransactions t
inner join tblLicense l on
t.license_id = l.license_id
group by customer_no
Finally, we put them together and get the following:
select distinct p.customer_no, Count_Uniq_Prods,
Count_Licenses,
Sum_Prods_Price,
Sum_Licenses_Price
from (
select customer_no, count(t.prod_id) as Count_Uniq_Prods,
sum(p.prod_price) as Sum_Prods_Price
from (
select customer_no, prod_id
from tblTransactions t
group by customer_no, prod_id
) t
inner join tblProd p on
t.prod_id = p.prod_id
group by customer_no
) p
inner join (
select customer_no, count(t. license_id) as Count_Licenses,
sum(l.license_price) as Sum_Licenses_Price
from tblTransactions t
inner join tblLicense l on
t.license_id = l.license_id
group by customer_no
) l
on p.customer_no = l.customer_no

SQL Selecting & Counting In the same query

thanks in advance for any help on this, I am a bit of a newbie to MS SQL and I want to do something that I think is achievable but don't have the know how.
I have a simple table called "suppliers" where I can do (SELECT id, name FROM suppliers ORDER BY id ASC)
id
name
1
ACME
2
First Stop Business Supplies
3
All in One Supply Warehouse
4
Farm First Supplies
I have another table called "products"
id
name
supplier_id
1
Item 1
2
2
Item 2
1
3
Item 3
1
4
Item 4
3
5
Item 5
2
I want to list all the suppliers and get the total amount of products for each supplier if that makes sense on the same row? I am just not sure how to pass the suppliers.id through the query to get the count.
I am hoping to get to this:
id
name
total_products
1
ACME
2
2
First Stop Business Supplies
2
3
All in One Supply Warehouse
1
4
Farm First Supplies
0
I really appreciate any help on this.
Three concepts to grasp here. Left Join, group by, and Count().
select s.id, s.name, Count(*) as total_products
from suppliers s
left join products p on s.id=p.supplier_id --the left join gets your no matches
group by s.id, s.name
left join is a join where all of the values from the first table are kept even if there are no matches in the second.
Group by is an aggregation tool where the columns to be aggregated are entered.
Count() is simply a count of transactions for the grouped columns.
Try this :-
SELECT id, name, C.total_products
FROM Suppliers S
OUTER APPLY (
SELECT Count(id) AS total_products
FROM Products P
WHERE P.supplier_id = S.id
) C

Query returns more rows

I have two tables. product_type listing name of products with product id. There are 5 product types which have same product id (1) as they are shared along with 4 other product types with unique product ids (2 to 9). Other table is product. It has the list of customer ids along with what product template id associated with it.
I want to get a list of products which are being used by customer. But I am getting a list with duplicate product rows if there are two customers using the same product. I just want to get a unique list of products being used by all the customers.
Product Table
Product Product_id
AML 1
EDU 1
EXM 1
JEXM 2
JFSA 3
Customer Table
Customer_id Product_id
112 1
113 2
114 1
115 3
116 4
117 2
The query:
SELECT CTE.ProductType, CTE.PRODUCT_ID, DECODE(CT.PRODUCT_ID,NULL,0,1) AS HasCustomer
FROM (
SELECT
LISTAGG(pt.product_type, ', ') WITHIN GROUP (ORDER BY pt.product_type) as ProductType,
pt.PRODUCT_ID
FROM product_type pt
group by pt.PRODUCT_ID) CTE
JOIN CUSTOMER CT ON CT.PRODUCT_ID = CTE.PRODUCT_ID;
Blockquote
I think you want:
SELECT c.customer_id,
LISTAGG(p.product, ', ') WITHIN GROUP (ORDER BY p.product) as products
FROM customers c JOIN
products p
ON c.PRODUCT_ID = p.PRODUCT_ID
GROUP BY c.customer_id;
For each customer, this will give the list of products for the customer.
I based this on your sample data. I don't see the relationship between your query and the sample data.
EDIT:
If you want all products used by any customer, then simply do:
select distinct c.product_id
from customers c;

SQL to fetch Data from 2 tables only using Join where we need empty records from second table as well

We have a situation in which one part of our stored procedure need to be filled with a join query, which had multiple filters in it. We need a solution only with join (it is easy to implement in the subquery, but our situation demands it to be a join [since the procedure has a where clause followed by it] )
We have two tables Customer and Order. We need to exclude the rows of Customer table, if Customer_id is present Order table & order_code = 10 & Customer.Grade = 3. It is not mandatory for all Customer_id to be present in Order table, but we still need it in the final result.
Customer Table OrderTable
Customer_id Grade Customer_id order_code
1 3 1 10
2 3 1 40
3 2 2 50
4 3 3 30
*Multiple Customer_id can be present in the OrderTable
Expected result :
Customer_id Grade
2 3
3 2
4 3
I think this may be what you need, not sure I understand the question properly.
select c.id, c.grade
from customer c left join customer_order o on (c.id = o.customer_id and o.order_code <> 10)
where c.grade = 3
This should give you all customers with a Grade of 3 that also have orders, provided the order_code is not 10. If you want to show customers that do not have any orders also, make it a left join.
You can express the logic like this:
select c.*
from customers c
where not (grade = 3 and
exists (select 1
from orders o
where o.customer_id = c.customer_id and
o.order_code = 10
)
);

Complex SQL Query - Joining 5 tables with complex conditions

I have the following tables: Reservations, Order-Lines, Order-Header, Product, Customer. Just a little explanation on each of these tables:
Reservations Contains "reservations" for a billing customer/product combination.
Order-Lines Contains line item detail for orders, including the product they ordered and the qty.
Order-Header Contains header info for orders including the date, customer and billing customer
Product Contains product detail information
Customer Contains Customer detail information.
Below are the tables with their associated fields and sample data:
Reservation
bill-cust-key prod-key qty-reserved reserve-date
10000 20000 10 05/30/2014
10003 20000 5 06/20/2014
10003 20001 15 06/20/2014
10003 20001 5 06/25/2014
10002 20001 5 06/21/2014
10002 20002 20 06/21/2014
Order-Item
order-num cust-key prod-key qty-ordered
30000 10000 20000 10
30000 10000 20001 5
30001 10001 20001 10
30002 10001 20001 5
30003 10002 20003 20
Order-Header
order-num cust-key bill-cust-key order-date
30000 10000 10000 07/01/2014
30001 10001 10003 07/03/2014
30002 10001 10003 07/15/2014
30003 10002 10002 07/20/2014
Customer
cust-key cust-name
10000 Customer A
10001 Customer B
10002 Customer C
10003 Customer D
Product
prod-key prod-name
20000 Prod A
20001 Prod B
20002 Prod C
20003 Prod D
I am attempting to write a query that will show me customer/product combinations that exist in both the reservation and order-item tables. A little snafu is that we have a customer and a billing customer. The reservation and order-header tables contain both the customers, but the order-item table only contains the customer. The results should display the billing customer. Additionally, there can be several reservations and order-items for the same customer/product combination, so I would like to show a total sum of the qty-reserved and the qty-ordered.
Below is an example of my desired output:
bill-cust-key cust-name prod-key prod-name qty-ordered qty-reserved
10000 Customer A 20000 Prod A 10 10
10003 Customer D 20001 Prod B 15 20
This is the query that I have tried and doesn't seem to be working for me.
SELECT customer.cust-key, customer.cust-name, product.prod-key, prod.prod-name,
SUM(order-item.qty-ordered), SUM(reservation.qty-reserved)
FROM ((reservation INNER JOIN order-item on reservation.prod-key = order-item.product-key)
INNER JOIN order-header on reservation.bill-cust-key = order-header.bill-cust-key and
order-item.order-num = order-header.order-num), customer, product
WHERE customer.cust-key = reservation.bill-cust-key
AND product.prod-key = reservation.prod-key
GROUP BY customer.cust-key, customer.cust-name, product.prod-key, product.prod-name
I'm sorry for such a long post! I just wanted to make sure that I had my bases covered!
You want to join your tables like this:
from reservation res join order-header oh on res.bill-cust-key = oh.bill-cust-key
join order-item oi on oi.order-num = oh.order-num
and oi.prod-key = res.prod-key
/* join customer c on c.cust-key = oi.cust-key old one */
join customer c on c.cust-key = oh.bill-cust-key
join product p on p.prod-key = oi.prod-key
I find that it can be very helpful to separate out your output rows from your aggregate rows by using CROSS APPLY (or OUTER APPLY) or simply an aliased inner query if you don't have access to those.
For example,
SELECT
customer.cust-key,
customer.cust-name,
tDetails.prod-key,
tDetails.prod-name,
tDetails.qty-ordered,
tDetails.qty-reserved
FROM customer
--note that this could be an inner-select table in which you join if not cross-join
CROSS APPLY (
SELECT
product.prod-key,
prod.prod-name,
SUM(order-item.qty-ordered) as qty-ordered,
SUM(reservation.qty-reserved) as qty-reserved
FROM reservation
INNER JOIN order-item ON reservation.prod-key = order-item.product-key
INNER JOIN product ON reservation.prod-key = product.prod-key
WHERE
reservation.bill-cust-key = customer.cut-key
GROUP BY product.prod-key, prod.prod-name
) tDetails
There are many ways to slice this, but you started out the right way saying "what recordset do I want returned". I like the above because it helps me visualize what each 'query' is doing. The inner query marked by the CROSS apply is simply grouping by prod orders and reservations but is filtering by the current customer in the outer top-most query.
Also, I would keep joins out of the 'WHERE' clause. Use the 'WHERE' clause for non-primary key filtering (e.g. cust-name = 'Bob'). I find it helps to say that one is a table join, the 'WHERE' clause is a property filter.
TAKE 2 - using inline queries
This approach still tries to get a list of customers with distinct products, and then uses that data to form the outer query from which you can get aggregates.
SELECT
customer.cust-key,
customer.cust-name,
products.prod-key,
products.prod-name,
--aggregate for orders
( SELECT SUM(order-item.qty-ordered)
FROM order-item
WHERE
order-item.cust-key = customer.cust-key AND
order-item.prod-key = products.prod-key) AS qty-ordered,
--aggregate for reservations
( SELECT SUM(reservation.qty-reserved)
FROM reservations
--join up billingcustomers if they are different from customers here
WHERE
reservations.bill-cust-key = customer.cust-key AND
reservations.prod-key = products.prod-key) AS qty-reserved
FROM customer
--get a table of distinct products across orders and reservations
--join products table for name
CROSS JOIN (
SELECT DISTINCT order-item.prod-key FROM order-item
UNION
SELECT DISTINCT reservation.prod-key FROM reservations
) tDistinctProducts
INNER JOIN products ON products.prod-key = tDistinctProducts.prod-key
TAKE 3 - Derived Tables
According to some quick googling, Progress DB does support derived tables. This approach has largely been replaced with CROSS APPLY (or OUTER APPLY) because you don't need to do the grouping. However, if your db only supports this way then so be it.
SELECT
customer.cust-key,
customer.cust-name,
products.prod-key,
products.prod-name,
tOrderItems.SumQtyOrdered,
tReservations.SumQtyReserved
FROM customer
--get a table of distinct products across orders and reservations
--join products table for name
CROSS JOIN (
SELECT DISTINCT order-item.prod-key FROM order-item
UNION
SELECT DISTINCT reservation.prod-key FROM reservations
) tDistinctProducts
INNER JOIN products ON products.prod-key = tDistinctProducts.prod-key
--derived table for order-items
LEFT OUTER JOIN ( SELECT
order-item.cust-key,
order-item.prod-key,
SUM(order-item.qty-ordered) AS SumQtyOrdered
FROM order-item
GROUP BY
order-item.cust-key,
order-item.prod-key) tOrderItems ON
tOrderItems.cust-key = customer.cust-key AND
tOrderItems.prod-key = products.prod-key
--derived table for reservations
LEFT OUTER JOIN ( SELECT
reservations.bill-cust-key,
reservations.prod-key,
SUM(reservations.qty-reserved) AS SumQtyReserved
FROM reservations
--join up billingcustomers if they are different from customers here
WHERE
reservations.bill-cust-key = customer.cust-key AND
reservations.prod-key = products.prod-key) tReservations ON
tReservations.bill-cust-key = customer.cust-key AND
tReservations.prod-key = products.prod-key
Based on your original code and request, here's the starting point of a Progress solution -
DEFINE VARIABLE iQtyOrd AS INTEGER NO-UNDO.
DEFINE VARIABLE iQtyReserved AS INTEGER NO-UNDO.
FOR EACH order-item
NO-LOCK,
EACH order-header
WHERE order-header.order-num = order-item.order-num
NO-LOCK,
EACH reservation
WHERE reservation.prod-key = order-item.prod-key AND
reservation.bill-cust-key = order-header.bill-cust-key
NO-LOCK,
EACH product
WHERE product.prod-key = reservation.prod-key
NO-LOCK,
EACH customer
WHERE customer.cust-key = reservation.bill-cust-key
NO-LOCK
BREAK BY customer.cust-key
BY product.prod-key
BY product.prod-name
:
IF FIRST-OF(customer.cust-key) OR FIRST-OF(product.prod-key) THEN
ASSIGN
iQtyOrd = 0
iQtyReserved = 0
.
ASSIGN
iQtyOrd = iQtyOrd + reservation.qty-ordered
iQtyReserved = iQtyReserved + reservation.qty-reserved
.
IF LAST-OF(customer.cust-key) OR LAST-OF(product.prod-key) THEN
DISPLAY
customer.cust-key
customer.cust-name
product.prod-key
prod.prod-name
iQtyOrd
iQtyReserved
WITH FRAME f-qty
DOWN
.
END.