SQL get a column as comma-seperated values from a subquery - sql

I have these tables in my postresql:-
1.Payment(id, number, amount)
2.Invoice(id, number, amount)
and a invoice_payment table to allocate payments amount to invoices
3.InvoicePayment(id, payment_id, invoice_id, amount)
Single payment can be allotted to many invoices.
Now I want payment details, but I also want invoices.number of the invoices this payment is allotted to. I am doing something like this:-
SELECT
payments.number,
payments.amount,
(SELECT invoices.number from invoices INNER JOIN invoice_payments
ON invoices.id = invoice_payments.invoice_id
WHERE invoice_payments.payment_id = payments.id)
from payments
But it gives me error more than one row returned by a subquery. How do I make the invoice number comma-seperated for every payments row?
Sample data:-
Payment
id number amount
1 "Pay001" 100
2 "Pay002" 150
3 "Pay003" 150
Invoice
id number amount
1 "INV001" 100
2 "INV002" 200
3 "INV003" 100
InvoicePayment
id payment_id invoice_id amount
1 1 1 50
2 1 2 50
3 2 2 150
4 3 1 50
5 3 3 100
Result:-
payment_id payment_number amount invoices
1 "Pay001" 100 "INV001, INV002"
2 "Pay002" 150 "INV002"
3 "Pay003" 150 "INV001, INV002"

You can use string_agg function in postgres to concatenate rows, separated by chosen delimiter.
SELECT
payments.number,
payments.amount,
(SELECT string_agg(invoices.number,',') from invoices INNER JOIN invoice_payments
ON invoices.id = invoice_payments.invoice_id
WHERE invoice_payments.payment_id = payments.id)
from payments

Try this
SELECT
payments.number,
payments.amount,
inv_p.inv_no
from payments p inner join (Select invoice_payments.payment_id, string_agg(invoices.number,',') as inv_no
From invoices inner join invoice_payments on (invoices.id = invoice_payments.invoice_id)
Group by invoice_payments.payment_id) inv_p on (p.id = inv_p.payment_id)

Related

SQL get SUM, COUNT, max, min and names of invoice

I have the following tables:
invoice
id
customerId
date
1
3
2020-10-10
2
NULL
2020-09-10
3
1
2020-10-15
product
id
name
price
1
car
10
2
pen
5
3
laptop
6
4
table
2
customer
id
name
1
a
2
b
3
c
4
d
invoceProduct
id
invoiceid
productid
1
1
1
3
1
2
4
1
4
5
2
2
6
2
3
I need to get the following for each invoice:
invoiceID, date, customerName, Total, Quantity(count of items), max product name and price, min product name and price in each invoice.
I wrote query and get most of values but I cannot get the name of products.
This is my sql query
WITH cte_Products(InvoiceId, date, CustomerName, ProductName, price) AS
(
select
i.id as InvoiceId,
i.date as date,
CASE
when c.name IS NULL THEN 'NoName'
Else c.name
End AS CustomerName,
p.name as ProductName,
p.price as price
from invoceProduct ip
join product p on p.id = ip.productID
join invoice i on i.id = ip.invoiceId
left join customer c on i.customerId = c.id
)
select
cte.InvoiceId,
cte.date,
cte.CustomerName,
SUM(cte.price) as Total,
count(*) AS ItemsQuantity,
MAX(cte.price) AS MostExpensiveItem,
MIN(cte.price) AS CheapestItem
from
cte_Products cte
group by cte.InvoiceId, cte.date, cte.CustomerName;
I got this result
InvoiceId
date
CustomerName
Total
ItemsQuantity
MostExpensiveItem
CheapestItem
1
2020-10-10
c
17
3
10
2
2
2020-09-10
NoName
11
2
6
5
I need to add the product name with product price under MostExpensiveItem and CheapestItem.

Select all column values as total and multiply it

This is my DB structure:
Invoice
ID
Company
InvoiceLine
LineID
Quantity
Price
These are my rows:
Invoice
ID Company
1 XYZ
2 ZYX
InvoiceLine
LineID InvoiceID quantity price
1 1 1 10
2 1 5 10
3 2 1 20
What I'm trying to generate is to select my total invoice price dynamically:
IDEAL RESULT
1 XYZ 60
2 ZYX 20
I use the following query for this:
select ID, cil.quantity * cil.unitPrice as invoiceTotal from Invoice ci
join InvoiceLine as cil on ci.invoiceID = cil.invoiceID
Problem is that this query returns 2 rows for the first invoice.
Why is this and what how could I select ALL values of my invoice lines?
You want group by:
select ci.id, sum(cil.quantity * cil.unitPrice) as invoiceTotal
from Invoice ci join
InvoiceLine cil
on ci.invoiceID = cil.invoiceID
group by ci.id;
However, you don't even need the join:
select cil.id, sum(cil.quantity * cil.unitPrice) as invoiceTotal
from InvoiceLine cil
group by cil.id;
select Invoice.id,Invoice.Company sum(InvoiceLine.quantity * InvoiceLine.unitPrice) as TotalSum
from Invoice join
InvoiceLine cil
on Invoice.invoiceID = InvoiceLine.invoiceID
group by Invoice.id,Invoice.Company
order by Invoice.Company ;

How to write Group by in Inner Join

Here I Have Two tables:
Orders
OrderId OrderName
1 Apple
2 Mango
Cust
Id Name OrderId Price
1 John 1 50
2 John 1 100
3 Mic 1 10
4 Mic 2 10
Sql Join Query:
SELECT Orders.CustName,Items.IteamName,Orders.Price
FROM Orders JOIN Items ON Items.Id = Orders.Id
Group By
SELECT Orders.CustName, SUM(Price) FROM Orders GROUP BY Orders.CustName
How can I Write Group by in Join?
You can do like this:
Select Orders.CustName, Items.IteamName, SUM(Orders.Price)
FROM
Orders JOIN Items ON Items.Id=Orders.Id
GROUP BY
Orders.CustName, Items.IteamName
The fields that you doesn't aggregate you put at the GROUP BYclause.

get balance from entities for all customers

I have table account
id - name
1 - Lab
2 - Sara
3 - Jone
table entities
id - credit - debit - value
1 1 3 10
1 1 2 20
1 3 1 5
1 2 1 3
I want the balance for all customers the output :
Name - balance
Sara 17
Jone 5
select account.name, (plus.balance - minus.balance) as balance
from accounts inner join
(select credit as id, sum(value) as balance from entities group by credit) as plus
inner join
(select debit as id, sum(value) as balance from entities group by debit) as minus
on plus.id = minus.id and accounts.id = plus.id
explanation- I'm making two copies from entities table- one to sum the credit (per id) and one to sum the debit, and then joins both of them with the accounts table to get the name. Not sure what you do with the id column in the entity table, seems redundant.
didn't work the errur invalid token ')' at line 6
select "Accounts".name, (plus.balance - minus.balance) as balance
from
"Accounts" inner join
(select public.entities.accounts_id_credit as id, sum(value) as balance from public.entities group by public.entities.accounts_id_credit) as plus
inner join
(select public.entities.accounts_id_debit as id, sum(value) as balance from public.entities group by public.entities.accounts_id_debit) as minus
on plus.id = minus.id and "Accounts".id = plus.id

Find number of times multiple products were purchased grouped by Customer SQL

I am trying to run a query to find how many times a customer ordered product x and product y. The customer must have purchased product 10 in order to be shown. And if there is a way to add another column to flag true or false if the amount of products match. There is also a second table holding customer information.
CustomerID ProductID
1 10
1 10
1 11
2 10
2 9
3 11
3 9
Result: (Remember if customer did not order Product_10 he/she will not show in results.
Customer Product_10 Product_11
John 2 1
Mike 1 0
Take a careful look at how the "Product_10" and "Product_11" columns are calculated; they're the crux of what you're trying to do. The HAVING at the end lops off any customers who don't have "Product_10" orders:
SELECT
Customers.Customer,
SUM(CASE WHEN Products.ProductID = 10 THEN 1 ELSE 0 END) AS Product_10,
SUM(CASE WHEN Products.ProductID = 11 THEN 1 ELSE 0 END) AS Product_11
FROM Customers
INNER JOIN Products ON Customers.ProductID = Products.ProductID
GROUP BY Customers.Customer
HAVING SUM(CASE WHEN Products.ProductID = 10 THEN 1 ELSE 0 END) > 0
The Customers table and columns are guesses because you didn't post the structure. Alter them as needed.
A solution using a derived table for each product. The first derived table t10 contains the # of product 10 purchased per customerId and this table is inner joined so that only customers with at least 1 purchase are shown, while the second table t11 is left joined so even customers w/o any purchases are shown.
select c.customer, t10.p10_count Product_10,
coalesce(t11.p11_count,0) Product_11,
(t10.p10_count = t11.p11_count) flag
from customer c
join (select CustomerID, count(*) p10_count
from customer_products
where ProductID = 10
group by CustomerID) t10
on t10.CustomerID = c.CustomerID
left join (select CustomerID, count(*) p11_count
from customer_products
where ProductID = 11
group by CustomerID) t11
on t11.CustomerID = c.CustomerID