How do I select all values which satisfy certain aggregate properties? - sql

Say, I have a table (named "Customers") which consists of:
CustomerName
Country
City
I am trying to list the names of all customers from cities where there are at least two customers.
This is my initial attempt:
SELECT CustomerName, City
FROM Customers
GROUP BY City
HAVING COUNT(City) > 1
This is the result that I got:
CustomerName
City
Person A
New York
Person C
Los Angeles
Here, Person A is a person from NY who appears on the top of the table and similar for Person B. However, what I wanted was the listing of all customers from New York and LA.
When I tried:
SELECT COUNT(CustomerName), City
FROM Customers
GROUP BY City
HAVING COUNT(City) > 1
I had
COUNT(CustomerName)
City
3
New York
5
Los Angeles
This means that the code is working properly, except that my original code only displays a person on top of the table from NY and LA. How do I resolve this issue?

Get cities with more than 1 customer in a subquery, and use that list to select the customers:
SELECT cst.CustomerName
FROM Customers cst
WHERE Cst.City in (
-- All cities where there are at least two customers
SELECT CstGE2.City
FROM Customers CstGE2
GROUP BY CstGE2.City
HAVING count(*) >= 2
)

How about this? I've taken the city out of the select part since you said you just wanted customer names.
SELECT a.CustomerName
FROM Customers a
WHERE (
SELECT COUNT(b.CustomerName)
FROM Customers b
WHERE b.City = a.City
) > 1
ORDER BY a.CustomerName

Related

How to get country wise max populated city with population count

I am currently searching for a SQL query that does the following:
I have a table of all cities worldwide with their countries and population.
e.g. the table "city" (some columns)
name
country
population
Berlin
Germany
3640000
New York
USA
8419000
Hamburg
Germany
1841000
Los Angeles
USA
3967000
I know need to find the city with the city with the highest population per country.
e.g. the desired result
name
population
country
Berlin
3640000
Germany
New York
8419000
USA
The problem is that this query:
SELECT name, MAX(population) FROM city GROUP BY country
wouldn't return the appropriate name of the city. I know why that happens but am not sure how I could solve it in another way.
Any help is appreciated! Thanks!
ANSI SQL solution using subquery almost for any rdbms:
create table city (name varchar(50),country varchar(50), population int);
insert into city values('Berlin' ,'Germany', 3640000);
insert into city values('New York' ,'USA', 8419000);
insert into city values('Hamburg' ,'Germany', 1841000);
insert into city values('Los Angeles' ,'USA', 3967000);
Query:
select name, population, country from city c
where population=(select max(population ) from city a where a.country=c.country)
Output:
name
population
country
Berlin
3640000
Germany
New York
8419000
USA
db<fiddle here
you need to tag your dbms , but this works in most of databases including mariadb , using window function will ovoid hitting city table twice:
select * from
(
select * , row_number() over (partition by country order by population desc) rn
from city
) t
where rn = 1
you can use "NOT EXISTS"
SELECT * from country a
where not exists
(
select 1 from country b
where a.country = b.country
and b.population > a.population
)
select * from city where (country, population) in
(
select country, max(population) from city group by country
);

sql, select only such rows that share a predefined value

I am trying to select such rows that have the same specific value in one of the columns. For example, in the table below there are airlines that fly to different cities. I need to select only such airlines that fly exclusively to the usa. In the table below that would be only the airline2. The city is basically not important for the moment.
airline country_destination city_destination
airline1 usa washington
airline1 eng london
airline1 fra paris
airline2 usa new york
airline2 usa chicago
airline2 usa washington
airline3 can montreal
airline3 usa new york
airline3 can toronto
My first guess returns all the airlines, because in every of them the usa appears at least once.
select distinct airline from table1 where country_destination = 'usa'
I assume I need a nested 'select' and probably a group by airlines? Somewhere directionof what I have below? But I am stuck at this point. Any help is highly appreciated!
select airline, country_destination
from (select airline, country_destination from table1 where country_destination = 'usa' group by airline)
You do need to aggregate.
This is the simplest way I know of to do it:
select airline
from table1
group by airline
having min(country_destination) = max(country_destination)
and min(country_destination) = 'usa';
One method is to check if the airline's row count matches the conditional count (in this case, the amount of rows where the destination is 'usa').
The CTE aggregates the airline data. In the SELECT-statement you can apply the filter to only include airlines where the total row count equals the row count for destination 'usa'. If the counts between count_all and count_usa differ you know there were other country destinations.
with counts as ( select airline,
count(*) as count_all,
sum(case when country_destination == 'usa' then 1 end) as count_usa
from table1
group by 1 )
select airline
from counts
where count_all = count_usa;
you can use below with inner query-
select * from
(select distinct airline, country_destination from table1 ) t
group by airline
having count(airline) = 1 AND country_destination='usa';

SQLite query to get table based on values of another table

I am not sure what title has to be here to correctly reflect my question, I can only describe what I want.
There is a table with fields:
id, name, city
There are next rows:
1 John London
2 Mary Paris
3 John Paris
4 Samy London
I want to get a such result:
London Paris
Total 2 2
John 1 1
Mary 0 1
Samy 1 0
So, I need to take all unique values of name and find an appropriate quantity for unique values of another field (city)
Also I want to get a total quantity of each city
Simple way to do it is:
1)Get a list of unique names
SELECT DISTINCT name FROM table
2)Get a list of unique cities
SELECT DISTINCT city FROM table
3)Create a query for every name and city
SELECT COUNT(city) FROM table WHERE name = some_name AND city = some_city
4)Get total:
SELECT COUNT(city) FROM table WHERE name = some_name
(I did't test these queries, so maybe there are some errors here but it's only to show the idea)
As there are 3 names and 2 cities -> 3 * 2 = 6 queries to DB
But for a table with 100 cities and 100 names -> 100 * 100 = 10 000 queries to DB
and it may take a lot of time to do.
Also, names and cities may be changed, so, I can't create a query with predefined names or cities as every day it's new ones, so, instead of London and Paris it may be Moscow, Turin and Berlin. The same thing with names.
How to get such table with one-two queries to original table using sqlite?
(sqlite: I do it for android)
You can get the per-name results with conditional aggregation. As for the total, unfortunately SQLite does not support the with rollup clause, that would generate it automatically.
One workaround is union all and an additional column for ordering:
select name, london, paris
from (
select name, sum(city = 'London') london, sum(city = 'Paris') paris, 1 prio
from mytable
group by name
union all
select 'Total', sum(city = 'London'), sum(city = 'Paris'), 0
from mytable
) t
order by prio, name
Actually the subquery might not be necessary:
select name, sum(city = 'London') london, sum(city = 'Paris') paris, 1 prio
from mytable
group by name
union all
select 'Total', sum(city = 'London'), sum(city = 'Paris'), 0
from mytable
order by prio, name
#GMB gave me the idea of using group by, but as I do it for SQLite on Android, so, the answer looks like:
SELECT name,
COUNT(CASE WHEN city = :london THEN 1 END) as countLondon,
COUNT(CASE WHEN city = :paris THEN 1 END) as countParis
FROM table2 GROUP BY name
where :london and :paris are passed params, and countLondon and countParis are fields of the response class

How to find people in a database who live in the same cities?

I'm new to SQL, and I'm asking for help in an apparently easy question, but it gets cumbersome in my mind.
I have the following table:
ID NAME CITY
---------------------
1 John new york
2 Sam new york
3 Tom boston
4 Bob boston
5 Jan chicago
6 Ted san francisco
7 Kat boston
I want a query that returns all the people who live in a city that another person registered in the database also lives in.
The answer, for the table I showed above, would be:
ID NAME CITY
---------------------
1 John new york
2 Sam new york
3 Tom boston
4 Bob boston
7 Kat boston
This is really a two part question:
What cities have more than one user located in them?
What users live in that subset of cities?
Let's answer it in two parts. Let's also make the simplifying assumption (not stated in your question) that the Users table has only one entry per user per city.
To find cities with more than one user:
SELECT City FROM Users GROUP BY City HAVING COUNT(*) > 1
Now, let's find all the users for those cities:
SELECT ID, User, City FROM Users
WHERE City IN (SELECT City FROM Users GROUP BY CITY HAVING COUNT(*) > 1)
I would use EXISTS :
SELECT t.*
FROM table t
WHERE EXISTS (SELECT 1 FROM table t1 WHERE t1.city = t.city AND t1.name <> t.name);
To avoid a correlated subquery which leads to a nested loop, you could perform a self join:
SELECT id, name, city
FROM persons
JOIN (SELECT city
FROM persons
GROUP BY city HAVING count(*) > 1) AS cities
USING (city);
This might be the most performant solution.
This will give you the rows that have the same city more than 1 time:
SELECT persons.*
FROM persons
WHERE (SELECT COUNT(*) FROM persons AS p GROUP BY CITY HAVING p.CITY = persons.CITY) > 1
This is just a different flavor from the others that have posted.
SELECT ID,
name,
city
FROM (SELECT DISTINCT
ID,
name,
city,
COUNT(1) OVER (PARTITION BY city) AS cityCount
FROM table) t
WHERE cityCount > 1
This can be expressed many ways. Here is one possible way:
select * from persons p
where exists (
select 1 from persons p2
where p2.city = p.city and p2.name <> p.name
)

How to join different columns of same table?

Suppose I have one table with two column, Country and City.
Country
USA
Canada
UK
City
NY
London
I want to join/merge both column records and expect the output like this -
USA
Canada
UK
NY
London
So, what will be the SQL query to merge different columns records of same table?
SELECT Country FROM TABLE
UNION
SELECT City FROM Table
should do it.
Responding to the comment "I am searching for any quick way. Because if I need to merge 10 columns then i have to write 10 Unions! Is there any other way?":
You can use an unpivot, which means you just need to add the column names into a list. Only thing is to watch for data types though. eg:
--CTE for example only
;WITH CTE_Locations as (
select Country = convert(varchar(50),'USA'), City = convert(varchar(50),'NY')
union select Country = 'Canada', City = 'Vancouver'
union select Country = 'UK', City = 'Manchester'
)
--Select a list of values from all columns
select distinct
Place
from
CTE_Locations l
unpivot (Place for PlaceType in ([Country],[City])) u