I need a solution to this SQL Query I'm trying to solve - 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.
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;

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.

How return two equal max values for the same country when the query is grouped by the country?

For example I have to write a query that shows the customer who had spent the most in each country but if a country has two customers with same max value i have to show them both in the output.
I have wrote the query that return the maximum value for each customer in each country but the last country in my example which is 'United Kingdom' has two customers with same maximum values and i couldn't show them both.
SELECT c1.CustomerId, c1.FirstName,c1.LastName,c1.Country,
MAX(c1.TotalSpent) as TotalSpent
FROM
(SELECT c.CustomerId,c.FirstName, c.LastName,i.BillingCountry
Country, SUM(i.Total) totalspent
FROM Customer c
JOIN Invoice i
ON c.CustomerId = i.CustomerId
GROUP BY 1
ORDER BY totalspent
) c1
GROUP BY 4
ORDER BY Country
Use window functions!:
SELECT c.*
FROM (SELECT c.CustomerId, c.FirstName, c.LastName, i.BillingCountry as Country,
SUM(i.Total) as totalspent,
DENSE_RANK() OVER (PARTITION BY i.BillingCountry ORDER BY SUM(i.Total) DESC) as seqnum
FROM Customer c JOIN
Invoice i
ON c.CustomerId = i.CustomerId
GROUP BY c.CustomerId, c.FirstName, c.LastName, i.BillingCountry
) c
WHERE seqnum = 1
ORDER BY Country;
This also fixes your GROUP BY clauses so they are consistent with the columns being selected.

how to select duplicated column value in 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
);

How to get two ties of maximum values in my query?

I have a database of a music store and I need to extract the max value of purchases from a customer specific to each country. While using MAX function, I noticed that I have two ties of maximum values in 'United Kingdom'. So, I need my query to return both the customers for this country.
With t1 As (
Select i.CustomerId, c.FirstName, c.LastName,
i.BillingCountry Country, Sum(i.Total) Totals
From Invoice i
Join Customer c
On c.CustomerId = i.CustomerId
GROUP BY 1, 4)
Select CustomerId, FirstName, LastName, Country, Max(Totals) TotalSpent
From t1
Group By 4;
This is the output
This is what the output should be
I tried using TOP but apparently by workspace does not accept this function. So, Please suggest a solution that does not use this function.
Thanks in advance.
I would consider something like
With t1 As (
Select i.CustomerId, c.FirstName, c.LastName,
i.BillingCountry Country, Sum(i.Total) Totals
From Invoice i
Join Customer c
On c.CustomerId = i.CustomerId
GROUP BY 1, 4)
Select CustomerId, FirstName, LastName, Country, Totals TotalSpent
From t1
WHERE t1.Total = (SELECT MAX(Totals) FROM t1 t2 WHERE t1.Country = t2.Country)
Group By 4;
(I've changed MAX(Totals) to Totals in your main query's SELECT statement and added the WHERE clause)
or
With t1 As (
Select i.CustomerId, c.FirstName, c.LastName,
i.BillingCountry Country, Sum(i.Total) Totals
From Invoice i
Join Customer c
On c.CustomerId = i.CustomerId
GROUP BY 1, 4),
t2 as (
SELECT Country, MAX(Totals) as Totals
FROM t1
GROUP BY Country
)
Select t1.CustomerId, t1.FirstName, t1.LastName, t1.Country, t1.Totals TotalSpent
From t1 INNER JOIN t2
on t1.Country = t2.Country and t1.Totals = t2.Totals
Group By 4;
(I've added the t2 CTE, joined it into your main query, and adjusted the main SELECT accordingly)
In both cases, I'm trying to select all the customer information where that customer's total is equal to the maximum total for their country. In principle, this should work no matter how many ties there are.
Use window functions!
select CustomerId, FirstName, LastName,
Country, Totals
from (select i.CustomerId, c.FirstName, c.LastName,
i.BillingCountry as Country, sum(i.Total) as Totals,
rank() over (partition by i.BillingCountry over sum(i.Total) desc) as seqnum
from Invoice i join
Customer c
on c.CustomerId = i.CustomerId
group by i.CustomerId, c.FirstName, c.LastName,
i.BillingCountry
) ic
where seqnum = 1;

Access SQL- Count distinct months from Table 1 by City in Table 2

I have a table (Orders) featuring CustomerID, Product, Sales, and Date (yyyy-mm-dd).
CustomerID is linked to the Customer table at CustomerName. The Customer table has fields Customername, City, State, Country.
I would like to count the number of unique months for the calendar year which an ordered occurred by each City.
Unfortunately, so for I've only been able to count distinct months across all Customers and Dates. How can I tie it to each city in the Customer table?
SELECT Count(*) AS CountOfMonths
FROM (
SELECT DISTINCT Month(Date), Year(Date)
FROM Orders );
Thanks!
Something like this:
select country, city, state,
count(*) as NumDistinctMonths
from (select c.country, c.state, c.city,
year(o.date) as yyyy, month(o.date) as mm, count(*) as cnt
from orders as o inner join
customers as c
on o.CustomerID = c.CustomerId
group by c.country, c.state, c.city, year(o.date), month(o.date)
) as ccsym
group by country, city, state;
Simply join the tables and aggregate by year and city and count distinct months:
select c.country, c.state, c.city, year(o.date), count(distinct month(o.date))
from orders o
join customers c on c.customername = o.customerid
group by c.country, c.state, c.city, year(o.date)
order by c.country, c.state, c.city, year(o.date);
Add a WHERE clause, if you want to see one year only.
UPDATE: MS Access doesn't support COUNT(DISTINCT expresssion). So you need a distinct subquery there:
select c.country, c.state, c.city, order_year, count(*)
from
(
select distinct c.country, c.state, c.city, year(o.date) as order_year, month(o.date)
from orders o
join customers c on c.customername = o.customerid
) as dist_months
group by country, state, city, order_year
order by country, state, city, order_year;