I have an online sales system I am developing and I’m working on the billing payment system.
I have the order total $ amount recorded on the database table with the order itself.
Example:
SELECT total FROM Orders WHERE id = '1'
Then, I’ve got another table that includes an individual record for each financial transaction (check, cc, etc.)
Example:
SELECT payment_amount FROM Payments WHERE order_id = '1'
What I would like to do is combine these two together when doing some reporting of which orders have not been paid in full and retrieve the balance of each order. I’d like to do this with a single query if possible...
This was what I tried...
SELECT o.id as order_id, o.total, (SELECT p.payment_amount FROM Payments as p WHERE o.order_id = o.id) as amount_paid_plus FROM Orders as o
This works great if there is only 1 entry in payments...but if there are two, I get this error
Subquery returns more than 1 row
I want the payments table results to be added together into one lump sum amount and returned as one variable in the query
I also need the query to still return info even if there are no payments in the payments table. It will just display amount paid as 0.
You can just change p.payment_amount to SUM(p.payment_amount) in your subquery. Note that you have an error in the subquery, it should probably be
(SELECT SUM(p.payment_amount) FROM Payments as p WHERE p.order_id = o.id)
Note change from o.order_id to p.order_id.
Try this query :
SELECT o.id, o.total, SUM(p.payment_amount) FROM Orders o, Payments p where p.order_id = o.id
Related
I have three tables customers, orders, and payments. payments table has a foreign key order_id, which references the orders table on the id field, however, the payments table can also accept payment without any order, i.e.( advance payment received without any order being placed.) conversely it is also possible that there could be orders without any payment e.g. orders created on credit without any payment.
now my query is I want to generate a day-closing table where I want to list all orders if any or all payments if any for a particular date.
I have tried to join the orders table with the payment table on order_date and payment_date but the result is not as per my requirement. i.e. if there are no orders on a particular date but there are payments then I don't get any results.
I have created a scenario on dB fiddle for the same. dbfiddle
if anybody can give me a solution, it will be an immense help.
as per the scenario on dB fiddle
I tried the following query.
select
o.id,
o.order_date,
o.customer,
o.inv_number,
p.pymt,
p.cash,
p.bank
from
orders o
left join
(select
pymt_date,
sum(amount) pymt,
sum(cash) cash,
sum(bank) bank
from
payments
group by
pymt_date) p
on
o.order_date = p.pymt_date
where
o.order_date = '2022/10/25'
but I am not getting any results.
The questions asks,
"Write a query to display the customer name and the number of payments they have made where the amount on the check is greater than their average payment amount. Order the results by the descending number of payments."
So far I have,
SELECT customerName,
(SELECT COUNT(checkNumber) FROM Payments WHERE
Customers.customerNumber = Payments.customerNumber) AS
NumberOfPayments
FROM Customers
WHERE amount > SELECT AVG(amount)
ORDER BY NumberOfPayments DESC;
But I am getting a syntax error every-time I run out. What am I doing incorrectly in this situation?
The syntax error comes from the fact that you are having an incorrect second subquery: amount > SELECT AVG(amount) doesn't work.
You could use amount > (SELECT AVG(amount) FROM Payments).
That is: complete the subquery and put it between ( ).
However this won't do what you want (plus it is inefficient).
Now since this is not a forum to do your homework for you, I will leave it at this and thus only help you with the actual question: why do you get the syntax error. Keep on looking, you will find it. No better way to learn than to search and find yourself.
I would phrase this as an inner join between the two tables, with a correlated subquery to find the average payment amount per customer:
SELECT
c.customerName,
COUNT(CASE WHEN p.amount > (SELECT AVG(p2.amount) FROM Payments p2
WHERE p2.customerName = c.customerName)
THEN 1 END) AS NumberOfPayments
FROM Customers c
INNER JOIN Payments p
ON c.customerNumber = p.customerNumber
GROUP BY
c.customerNumber
ORDER BY
NumberOfPayments DESC;
Your current query is on the right track, but you need to do something called conditional aggregation to obtain the count. In this case, we aggregate by customer then assert that a given payment amount is greater than his average before we include it in the count.
I would approach this just using JOINs:
SELECT c.customerName,
SUM( p.amount > p2.avg_amount ) as Num_Payments_Larger_Than_Average
FROM Customers c LEFT JOIN
Payments p
ON c.customerNumber = p.customerNumber LEFT JOIN
(SELECT p2.customerNumber, AVG(amount) as avg_amount
FROM payments p2
GROUP BY p2.customerNumber
) p2
ON p2.customerNumber = p.customerNumber
GROUP BY c.customerNumber, c.customerName
ORDER BY Num_Payments_Larger_Than_Average;
Some notes about this answer. First, it uses LEFT JOIN and conditional aggregation. This allows the query to return customers with zero payments larger than their average -- that is, customers with no payments or all of whose payments are the same.
Second, it includes customerNumber in the GROUP BY. I think this is important, because it may be possible for two customers to have the same name.
I am really having a headache since the other day on how to fix this mysql statement to get my desired result. I also want to inform that I am new to mysql and prorgramming.
I have 4 tables CUSTOMER, CUSTOMER_ACCT_SETTING, DEBT, and PAYMENT.
Here are the 4 tables with their record so you can relate.
CUSTOMER
CUSTOMER_ACCT_SETTING
DEBT
PAYMENT
When I run this mysql statement:
SELECT C.CUSTOMER_ID, C.NAME, C.ADDRESS, C.CONTACT_NUMBER,
SUM(((CAS.INTEREST_RATE / 100) * D.AMOUNT) + D.AMOUNT) - COALESCE(SUM(P.AMOUNT), 0) AS CURRENT_BALANCE
FROM CUSTOMER C
INNER JOIN CUSTOMER_ACCT_SETTING CAS ON (C.CUSTOMER_ID = CAS.CUSTOMER_ID)
LEFT JOIN DEBT D ON (C.CUSTOMER_ID = D.CUSTOMER_ID)
LEFT JOIN PAYMENT P ON C.CUSTOMER_ID = P.CUSTOMER_ID
GROUP BY (C.CUSTOMER_ID)
ORDER BY C.NAME
The result is below:
PS: The result is ordered by name.
My question is:
1.) Why did I get a negative result on the CURRENT_BALANCE column in the first row? I am expecting the result to be around 16374.528.
My desired result is like this:
You are projecting your payments through all your debts by doing a join with both tables at the same time. So you essentially get 5 applications of your payment on customer 4 and zero applications on all the other customers. (so NULL on P.AMOUNT yields X - NULL = NULL). To see this, remove the "GROUP BY" and the "SUM" and just return your amounts paid and debited. Then if you group/sum these results manually by customer, you'll see what's going on.
To get the results you expect, you will need to use subqueries or some other mechanism like temporary tables. Something like this:
SELECT C.CUSTOMER_ID,
(SELECT SUM(P.AMOUNT) FROM PAYMENT P
WHERE P.CUSTOMER_ID = C.CUSTOMER_ID) AS TOTAL_PAID_BY_CUSTOMER
FROM CUSTOMER C
The answer to #1 is that each row in your result set has the payment attached to it. That is, for customer #1, you're getting three instances of the 8132.
I have 3 tables:
Orders
- id
- customer_id
Details
- id
- order_id
- product_id
- ordered_qty
Parcels
- id
- detail_id
- batch_code
- picked_qty
Orders have multiple Details rows, a detail row per product.
A detail row has multiple parcels, as 10'000 ordered qty may come from 6 different batches, so goods from batches are packed and shipped separately. The picked quantity put in each parcel for a detail row should then be the same as the ordered_qty.
... hope that makes sense.
Im struggling to write a query to provide summary information of all of this.
I need to Group By customer_id to provide a row of data per customer.
That row should contain
Their total number of orders
Their total ordered_qty of goods across all orders
Their total picked_qty of goods across all orders
I can get the first one with:
SELECT customer_id, COUNT(*) as number_of_orders
FROM Orders
GROUP BY Orders.customer_id
But when I LEFT JOIN the other two tables and add the
SELECT ..... SUM(Details.ordered_qty) AS total_qty_ordered,
SUM(Parcels.picked_qty) AS total_qty_picked
.. then I get results that dont seem to add up for the quantities, and the COUNT(*) seems to include the additional lines from the JOIN which obviously then isn't giving me the number of Orders anymore.
Not sure what to try next.
===== EDIT =======
Here's the query I tried:
SELECT
customer_id,
COUNT(*) as number_of_orders,
SUM(Details.ordered_qty) AS total_qty_ordered,
SUM(Parcels.picked_qty) AS total_qty_picked
FROM Orders
LEFT JOIN Details ON Details.order_id=Order.id
LEFT JOIN Parcels ON Parcels.detail_id=Detail.id
GROUP BY Orders.customer_id
try COUNT(distinct Orders.order_id) as number_of_orders,
as in
SELECT
customer_id,
COUNT(distinct Orders.order_id) as number_of_orders,
SUM(Details.ordered_qty) AS total_qty_ordered,
(select SUM(Parcels.picked_qty)
FROM Parcels WHERE Parcels.detail_id=Detail.id ) AS total_qty_picked
FROM Orders
LEFT JOIN Details ON Details.order_id=Order.id
GROUP BY Orders.customer_id
EDIT: added an other select with subselect
Is there any particular reason you feel the need to combine all these in one query? Simplify by breaking it up in to separate queries, and if you want a single call to get the results, put the queries in a stored procedure, using temp tables.
I have an issue with joining of tables that I have not managed to solve. Somehow I have the impression that it is more simple than I think. Anyhow:
I have three tables:
orders
orderlines
payments
In "orders" every line corresponds to one order made by a customer. Every order has an order_id which is the primary key for that table. In "orderlines" I keep the content of the order, that is references to the products and services on the order. One order can, and typically has, many orderlines. Finally, in payments I store one row for every transaction made to pay for an order.
One order ideally never has more than one corresponding row in payments. But since customers are customers it is not unusual that someone pays the same invoice twice, hinting that the payments table can have two or more payments for one order.
Therefore it would be useful to create a query that joins all three tables in a relevant way, but I have not managed to do so. For instance:
SELECT orders.order_id, SUM(orderlines.amount), SUM(payments.amount)
FROM orders
LEFT JOIN orderlines
ON orders.order_id = orderlines.order_id
LEFT JOIN payments
ON orders.order_id = payments.order_id
GROUP BY orders.order_id
The purpose of this join is to find out if the SUM of the products on the order equals the SUM in payments. The problem here is that the two tables payments and orderlines "distract" each other by both causing multiple rows while joining.
Is there a simple solution to this problem?
Maybe I'm overcomplicating things, but using both tables and producing the sum would always lead too wrong results, i.e. one order has 10 orderline rows and 1 payment rows => the payment amount is going to be added 10 times. I guess you have to use subselects like this below (you didn't use anything from your table "orders" but the id, so I left it out, because all orders have orderlines):
SELECT t1.order_id, t1.OrderAmount, t2.PaymentAmount
FROM (SELECT SUM(amount) AS OrderAmount, order_id
FROM orderlines
GROUP BY order_id) AS t1
LEFT JOIN (SELECT SUM(amount) AS PaymentAmount, order_id
FROM payments
GROUP BY order_id) AS t2
ON t1.order_id=t2.order_id
I think what you want to do is get the sum of all the items, and the sum of all the payments, and then link them together. A sub-select is able to do this.
Something like: (ps I have no database on hand so it might not be valid sql)
SELECT * FROM orders
LEFT JOIN (SELECT order_id, SUM(amount) FROM orderlines GROUP BY order_id) AS ordersums
ON orders.order_id = ordersums.order_id
LEFT JOIN (SELECT order_id, SUM(amount) FROM payments GROUP BY order_id) AS paymentsums
ON orders.order_id = paymentsums.order_id;