How do I keep only 1 result according the alphabetical order in a tie with SQL queries? - sql

The question asked to take the city with the highest sum of goods that bought by customer for each country. Basically, there are cities that have the same number of goods, but we only keep the first one in alphabetical order. The result only contains country name, the city with highest number of goods and their goods in sum.
Table Schema:
Country table:
country_name
city_name
Goods table:
city_name
user_id
number_of_goods
My queries result:
France Paris 85
Germany Berlin 100
Germany Frankfurt 100
Germany Luxembourg 100
Netherlands Amsterdam 75
Spain Barcelona 93
The right result should be:
France Paris 85
Germany Berlin 100
Netherlands Amsterdam 75
Spain Barcelona 93

You can use row_number() :
select t.*
from (select t.*, row_number() over (partition by country order by city) as seq,
max(no_goods) over (partition by country) as max_good
from table t
) t
where seq = 1;

use aggregation functions min() for city and max() for no_of_goods.
select t1.country, t1.no_of_goods, min(t2.city) as city
from
(select country, max(no_of_goods) as no_of_goods from tableA
group by country) t1
left join tableA t2 on t2.no_of_goods = t1.no_of_goods and t1.country = t2.country
group by t1.country, t1.no_of_goods
see dbfiddle.

Basically, there are cities that have the same number of goods, but we only keep the first one in alphabetical order.
Based on your sample data, all cities in a country seem to have the same number_of_goods. If so, you can just use aggregation:
select c.country, min(c.city_name), max(number_of_goods)
from countries c join
goods g
on c.city_name = g.city_name
group by c.country;

Related

Oracle Sql Developer (Select Count) Twoc olumns

I have to make a query that has the Total number of customers by country and city
country and city are columns that are inside the customer table
On my own I have managed to get the total number of customers per city like this:
SELECT city, COUNT (*)
FROM employees
GROUP BY city
ORDER BY city
But how do I get it together with the country?
looking for information I think it should be something like this and ordered from largest to smallest
Country
City
TOTAL_CUSTOMERS
USA
Kirkland
3
USA
London
2
UK
Redmond
2
UK
Seattle
1
UK
Tacoma
1
What we have been told is to say Total number of customers by country and city.
You simply add country to the column list and group by list:
SELECT country,city, COUNT(*)
FROM employees
GROUP BY country,city
ORDER BY COUNT(*) DESC

How to check how many times some values are duplicated?

I have table like below:
city | segment
------------------
London | A
London | B
New York | A
Berlin | B
Barcelona | C
Barcelona | H
Barcelona | E
Each city should have only one segment, but as you can see there are two cities (London and Barcelona) that have more than one segment.
It is essential that in result table I need only these cities which have > 1 segmnet
As a result I need somethig like below:
city - city based on table above
no_segments - number of segments which have defined city based on table above
segments - segments of defined city based on table above
city
no_segments
segments
London
2
A
B
Barcelona
3
C
H
E
How can I do that in Oracle?
You can use COUNT(*) OVER ()(in order to get number of segments) and ROW_NUMBER()(in order to prepare the results those will be conditionally displayed) analytic functions such as
WITH t1 AS
(
SELECT city,
segment,
COUNT(*) OVER (PARTITION BY city) AS no_segments,
ROW_NUMBER() OVER (PARTITION BY city ORDER BY segment) rn
FROM t
)
SELECT DECODE(rn,1,city) AS city,
DECODE(rn,1,no_segments) AS no_segments,
segment
FROM t1
WHERE no_segments > 1
ORDER BY t1.city, segment
Demo
Another way to do this is:
SELECT NULLIF(CITY, PREV_CITY) AS CITY,
SEGMENT
FROM (SELECT CITY,
LAG(CITY) OVER (ORDER BY CITY DESC) AS PREV_CITY,
SEGMENT,
COUNT(SEGMENT) OVER (PARTITION BY CITY) AS CITY_SEGMENT_COUNT
FROM CITY_SEGMENTS)
WHERE CITY_SEGMENT_COUNT > 1
Using LAG() to determine the "previous" CITY allows us to directly compare the CITY values, which in my mind is clearer that using ROW_NUMBER = 1.
db<>fiddle here
;with cte as (
Select city, count(seg) as cntseg
From table1
Group by city having count(seg) > 1
)
Select a.city, b.cntseg, a.seg
From table1 as a join cte as b
On a.city = b.city

How to replace multiple columns in one SQL query?

I have 2 tables: country and trip.
A trip can have up to 3 country codes.
country table
country_code
country_name
FRA
FRANCE
IRL
IRELAND
JPN
JAPAN
MAR
MOROCCO
NZL
NEW ZEALAND
trip table
trip_id
country_code
country_code2
country_code3
1
FRA
IRL
JPN
2
MAR
NZL
My goal is to have country names displayed on the trip table instead of country codes.
I succeed to have only 1 country code replaced, thanks to the left join clause. I would like to have up to 3 country names displayed per row.
SELECT trip_id, country_name
FROM trip
LEFT JOIN country ON country_code = country_name
The actual output of the trip table:
trip_id
country_name
1
FRANCE
2
MOROCCO
Is there a way to replace each country code with its corresponding country name?
The EXPECTED output of the query from the trip table:
trip_id
country_name
country_name2
country_name3
1
FRANCE
IRELAND
JAPAN
2
MOROCCO
NEW ZEALAND
Thank you!
You could add two more joins
SELECT trip_id, c1.country_name, c2.country_name, c3.country_name
FROM trip t
left join
country c1
on t.country_code = c1.country_code
left join
country c2
on t.country_code2 = c2.country_code
left join
country c3
on t.country_code3 = c3.country_code
The cleanest way of accomplishing this query is using subqueries:
SELECT t.trip_id,
(SELECT country_name FROM country WHERE country_code = t.country_code) "c1",
(SELECT country_name FROM country WHERE country_code = t.countty_code2) "c2",
(SELECT country_name FROM country WHERE country_code = t.country_code3) "c3"
FROM trip t

which command should i use on SQL for having?

I want your help.
I have 2 columns with data, customer and city.
I want to show customers a mix if this customer has more different cities, and I want to show the customer if it has only 1 city.
for example, I have this data:
customer city
ana London
Ella London
Sarah Paris
Haidi Greece
Chloe France
ana London
Ella france
I want to show it like this:
Ana London
Ella Mix
Sarah Paris
Haidi Greece
Chloe France
How could I do this? Which command should I use?
Here you go.
Select
Customer,
case when count(DISTINCT city) > 1 then 'MIX' Else max(City) End as City
from MyTable
Group by Customer
You could use a command like before:
Select
Customer,
case when count(city) > 1 then 'MIX' Else City End as City
from Mytable
Group by Customer, City
but Ana is present twice in the table, and you have to use the Max to solve
Select
Customer,
case when count(city) > 1 then 'MIX' Else MAX(City) End as City
from Mytable
Group by Customer
If you wanted NULL instead of 'Mix', you could use:
select customer, nullif(min(city), max(city)) as city
from t
group by customer;
You can actually extend this to get 'Mix':
select customer, coalesce(nullif(min(city), max(city)), 'Mix') as city
from t
group by customer;
But NULL makes sense to me.
Here's what I think you're looking for
select customer,
case when count(*)>1
then 'mix'
else max(city) end as city
from t
group by customer;

SQLite percentages with small values

So I have this table of subscribers of users and the country they are in.
UserID | Name | Country
-------+-------------------+------------
1 | Zaphod Beeblebrox | UK
2 | Arthur Dent | UK
3 | Gene Kelly | USA
4 | Nat King Cole | USA
I need to produce a list of all the users by percentage from each of the countries. I also need all the smaller member countries (under 1%) to be collapsed into an "OTHERS" category.
I can accomplish a simple "top x" of members trivially with a
SELECT COUNTRY, COUNT(*) AS POPULATION FROM SUBSCRIBERS GROUP BY COUNTRY ORDER BY POPULATION DESC LIMIT 10
and can generate the percentages by PHP server side code, but I don't quite know how to:
Do all of it in SQL including percentage calculations directly in the result
Club all under 1% members into a single OTHERS category.
So I need something like this:
Country | Population
--------+-----------
USA | 25.4%
Brazil | 12%
UK | 5%
OTHERS | 65%
Appreciate the help!
Here is query for this, I used a subquery to count the total number of rows and then used that to get the percentage value for each. The 'Others' category was generated in a separate query. Rows are sorted by descending population with the Others row last.
SELECT * FROM
(SELECT country , ROUND((100.0*COUNT(*)/count_all),1) ||'%' AS population
FROM (SELECT count(*) count_all FROM subscribers) AS sq,
subscribers s
WHERE (SELECT 100*count(*)/count_all
FROM subscribers s2
WHERE s2.country = s.country) > 1
GROUP BY country
ORDER BY population DESC)
UNION ALL
SELECT 'OTHERS', IFNULL(ROUND(100.0*COUNT(*)/count_all,1),0.0) ||'%' AS population
FROM (SELECT count(*) count_all FROM subscribers) AS sq,
subscribers s
WHERE (SELECT 100*count(*)/count_all
FROM subscribers s2
WHERE s2.country = s.country) <= 1
Ok I think I might have found a way to do this that's a hell of a lot quicker on execution speed:
SELECT territory,
Round(Sum(percentage), 3) AS Population
FROM (SELECT
Round((Count(*)*100.0)/(SELECT Count(*) FROM subscribers),3) AS Percentage,
CASE
WHEN ((Count(*)*100.0)/(SELECT Count(*) FROM subscribers)) > 2 THEN
country
ELSE 'Other'
END AS Territory
FROM subscribers
GROUP BY country
ORDER BY percentage DESC)
GROUP BY territory
ORDER BY population DESC;