how to select duplicated column value in sql - sql

Write a query that determines the customer that has spent the most on music for each country. Write a query that returns the country along with the top customer and how much they spent. For countries where the top amount spent is shared, provide all customers who spent this amount.
You should only need to use the Customer and Invoice tables.
i want to select the customer with the maximum money spent for each country and there is two customers have the same money spent and the same country so when using group by country i got only 1 customer what should i do ?
select c.CustomerId,c.FirstName,c.LastName, c.Country , max(c.Invoices) as TotalSpent
from
(select * , sum(i.Total) as 'Invoices'
from Customer d
join Invoice i on i.CustomerId = d.CustomerId
group by i.CustomerId
) c
group by c.Country
the table i got is the same expected table except 1 customer

Consider joining unit level with two aggregate queries: 1) first to calculate total amount by CustomerId and Country and 2) second to calculate max total amount by Country.
Below assumes your database supports Common Table Expression (CTE) using the WITH clause (nearly supported by all major commercial or open-source RDBMS's). CTE here avoids the need to repeat sum_agg as a subquery.
with sum_agg AS (
select i.CustomerId, sub_c.Country, sum(i.Total) as Sum_Amount
from Customer sub_c
join Invoice i on i.CustomerId = sub_c.CustomerId
group by i.CustomerId, sub_c.Country
)
select c.CustomerId, c.FirstName, c.LastName, c.Country, max_agg.Max_Sum
from Customer c
join sum_agg
on c.CustomerId = sum_agg.Customer_Id and c.Country = sum_agg.Country
join
(select Country, max(Sum_Amount) as Max_Sum
from sum_agg
group by Country
) max_agg
on max_agg.Country = sum_agg.Country and max_agg.Max_Sum = sum_agg.Sum_Amount

Your inner query is almost correct. It should be
select d.*, sum(i.Total) as Invoices
from Customer d
join Invoice i on i.CustomerId = d.CustomerId
group by d.CustomerId
It is allowed to use d.* here, as we can assume d.CustomerId to be the table's primary key, so all columns in the table are functionally dependent on it. If we grouped by d.country instead for instance, that would not be the case and d.* would be forbidden in the select clause (as well as d.firstname etc.). We can only select columns we grouped by (directly or indirectly) and aggregates such as MIN, MAX, SUM etc.
This query gives you the totals per customer along with the customers' countries.
But then you are taking this result and group by country. If you do this, you can only access country and its aggregates. Selecting c.CustomerId for instance is invalid, as there is no the customer ID per country. If your DBMS allows this, it it flawed in this regard and you get a kind of random result.
If your DBMS features window functions, you can get the maximum amounts per country on-the-fly:
select customerid, firstname, lastname, country, invoices
from
(
select
c.*,
sum(i.total) as invoices,
max(sum(i.total)) over (partition by c.country) as max_sum
from customer c
join invoice i on i.customerid = c.customerid
group by c.customerid
) per_customer
where invoices = max_sum
order by country, customerid;
Otherwise you'd have to use your inner query twice, once to get the country totals, once to get the customers matching these totals:
select
c.customerid, c.firstname, c.lastname, c.country,
sum(i.total) as invoices
from customer c
join invoice i on i.customerid = c.customerid
group by c.customerid
having (c.country, invoices) in
(
select country, max(invoices)
from
(
select
--c.customerid, <- optional, it may make this query more readable
c.country,
sum(i.total) as invoices
from customer c
join invoice i on i.customerid = c.customerid
group by c.customerid
) per_customer
);

Related

show each customers' names, how much each person has spent in total, and how many orders they have made

enter image description here
I am trying to extract infomation from atable to solve the aforementioned question:
show each customers' names, how much each person has spent in total, and how many orders they have made
Here is my attempt
select firstName, lastName, ISNULL(totalOrders, 0), ISNULL(totalSpent) from Customers as C
join (
SELECT customerID, count(orderNumber) as totalOrders from CustomerOrders
ORDER BY COUNT(orderNumber) ASC
) AS CO ON CO.customerID = C.customerID
JOIN (
select sum(orderNumber) as totalSpent from ItemsInOrder
order by C.lastName
) as IIO ON IIO.totalSpent = CO.totalOrders
Unfortunately, this did not run. Also i'm trying to get my result to be ordered by order count in ascending and order by the customer's last name but I'm having a hard time, as I don't know where to place it.
I feel like this is an easy question but I kept overthinking it and ending up being confused
As #HoneyBadger has pointed out in the comments, you are not using any group by clause, so that is going to error out. But, you have to look at how you join your tables as well. It does not make sense to equate the sum of item costs to the total number of orders. You should be joining that on order number.
Here is a quick and dirty answer using outer apply. Because count ignores nulls in the count on a single column, we don't need an isnull or a coalesce there, but we would on the sum column.
select
c.firstname,
c.lastname,
sum(coalesce(c.totalspend, 0)) as TotalSpend,
count(a.orderNumber) as Numorders
from customers c
outer apply
(
select co.customerid, orderNumber, sum(totalItemCost) as TotalSpend
from customerorders co
left join itemsinorders ii on ii.ordernumber = co.ordernumber
group by co.customerid, ordernumber
) a on a.customerid = c.customerid
Group by c.firstname, c.lastname
If outer apply doesn't work, you should be able to do it all with joins with a count(distinct). So,
select
c.firstname,
c.lastname,
count(distinct o.ordernumber) as NumOrders,
sum(coalesce(i.totalspend, 0) as totalSpend
from customers c
left join customerorders o on o.customerid = c.customerid
left join itemsinorders i on i.orderid = o.orderid
group by c.firstname, c.lastname
Without being able to check on the null values of distinct, this should work and is easier to read.

Find the highest amount although there are more than one achieving the same amount

I want to find the best customer for each country despite there is one country has two customers the same amount, I want them both to appear.
select customerid,firstname,lastname,country, max(total_amt)
from (select invoice.customerid, customer.firstname,lastname,
sum(invoice.total)total_amt,customer.country
from invoice
join customer
on customer.customerid= invoice.customerid
group by invoice.customerid,customer.country)t2
group by country;
Use window functions:
select c.*
from (select c.country, c.customerid, c.firstname c.lastname, sum(i.total) as total,
dense_rank() over (partition by c.country order by sum(i.total) desc) as seqnum
from customer c join
invoice i
on c.customerid = i.customerid
) c
where seqnum = 1;
Note that I also introduced window functions so the query is easier to write and to read.

I need a solution to this SQL Query I'm trying to solve

"Write a query that determines the customer that has spent the most on
music for each country. Write a query that returns the country along
with the top customer and how much they spent. For countries where the
top amount spent is shared, provide all customers who spent this
amount.
You should only need to use the Customer and Invoice tables.
Check Your Solution
Though there are only 24 countries, your query should return 25 rows
because the United Kingdom has 2 customers that share the maximum."
You can find the data set here
.
Here is the code I tried with the results
And here is the expected outcome
Generally, you should always GROUP BY anything in your SELECT that is not an aggregation function (e.g. SUM). Try this:
SELECT c.CustomerId, c.FirstName, c.LastName, c.Country,
SUM(i.Total) AS TotalSpent
FROM Customer c
JOIN Invoice i
ON i.CustomerId = c.CustomerId
GROUP BY c.CustomerId, c.FirstName, c.LastName, c.Country
ORDER BY c.Country
WITH tab1 AS ( SELECT c.CustomerId, c.FirstName, c.LastName, c.Country, SUM(i.Total) TotalSpent FROM Customer c JOIN Invoice i ON c.CustomerId = i.CustomerId GROUP BY c.CustomerId ) SELECT tab1.* FROM tab1 left JOIN ( SELECT CustomerId, FirstName, LastName, Country, MAX(TotalSpent) AS TotalSpent FROM tab1 GROUP BY Country ) tab2 ON tab1.Country = tab2.Country WHERE tab1.TotalSpent = tab2.TotalSpent ORDER BY Country;

SQL Subtract two columns on different tables

I have two tables, Customer, and Invoices,I have to list all the customers with their remaining credit. I'm trying to subtract the sum of the Invoice Amount column from the CreditLimit column to give me the remaining credit?
This is my query so far
DECLARE #CreditRemaining INT
SELECT
#CreditRemaining = (c.CreditLimit - SUM(i.Amount))
FROM
Customer c
INNER JOIN
Invoices i on
c.ID = i.customerId
Use a derived table for the invoice amount SUM(), then JOIN back to Customer:
DECLARE #CreditRemaining INT
SELECT #CreditRemaining = (c.CreditLimit - TotalSpent)
FROM Customer c
INNER JOIN (SELECT SUM(Amount) TotalSpent, CustomerID
FROM Invoices
GROUP BY CustomerID) i ON i.CustomerID = c.ID
As others mentioned, this is assuming you are limiting your selection to one customer.
For all customers, just use a select:
SELECT C.Name, (c.CreditLimit - TotalSpent) CreditRemaining
FROM Customer c
INNER JOIN (SELECT SUM(Amount) TotalSpent, CustomerID
FROM Invoices
GROUP BY CustomerID) i ON i.CustomerID = c.ID
GROUP BY C.Name

SQL Server Aggregation using Max() and obtaining details from max() line.

I just took a final exam and one of the questions asked me to double join three tables, and report the max sale payout for each salesperson.
The tables have the following variables:
Salesperson(id, name)
Order(orderid, order_date, Cust_id, Saleperson_id, amount)
Customer(id, name)
After joining:
select salesperson.Name, Orders.Number, customer.Name, Orders.Amount
from Orders
join salesperson
on orders.Salesperson_id = salesperson.ID
join Customer
on customer.ID = orders.cust_id
What the instructed wanted was for me to find each salesperson's maximum sell (as found by order.amount). He also wanted the salesperson (salesperson.name), the order number of the max sale (orders.number), the customer the sale was with (customer.name), and the max sale amount. What is the most efficient way to do this problem? I have tried to use "group by salesperson.name", but I cannot because the orders.number and customer.name are never held in the aggregation.
I finished the problem this way
select
salesperson.name as Sales_Person,
orders.number as Order_Number,
customer.Name as Customer_Name,
orders.Amount as Sale_Amount
from salesperson
left join Orders
on salesperson.ID = orders.Salesperson_id
left join Customer
on orders.cust_id = customer.ID
where orders.Amount in (select max(orders.Amount)
from salesperson
join Orders
on salesperson.ID = orders.Salesperson_id
join Customer
on orders.cust_id = customer.ID
group by salesperson.name)
I know this is a bad way to do it. For instance, what if two different salesperson's max sale was equivalent? Max and min are not like count and sum because it is picking out one line from a aggregation, but the rules still apply. Also, you might notices that there is no real unique identifier in the joined table other than order.number which is not useful. Therefore, I would have to use some composite of salesperson.name and order.number.
Also, what do I do if I have to pick the top three sales for each salesperson? Should such an output be totally different code-wise than what would be required from just the first sale?
I keep bumping me head against this problem, and I would love to have a more professional approach to this problem.
SELECT
M.max_amount,
S.Name,
O.Number,
C.Name
FROM orders O
JOIN salesperson S
ON S.Salesperson_id = O.Salesperson_id
JOIN customer C
ON C.Customer_id = O.Customer_id
JOIN (
SELECT Salesperson_id, MAX(amount) max_amount
FROM Order
GROUP BY Salesperson_id
) M
ON M.Salesperson_id = O.Salesperson_id AND M.max_amount = O.amount
For the top 3:
SELECT
M.Amount,
S.Name,
O.Number,
C.Name
FROM orders O
JOIN salesperson S
ON S.Salesperson_id = O.Salesperson_id
JOIN customer C
ON C.Customer_id = O.Customer_id
CROSS APPLY (
SELECT TOP 3 Amount
FROM Order
WHERE Salesperson_id = O.Salesperson_id
ORDER BY Amount DESC
) M