PostgreSQL: get the min of a column with it's associated city - sql

I have been at this for the past two hours and have tried many different ways in regards to subquery and joins. Here's the exact question "Get the name and city of customers who live in the city where the least number of products are made"
Here is a snapshot of the database tables
I know how to get the min
select min(quantity)
from products
but this returns just the min without the city attached to it so I can't search for the city in the customers table.
I have also tried group by and found it gave me 3 min's (one for each group of cities) which i believe may help me
select city,min(quantity)
from products
group by city
Putting everything together I got something that looks like
SELECT
c.name,c.city
FROM
customers c
INNER JOIN
(
SELECT
city,
MIN(quantity) AS min_quantity
FROM
products
GROUP BY
city
) AS SQ ON
SQ.city = c.city
But this returns multiple customers, which isn't correct. I assume by looking at the database the city when the lowest number of products seems to be Newark and there are no customers who reside in Newark so I assume again this query would result in 0 hits.Thank you for your time.
Example
Here is an example "Get the pids of products ordered through any agent who makes at least one order for a customer in Kyoto"
and the answer I provided is
select pid
from orders
inner join agents
on orders.aid = agents.aid
inner join customers
on customers.cid = orders.cid
where customers.city = 'Kyoto'

In Postgresql you have sophisticated tools, viz., windowing and CTEs.
WITH
find_least_sumq AS
(SELECT city, RANK() OVER ( PARTITION BY city ORDER BY SUM(quantity) ) AS r
FROM products)
SELECT name, city
FROM customers NATURAL JOIN find_least_sumq /* ON city */
WHERE r=1; /* rank 1 is smallest summed quantity including ties */
In Drew's answer, you are zeronig in on the cities where the smallest number of any particular item is made. I interpret the question as wanting the sum of items made in that city.

I guess it be something around this idea:
select customers.name, city.city, city.min
from customers
join (
select city, sum (quantity) as min
from products
group by city
--filter by the cities where the total_quantity = min_quantity
having sum (quantity) = (
--get the minimum quantity
select min(quantity) from products
)
) city on customers.city = city.city

This can be made so much simpler. Just sort the output by the field you want to get the minimum of.
SELECT city, quantity FROM customers ORDER BY quantity LIMIT 1;

I have just figured out my own answer. I guess taking a break and coming back to it was all I needed. For future readers this answer will use a subquery to help you get the min of a column and compare a different column (of that same row) to a different tables column.
This example is getting the city where the least number of products are made (quantity column) in the products table and comparing that city to the cities to the city column in the customers table, then printing the names and the city of those customers. (to help clarify, use the link in the original question to look at the structure of the database I am talking about) First step is to sum all the products to their respective cities, and then take the min of that, and then find the customers in that city.Here was my solution
with citySum as(
select city,sum(quantity) as sum
from products
group by city)
select name,city
from customers
where city
in
(select city
from citySum
where sum =(
select min(sum)
from citySum))
Here is another solution I have found today that works as well using only Sub queries
select c.name,c.city
from customers c
where c.city
in
(select city
from
(select p.city,sum(p.quantity) as lowestSum
from products p
group by p.city) summedCityQuantities
order by lowestsum asc
limit 1)

Related

SQL Count Customers where Products are the same

I have a problem. I have a SQL-database named customers with the 3 columns Country, CustomerID and Product. With that database, I want to count all the customers which bought the products bike, flask and helmet but grouped by the country as you can see in the following picture.
Is there a chance you can help me out with that? I guess I have to make a join on the same table and make a nested query with another select, but I don't really know how to do that.
I would be very thankful for your help!
You have to do aggregation in two steps. First find the customers with the 3 different products, then count these customers.
SELECT country, count(*)
FROM
(
SELECT country, CustomerID
FROM customers
WHERE product IN ('Bike','Flask','Helmet')
GROUP BY country, CustomerID
HAVING COUNT(distinct product) = 3
) dt
GROUP BY country
You might use HAVING clause along with GROUP BY while distinctly count for each customer after counted for those exact three products such as
SELECT Country, COUNT(DISTINCT CustomerID) AS Count
FROM customers
WHERE Product IN ('Bike','Flask','Helmet')
AND CustomerID IN ( SELECT CustomerID
FROM customers
GROUP BY CustomerID
HAVING COUNT(DISTINCT Product)=3 )
GROUP BY Country
Demo
Try this sql:
select Country,count(distinct CustomerID)
from customers
where Product in ('Bike','Flask','Helmet')
group by Country
select Country,count(distinct CustomerID)
from customers
where Product in ('Bike','Flask','Helmet')
group by Country
SELECT COUNT(CustomerID), Country
FROM Customers
GROUP BY Country
HAVING Product in ('Bike','Flask','Helmet');

SQL statement selects top 10 orders from each country in a list of countries

I'm trying to build a query where I can get the top 10 orders from each country in a list of countries. So that if my list of countries is 3 long, I should get no more than 30 result total and no more than 10 from one country.
Assume the table I am querying has the necessary fields.
My list of countries can change with the query. So at one point I may just be interested in ('China', 'Japan', 'USA') but at another ('China', 'Japan', 'Germany') for example.
In Teradata, you would use the qualify clause:
select o.*
from orders o
qualify row_number() over (partition by country order by total desc) <= 10;

SQL query to count number of rows with same value

I have this table data:
I want to perform an sql query which will give me the total number of distinct loan applications per city.
So for example, I would expect this output
City Wexford
Loans 1
City Waterford 1
Loans 1
City Galway
Loans 3
Any idea what kind of query I need to perform to get the count of distinct loans for each city?
I would guess, probably a COUNT (Distinct ID) with GROUP BY. Something like this:
SELECT city, COUNT(DISTINCT LoanApplicationID) as Loans
FROM tableName
GROUP BY city
Here is another approach for this question. I am adding this because using DISTINCT may cause performance issues for another example, especially for large databases. Good to keep in mind.
select city,count(LoanApplicationID) as Loans
from (
select LoanApplicationID, city
from tablename
group by LoanApplicationID, city
) t
group by city

I can't get max and min from my table

How come this query returns an error?
select CUSTOMER, TOTAL_VALUE
from CUSTOMER, SALES
where TOTAL_VALUE in (select max(TOTAL_VALUE), min(TOTAL_VALUE)
from SALES)
When I just do max(TOTAL_VALUE) or min(TOTAL_VALUE) alone it works perfectly. But I need to get the min number in TOTAL_VALUE and max number in TOTAL_VALUE. Can anyone help me figure out why this query won't work for me? I would like to keep the structure that i have (using the in operator and nested subquery)
It returns an error because the subquery is returning two values, not one. Here is one fix:
select CUSTOMER, TOTAL_VALUE
from CUSTOMER cross join
SALES join
(select max(TOTAL_VALUE) as maxt, min(TOTAL_VALUE) as mint
from sales
) sm
where s.total_value in (sm.maxt, sm.mint);
That said, the query makes no sense. There you are going to get a list of every customer along with the value of the overall minimum and maximum sales.
This does answer your question. If you have another question, then provide sample data, desired results, in another question.
Try this (Joining SALES and CUSTOMER tables):
select C.CUSTOMER, MIN(TOTAL_VALUE), MAX(TOTAL_VALUE)
from SALES S
join CUSTOMER C on S.Customer_ID=C.Customer_ID
group by C.CUSTOMER
order by C.CUSTOMER

Count number of users from a certain country

I have a table of users, and in this table I have a country field telling where these people are from (i.e. "Sweden", "Italy", ...). How can I do a SQL query to get something like:
Country Number
Sweden 10
Italy 50
... ...
Users select their countries from a list I give to them, but the list is really huge so it would be great to have a SQL query that can avoid using that list, that is look in the DB and give back only those countries which are in the database, because for example I have nobody from Barbados, even if I have that option in the country select field of the signup form :)
Thanks in advance!
If the name of the country is in the Users table, try something like this:
SELECT Country, COUNT (*) AS Number
FROM Users
GROUP BY Country
ORDER BY Country
If the name of the country is in the country table, then you will have to join
SELECT Contries.CountryName, Count (*) AS Number
FROM Users
INNER JOIN Countries
ON Users.CountryId = Countries.CountryId
GROUP BY Countries.CountryName
ORDER BY Countries.CountryName
This will give what you want. But you might want to cache the result of the query. With a lot of users it's quite a heavy query.
SELECT
country,
COUNT(*)
FROM
users
GROUP BY
country
Perhaps a better idea is (assuming you don't need the counts) to do it like this:
SELECT
DISTINCT country
FROM
users
Sounds like you want something like this...?
SELECT Country, COUNT(*) AS Number
FROM Users
GROUP BY Country
This is pretty straightforward:
SELECT
Country, COUNT(*) AS 'Number'
FROM
YourTable
GROUP BY
Country
ORDER BY
Country
You just group your data by country and count the entries for each country.
Or if you want them sorted by the number of visitors, use a different ORDER BY clause:
SELECT
Country, COUNT(*) AS 'Number'
FROM
YourTable
GROUP BY
Country
ORDER BY
COUNT(*) DESC
If you want the count per country:
select country, count(*) from users group by country;
If you just want the possible values:
select distinct country from users;
SELECT BillingCountry, COUNT(*)as Invoices
FROM Invoice
GROUP BY BillingCountry
ORDER BY Invoices DESC