SQL help on self Join query - sql

Two tables customers table and payment table
Payment table
paymentid int
paymentdate date
custid int
Customers table
Custid int
name varachar
paymentcustid int
foreign key constraints:
payment.custid refers to customer.custid
payment.paymentcustid also refers to customer.custid
Write a query to fetch the name of the paymentid, paymentdate, name of the customer, name of the payment customer.
Table structure would be like
Payment table
paymentid paymentdate custid
100 07/11/18 1
101 08/11/18 3
102 08/11/18 4
Customer table
Custid name paymentcustid
1 a 4
2 b 3
3 c 5
4 d 5
5 e 1

Looks like you just need :
SELECT
p.paymentid,
p.paymentdate,
c1.name payment_customer,
c2.name customer
FROM
payment p
INNER JOIN customers c1 ON p.cust_id = c1.paymentcustid
INNER JOIN customers c2 ON p.cust_id = c2.custid;

Related

Select userid and sum of total amount of books a user has made on all loans

I would like to get an output which displays the personID and the total sum of books the user has made throughout every loan.
Member:
PersonID
1
2
Loan:
PersonID
LoanID
1
1
1
2
2
3
OrderLine:
LoanID
BookID
1
1
1
2
1
3
2
4
2
5
3
6
3
7
Expected output:
PersonID
Total sum of books
1
5
2
2
Edit:
I have tried a couple of things, as I've been at this for about three hours now. Most of my attempts have been scrapped but this is one attempt I came up with which wasn't able to do my problem.
SELECT SUM(TOTAL) AS Test FROM (
SELECT COUNT(*) AS TOTAL FROM Person AS P
WHERE P.PersonID IN (
SELECT PersonID FROM Loan AS L
WHERE L.LoanID IN (
SELECT LoanID FROM Orderline AS OL
WHERE L.LoanID = OL.LoanID
)
)
GROUP BY P.PersonID
) AS TOTAL;
If you want to count duplicated books :
SELECT
PersonID,
count(*) as 'Total sum of books'
FROM
Loan l
INNER JOIN
OrderLine o on l.LoanID = o.LoanID
GROUP BY PersonID
For including users with 0 loan:
SELECT
m.PersonID,
CASE
WHEN c.PersonID is not NULL THEN c.cpt
ELSE 0
END as 'Total sum of books'
FROM
Member m
FULL JOIN
(
SELECT
PersonID,
count(*) as cpt
FROM
Loan l
INNER JOIN
OrderLine o on l.LoanID = o.LoanID
GROUP BY PersonID
) as c ON m.PersonId = c.PersonId
It's not the most elegant way to do it, but I think it's one of the easiest to understand.
With the full join will give you one counter (cpt) per user. If there is no match then cpt will be NULL.

how left outer join works for table have null values

I have four tables: person and booking, booking_detail,room_pricing where person_id used as foreign key in the booking table and person_id is used as foreign key in the booking_detail table. where room_id is used as foreign_key in booking_detail
Supposing I want to show all the booking_id from booking table and their corresponding total income from rooms on each booking including those who doesn't exist in `` table such as id 1 ,i am using oracle database
person
person_id name
1 xyz
2 abc
3 jkl
booking
booking_id person_id
1 1
2 3
3 1
booking_details
person_id roomid
2 201
3 303
3 303
room_pricing
room_id price
201 $ 100
302 $ 100
303 $ 200
final table should be like this
booking_id total
1 0
2 400$
3 0
Try the following using left join
select
b.booking_id,
coalesce(sum(total), 0) as total
from booking b
left join booking_details bd
on b.person_id = bd.person_id
left join room_pricing rp
on bd.room_id = rp.room_id
group by
b.booking_id
You want a left join with aggregation:
select p.person_id, coalesce(sum(o.total), 0)
from person p left join
order o
on o.person_id = p.person_id
group by p.person_id;

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 ;

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

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)

check if the column value exists in subquery

i have 3 tables Product Category and ProductCategory.
Product table:
ProductID ProductName
1 P1
2 P2
3 P3
Category table:
CategoryID CategoryName
1 C1
2 C2
3 C3
ProductCategory:
ProductID CategoryID
1 1
1 2
1 3
2 3
3 1
3 2
I need a query which returns products which fall under more than 1 categories. Based on the table data above the result would be:
ProductID ProductName
1 P1
3 P3
So i wrote a query to fetch all the ProductID's which have more than one CategoryID's as below:
select ProductID,count(CategoryID)
from ProductCategory
group by Productid
having count(CategoryID)>1)
But when i try to display product details using the below query i get an error:
select *
from Product
where ProductID in (
select ProductID,count(CategoryID)
from ProductCategory
group by Productid
having count(CategoryID)>1))
Is my query wrong? How do i get the required product details which fall in more than one categories?
Remove the COUNT() in the subquery. The result of the subquery when used on IN clause must have only one returned column.
SELECT *
FROM Product
WHERE ProductID IN
(
SELECT ProductID
FROM ProductCategory
GROUP BY Productid
HAVING count(CategoryID) > 1
)
SQLFiddle Demo
or by using JOIN
SELECT a.*
FROM Product a
INNER JOIN
(
SELECT ProductID
FROM ProductCategory
GROUP BY Productid
HAVING count(CategoryID) > 1
) b ON a.ProductID = b.ProductID
SQLFiddle Demo
You can try use CROSS APPLY Operator in SQL Server
SELECT DISTINCT C.ProductID,C.ProductName,A.CategoryID,A.Total
FROM Product C
CROSS APPLY (
Select CA.CategoryID,Total=COUNT(*)
From ProductCategory CA
Where C.ProductID=CA.ProductID
Group By CA.CategoryID Having COUNT(*)>1
) AS A
ORDER BY A.Total DESC
Take a look: http://explainextended.com/2009/07/16/inner-join-vs-cross-apply/