Select results get multiplied on joining - sql

I'm using an SQL Server database which has Order table contains a foreign key called invoice_id, this attribute belongs to Invoice table. Also, I have another table called "Receiptwhich also includesinvoice_idandamount_paid` attributes.
Many items can be assigned to the same invoice (customer may make many orders at once), also many receipts can be assigned to the same invoice (customer may make different payments to the same invoice as for example they can pay 50% and then pay the rest later).
So the problem I'm facing is when I try to select the total paid amounts from the Receipt table taking the order_id as a condition, the result will be multiplied according to the number of orders that have the same invoice_id
For example, customer A placed three orders at once, each order cost is 100 USD, which should be 300 USD in the invoice and he already paid that invoice. Now if I query the Receipt table for the paid amounts, the result will be 900 USD (300 USD * 3 orders), which is obviously incorrect.
I'm stuck at this issue, I believe there are some mistakes in my database logic, so please provide me your suggestions to solve this problem and also what should do with the database if the logic is incorrect.
Below is the query i'm using to get the result:
select sum(r.amount_paid), o.invoice_id from RECEIPT r, INVOICE i, ORDER o
where r.invoice_id = i.invoice_id
and o.invoice_id = i.invoice_id
group by o.invoice_id;

Here's three answers to three slightly different questions you might ask of your database.
Amount paid per invoice
If you are trying to get the total amount paid per invoice, all you need is
SELECT SUM(Amount_Paid) Total_Paid,
Invoice_ID
FROM Receipt
GROUP BY Invoice_ID
Amount paid per order
If you want to know the total paid per order, this is not quite possible in your data model as you have described it. If a invoice has three orders on it, and the invoice is only partly paid, there is no way to tell which of the the orders is paid and which is not.
You need some additional data structure that indicates how payments are applied to orders within an invoice, e.g. an Allocation or Split table.
Amount paid on invoices that pertain to one or more orders
On the other hand, if you want to know how much payment has been received on invoices that contain one or more order IDs, you could write this:
SELECT SUM(Amount_Paid) Total_Paid,
Invoice_ID
FROM Receipt
WHERE Invoice_ID IN (SELECT Invoice_ID
FROM Order
WHERE Order_ID IN (1,2,3,4)) --Edit these IDs for your specific case
GROUP BY Invoice_ID
Notice none of the queries above required any joins, so no multiplying :)

Please, try this:
SELECT SUM(r.amount_paid), r.invoice_id FROM RECEIPT r
JOIN INVOICE i ON r.invoice_id = i.invoice_id
JOIN ORDER o ON r.invoice_id = o.invoice_id AND r.order_id = o.order_Id
GROUP BY r.invoice_id;

Related

SQL QUERY for sum loans per customer

enter image description here
I need a query that returns all customers whose name contains the string "Will", and their associated total loan values.
Loan totals should be sorted from largest amount to smallest amount and the loans totals column should be called "TotalLoanValue".
Only one record per customer should be returned.
SELECT name, loan_amount
FROM customers, loans
WHERE name LIKE '%WILL%'
I have wrote that query, but I'm having a hard time to figure out how to sum all the loan values per customer
To say first things first:
If you want to ask further questions here, you should please read and follow this: How to create a good example instead of just adding a link.
Otherwise, you will be on risk that your questions will just be closed and you will never get an answer.
To answer your question:
We need to JOIN the two tables by their common column and then build the SUM of all loan amounts with a GROUP BY clause of the customer name.
I didn't follow your link because I wouldn't know if this is spam, so let's say the customer table has a column "id" and the loan table a column "customer_id".
Then your query will look like this:
SELECT c.name, SUM(l.loan_amount)
FROM customers c
JOIN loan l
ON c.id = l.customer_id
WHERE c.name LIKE '%will%'
GROUP BY c.name
ORDER BY SUM(l.loan_amount) DESC, c.name;
The ORDER BY clause makes sure to begin with the customer having the highest sum of loan amounts.
The "c.name" at the end of the ORDER BY clause could be removed if we don't care about the order if different customers have the same sum of loan amounts.
Otherwise, if we use the query as shown, the result will be sorted by the sum of loan amounts first and then with a second priority by the customer name, i.e. will sort customers having the identic sum of loan amounts by their name.
Try out with some sample data here: db<>fiddle

Sum All Invoices Against Multiple Row PO Line Detail

I have a query which retrieves all Purchase Order line detail, with item specific information on each line related to cost. I wanted to validate this PO total cost detail with a cross reference to our Accounts Payable table. I assumed one PO would have one invoice; that was incorrect. I wanted to joint the payment(s) next to each row of any given PO. I would then be able to Sum my PO line detail and then use an average of the payment to calculate a variance between the PO detail and the actual payment from AP. My query returns all payments to one PO, creating a duplication problem.
Is there a simple way to Sum all payments against one distinct PO?
My current select statement is pretty simple and left joins the AP payment column to the PO received rows. If I had a one to one relationship between PO numbers and Invoice payments, I wouldn't have this issue. Alas, here we are. I'm using SQL Server 2014 Management Studio to drive the query.
you could use the following
SElect SUM (actualPOAmount), sum(extpoAmount) , PO.PONUM
FRom PO_Table PO (nolock)
JOIN PO_Invoice INV (nolock) on INV.PONUM = po.PONUM
group by PO.PONUM

GROUP BY clause with logical functions

I'm using Oracle 11g Application Express, and executing these commands within the SQL Plus CLI. This is for a class, and I cannot get past this problem. I don't know how to add the total quantity of the items on the orders - I get confused as I don't know how to take the SUM of the QUANTITY per ORDER (customers have multiple orders).
For each customer having an order, list the customer number, the number of orders
that customer has, the total quantity of items on those orders, and the total price for
the items. Order the output by customer number. (Hint: You must use a GROUP BY
clause in this query).
Tables (we will use):
CUSTOMER: contains customer_num
ORDERS: contains order_num, customer_num
ITEMS: contains order_num, quantity, total_price
My logic: I need to be able to calculate the sum of the quantity per order number per customer. I have sat here for over an hour and cannot figure it out.
So far this is what I can formulate..
SELECT customer_num, count(customer_num)
FROM orders
GROUP BY customer_num;
I don't understand how to GROUP BY very well (yes, I have googled and researched it for a bit, and it just isn't clicking), and I have no clue how to take the SUM of the QUANTITY per ORDER per CUSTOMER.
Not looking for someone to do my work for me, just some guidance - thanks!
select o.customer_num,
count(distinct o.order_num) as num_orders,
sum(i.quantity) as total_qty,
sum(i.total_price) as total_price
from orders o
join items i
on o.order_num = i.order_num
group by o.customer_num
order by o.customer_num
First thing:
you have to join the two tables necessary to solve the problem (orders and items). The related field appears to be order_num
Second thing:
Your group by clause is fine, you want one row per customer. But because of the join to the items table, you will have to count DISTINCT orders (because there may be a one to many relationship between orders and items). Otherwise an order with 2 different associated items would be counted twice.
Next, sum the quantity and total price, you can do this now because you've joined to the needed table.
This is also solved by using WHERE:
SELECT orders.customer_num, /*customer number*/
COUNT(DISTINCT orders.order_num) AS "num_orders", /*number of orders/c*/
SUM(items.quantity) as "total_qty", /*total quantity/c*/
SUM(items.total_price) as "total_price" /*total price/items*/
/* For each customer having an order, list the customer number,
the number of orders that customer has, the total quantity of items
on those orders, and the total price for the items.
Order the output by customer number.
(Hint: You must use a GROUP BY clause in this query). */
FROM orders, items
WHERE orders.order_num = items.order_num
GROUP BY orders.customer_num
ORDER BY orders.customer_num
;

SQL to find the average amount of money spent by country?

I need to find the average amount of money spent by country, using the two tables below in oracle. Sale_total is the money spent in each sale and Cust_country is the customer's country. Any help would be greatly appreciated.
Tables
Sale
Sale_Id
Payment_ID
Ship_Id
Customer_ID
Sale_total ==> Money Spent
Sale_date
Sale_time
Customer
Cust_name
Cust_address
Cust_city
Cust_country
Cust_phone
Cust_age
Cust_sex
You need to have a link between the Sale and Customer tables. Presumably place Customer_ID in the Customer table as a primary key, and have Customer_ID in the Sale table be a foreign key. Assuming you do that, you can then run the below query.
SELECT
AVG(S.Sale_Total) Spent,
c.Cust_country
FROM
Sale S
INNER JOIN
Customer C on S.Customer_ID=C.Customer_ID
GROUP BY C.Cust_Country
This tells you the average amount spent, and the country where it was spent.
The key to understanding this answer is that AVG (the average function) is an aggregate function, as it combines things. Often when you have an aggregate function, you have to group the other columns, hence why we included the GROUP BY clause.
The reason you need Customer Id in the Customer table (apart from being the logical place for it) is so that you can establish a relationship between the Customer and Sale tables.
Another way to establish the relation is you can create a new table to link Customer and Sale together. Call it Customer Sales. For example:
Customer_Sales
Customer_Id
Sale_Id
Then you'd adjust the query to join based on that.
Try this:
SELECT C.Cust_country as Country, AVG(S.Sale_total) as Spent
FROM Sale S INNER JOIN
Customer C on S.Customer_ID=C.Customer_ID
GROUP BY C.Cust_country
AVG is an aggregate function that evaluates the average of an expression over a set of rows.
Read more about here.

grouping common results in sql

I have a products table, with the fields product, category and cost, of type varchar, varchar and decimal.
I then have a sales table, with the fields client, productname, quantity, cost, and saledate, of type varchar, varchar, int, decimal and date.
I want to show all of the products sold for a month, say the current month.
However, I donĀ“t want to show every sale individually. I want to automatically add all of one product together and show it as one row.
In the sales table, the cost for each sales record is already multiplied by the quantity.
So for example, to if 5 beers were purchased, it would returned as one row showing name as beers, quanity as 5, and cost as however much.
I need something like say:
Select product, cost from sales, WHERE sales.product=products.name
AND category='food' AND WHERE month(date_field) = month(getdate())
This should show all the sales for a certain category of product for the current month, but is there an easy way to "group" products together?
I would have to take into account the quantity field in the sales table, because one sale is not necessarily only one product
A hopefully clearer example, one sale record maybe for 2 beers for one client with a cost of 10, and another sales record may be to a different client with a quantity of 3 and cost of 15. I want just one record that would say for beer, 5 were sold and the total cost is 25.
I have no idea where to go from as far as I have gotten...
You are looking for something like
Select product, cost from sales,products WHERE sales.product=products.name
AND category='food' AND month(date_field) = month(getdate())
To get a listing of the items linked as you suggest according to the category in the products tables.
To get the summary by category you need something like:
Select category,SUM(Sales.Quantity),SUM(Sales.cost) from
sales,products WHERE sales.product=products.name
AND category='food' AND month(date_field) = month(getdate()) group by category
This will work but there is a lot to criticise in your database structure, specifically to link products by name as you do is not very reliable.
This question looks awfully familiar...
The answer is a SQL GROUP BY statement.
SELECT product, SUM(quantity) FROM sales s, products p WHERE product=p.name AND category='food' AND month(date_field)=month(getdate()) GROUP BY product
The SUM(quantity) above will tally up all the units sold of a particular product in the given month.
Use GROUP BY and COUNT
SELECT productname, cost, COUNT(*) AS cnt
FROM sales LEFT JOIN products ON sales.product = products.productname
WHERE category='food' AND month(date_field) = month(getdate())
GROUP BY productname