Join another table then show max from other table - sql

I'm very new to sql so struggling a lot here.
I have 2 tables, Customer, and Transaction
Transaction
tID
cID
carID
eID
tDate
PickupDate
ReturnDate
Amount_Due
Customer
cID
fName
lName
Address
Postcode
email
DOB
I need to show all Customer information for the customer with the highest Amount_Due.
I think I have the first part correct but cannot get the Join working correctly.
SELECT c.cID
,c.fName
,c.lName
,c.Address
,c.Postcode
,c.email
,c.DOB
,[Transaction].Amount_Due
FROM Customer c, [Transaction]
LEFT JOIN
(
SELECT MAX(Amount_Due) AS Amount_Due
FROM [Transaction]
GROUP BY Amount_Due
) t
ON c.cID = t.cID

There are more than one method of solving this if I understand it correctly. e.g:
SELECT
c.cID
, c.fName
, c.lName
, c.Address
, c.Postcode
, c.email
, c.DOB
, t.Amount_Due
FROM Customer c
INNER JOIN (SELECT
cID
, MAX(Amount_Due) AS Amount_Due
FROM [Transaction]
GROUP BY cID
) t ON c.cID = t.cID
WHERE t.Amount_Due = (SELECT MAX(Amount_Due) FROM transactions)
or:
with cte as (
select cID, amount_due, max(Amount_Due) over(partition by 1) as max_amount_due from transactions
)
select
*
FROM Customer c
INNER JOIN cte on c.cID = cte.cID
and cte.amount_due = cte.max_amount_due

SELECT c.cID
,c.fName
,c.lName
,c.Address
,c.Postcode
,c.email
,c.DOB
,t.Amount_Due
FROM Customer c
LEFT JOIN
(
SELECT cID, MAX(Amount_Due) AS Amount_Due
FROM [Transaction]
GROUP BY cID
) t
ON c.cID = t.cID

Related

Select sum from

I am trying to get the sum of all the rows associated with each customer and join on them.
However I am finding that if no rows exist it leaves out the customer completely.
I would prefer if the sum was zero. How would I achieve this.
Here is the SQL statement:
SELECT
Id, DebitSum
FROM
Customers
JOIN
(SELECT
SUM(Amount) DebitSum, CustomerId
FROM
Purchases
WHERE
Completed IS NULL
GROUP BY
CustomerId) p ON p.CustomerId = Id;
Using SQL Server, if it matters.
Just use LEFT JOIN:
SELECT c.Id, COALESCE(p.DebitSum, 0)
FROM Customers c LEFT JOIN
(SELECT SUM(p.Amount) as DebitSum, p.CustomerId
FROM Purchases p
WHERE p.Completed IS NULL
GROUP BY CustomerId
) p
ON p.CustomerId = c.Id;
This would normally be written without the subquery:
SELECT c.Id, COALESCE(SUM(p.Amount), 0) as DebitSum
FROM Customers c LEFT JOIN
Purchases p
ON p.CustomerId = c.Id;
WHERE p.Completed IS NULL
GROUP BY c.Id
You could use LEFT JOIN:
SELECT Id, COALESCE(DebitSum,0) AS DebitSum
FROM Customers
LEFT JOIN (
SELECT SUM(Amount) DebitSum, CustomerId
FROM Purchases
WHERE Completed IS NULL
GROUP BY CustomerId
) p ON p.CustomerId = Id;
Try this:
SELECT Id, DebitSum
FROM Customers
LEFT JOIN (
SELECT SUM(Amount) DebitSum, CustomerId
FROM Purchases
WHERE Completed IS NULL
GROUP BY CustomerId
) p ON p.CustomerId = Id;
Your doing a JOIN which means it has to exist in both tables/data sets. Changing it to LEFT JOIN only requires it to be in the First table and not the one after the LEFT JOIN
You can also use subquery only:
select id, (select coalesce(sum(p.Amount), 0)
from Purchases p
where p.CustomerId = c.id and p.Completed IS NULL
) as DebitSum
from Customers c
group by id;
SELECT SUM(Amount) DebitSum, CustomerId
there is no AS after the information? select sum(amount) as debitsum, customerid
try this
SELECT c.Id, COALESCE(p.DebitSum, 0) as DebitSum
FROM Customers c LEFT JOIN Purchases p
on c.Id = p.CustomerId
where p.completed is null

SQL joining two tables and counting

I want to retrieve all the customers who own more than 1 car.
I have this code:
SELECT c.fname,
c.lname,
c.cid,
Count(v.cid) AS nmbrofvehicle
FROM customer c
LEFT JOIN vehicle v
ON c.cid = v.cid
GROUP BY c.fname;
But it returns this error:
ORA-00979: not a GROUP BY expression
select c.fname, c.lname, c.cid, count(v.cid) as nmbrofvehicle
from customer c left join vehicle v on c.cid = v.cid
group by c.fname, c.lname, c.cid
having count(*) > 1;
The problem you have there is that you are attempting to group in ungrouped data (e.g. surname).
Some databases (such as MySQL) are very forgiving and try to do this - Oracle, however is not.
Try this:
SELECT a.cid
, a.fname
, a.sname
, NVL(b.nmbrofvehicle, 0) AS nmbrofvehicle
FROM customers a
LEFT JOIN ( SELECT z.cid
, COUNT(z.cid) AS nmbrofvehicle
FROM vehicle z
GROUP BY z.cid
) b
ON ( a.cid = b.cid );
This will take data from customers, and left join any matching data from your vehicles table on cid, or return 0 thanks to this NVL function.
Remove c.cid from the select and add c.lname to the group by:
SELECT c.fname, c.lname,
Count(v.cid) AS nmbrofvehicle
FROM customer c JOIN
vehicle v
ON c.cid = v.cid
GROUP BY c.fname, c.lname
HAVING COUNT(*) > 1;
A LEFT JOIN is unnecessary because you are requiring at least one match.

Finding Sum of all previous sales to all customer and sum of today's sale in sql query

I have following database tables in SQL Server 2008.
customer
------------
id, Name, Address
payment
-------
payment_id, amount, customer_id
Sales
S_id, Date, ItemName, amount, commission, customer_id
I am novice to SQL queries. i want want to to display result
name, previous customer balance i.e (sum(Sale.amount)+Sum(commission))-sum(Payment) for all customers
Something like the below should work:
select c.[Name], saleSum.SaleTotal - paymentSum.PaymentTotal
from customer c join
(
select c.[id], sum(isnull(s.amount,0) + isnull(s.commission, 0)) SaleTotal
from customer c left join sales s on c.id = s.customer_id
group by c.[id]
) as saleSum on c.id = saleSum.id
join
(
select c.id, sum(isnull(p.amount,0)) PaymentTotal
from customer c left join payment p on c.id = p.customer_id
group by c.id
) paymentSum on c.id = paymentSum.id
The equery is
Select Tab1.ID,
Min(Tab1.name),
sum(Tab3.amount) + Sum(Tab3.commission) - sum(Tab2.amount)
From Table1 Tab1
inner join Table2 tab2 on Tab1.id = Tab2.customer_id
inner join Table3 tab3 on Tab1.id = Tab3.customer_id
Group by Tab1.ID
SELECT
customer.name,
(SUM(sales.amount)+SUM(sales.comission)-SUM(payment.amount)) as "customer balance"
FROM
sales
INNER JOIN customer on sales.customer_id = customer.id
INNER JOIN payment on sales.customer_id = payment.customer_id
GROUP BY customer.name

Count row and get latest row by date from multiple tables

I have 2 tables, Customer and CustomerActivity as showed in the picture below:
I want to output a table that:
has all columns from Customer table where CustomerType = 'Existing Customer', plus 2 more columns:
totalActivity (count activityID) - shows total activity number of each customer.
latestActivity (max checkinTime) - shows the most recent activity datetime
So far I have these 2 queries but I don't know how to combine/join and filter them to get what I need. Anyone can help with 1 query (and some explanation would be perfect)
SELECT customerId, firstName, birthDate, customerType
FROM Customer
WHERE Customer.customerType = 'Existing Customer'
SELECT t1.activityId, t1.checkinTime, t1.customerId
FROM CustomerActivity t1
inner join (
SELECT customerId, max(checkinTime) as Lastest
FROM CustomerActivity
group by customerId
) t2 on t1.customerId = t2.customerId and t1.checkinTime = t2.Lastest
You're actually close. Here is what your query should look like:
SELECT
c.customerId,
c.firstName,
c.lastName,
c.birthDate,
c.customerType,
ca.totalActivity,
ca.latestActivity
FROM Customer c
INNER JOIN(
SELECT
customerId,
latestActivity = MAX(checkinTime),
totalActivity = COUNT(*)
FROM CustomerActivity
GROUP BY customerId
) ca
ON ca.customerId = c.customerId
WHERE
c.customerType = 'Existing Customer'
The subquery (inside the INNER JOIN) retrieves the total number of activities by using COUNT(*) and latest activity using MAX(checkinTime) of each customer. After that, you would want to join it to the Customer table on customerId. You then add a WHERE clause to filter for 'Existing Customer' only.
I haven't tested it against an actual schema, but something like this should work (this approach will show customers even if they have no activity, simply change the left join to an inner join if you only want customers with activity):
SELECT c.CustomerID
, c.FirstName
, c.BirthDate
, c.CustomerType
, COUNT(ca.ActivityID) AS TotalActivity
, MAX(ca.CheckinTime) AS MostRecentActivity
FROM Customer c
LEFT JOIN CustomerActivity ca ON c.CustomerID = ca.CustomerID
WHERE c.CustomerType = 'Existing Customer'
GROUP BY c.CustomerID
, c.FirstName
, c.BirthDate
, c.CustomerType
You can get what you want without group by, by using row_number() and window fu instead:
SELECT c.*, ca.numActivities, ca.activityId as LastActivity
FROM Customer c JOIN
(select ca.*,
count(*) over (partition by ca.CustomerId) as numActivities
row_number() over (partition by ca.CustomerId order by checkinTime desc) as seqnum
from CustomerActivity ca
) ca
on c.customerId = ca.customerId and ca.seqnum = 1
WHERE c.customerType = 'Existing Customer';
This version will let you get whatever columns you like from the most recent activity row.
EDIT:
In your original question, I thought you wanted the latest activity. If you just want the latest datetime, then aggregation works:
SELECT c.*, ca.numActivities, ca.lastActivityDateTime
FROM Customer c JOIN
(select ca.*,
count(*) as numActivities
max(checkinTime) as lastActivityDateTime
from CustomerActivity ca
) ca
on c.customerId = ca.customerId
WHERE c.customerType = 'Existing Customer';
Select c.customerId, c.firstName, c.lastName, c.birthDate, c.customerType, gca.latestCheckIn, gca.count
from customer as c,
(select ca.customerId, max(ca.checkInTime) as latestCheckIn, count(*) as checkinCount
from customerActivity as ca
group by ca.customerId) as gca
where gca.customerId = c.customerId AND c.customerType = 'Existing Customer'
If you clarify more about customer with no activity, one can change the query to using left join

Need to order output based on date - Sub query

I have a simple subquery where I have two tables. First table has the customer id, first name and last name. Second table has the customer id and order date. I want to generate a query that shows the first name, last name and order date.
I have tried the below code and i dont know how the order the output based on date
Select
Customerid,
FirstName,
LastName
From
Customer
Where
CustomerID IN (select
CustomerID
from
orders
where
orderdate is not null);
The output I show is only the customer id, first name and last name. How do I include the order date in my output.
what did u select = what will display for you, include date in your select statement
Select A.Customerid, A.firstname, A.lastname, B.orderdate
From tableA A
Inner join Tableb B on A.customerid = B.customerid
For your modified question(s), try query below
Select A.firstname, A.lastname, B.orderdate
From tableA A
Inner join Tableb B on A.customerid = B.customerid
Order By B.orederdate
;with CustomerProductOrderOrdinal( OrderId, Ordinal )
as
(
select
o.OrderId
, row_number() over ( partition by o.CustomerId, o.ProductId order by o.OrderDate ) Ordinal
from
Orders o
where
o.OrderDate is not null
-- filter for product here if so desired
-- and o.ProductId = <whatever>
)
,FirstCustomerProductOrder( OrderId )
as
(
select
OrderId
from
CustomerProductOrderOrdinal
where
Ordinal = 1
)
select
c.CustomerId
, c.FirstName
, c.LastName
--, p.ProductId
, o.OrderDate
From
Customer c
inner join Orders o
on c.CustomerId = o.CustomerId
inner join FirstCustomerProductOrder fcpo
on o.OrderId = fcpo.OrderId
-- join with product if you want product info
--inner join Product p
-- on o.ProductId = p.ProductId