How to find the 3rd largest population of a country by state [closed] - sql

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I have a table where there are three columns zipcode, state, total_population.
ZIPCODE STATE POPULATION
11937 36 15511
11941 36 1822
11940 36 4933
12435 36 280
12063 36 441
64733 29 1251
64734 29 1952
64735 29 13653
I am looking for this
zipcode state third_highest_population
11941 36 1822
4733 29 1251
I cannot think of a way to find the third largest population each state..any help is much appreciated

You can use window functions to help rank zip code populations by state, then keep the third ranked for each state.
SELECT *
FROM (
SELECT zipcode,
state,
total_population,
DENSE_RANK() OVER (PARTITION BY state ORDER BY total_population DESC) as ziprank
FROM yourtable
) r
WHERE ziprank = 3
RANK(), DENSE_RANK() and ROW_NUMBER() may all work here depending on your data. DENSE_RANK() insures you will get at least 1 (but maybe more) ranked at 3. The reason you may get more is if two zip codes share the same population in the state. That is highly unlikely though, so DENSE_RANK() is a good fit.

Something like:
select * from (
select your_table.*, rank() over(partition by state order by totpop) rnk from your_table
) t
where
rnk = 3

Sample Data
DECLARE #Data AS TABLE (zipcode INT,
[state] VARCHAR(10),
[total_population] INT
)
INSERT INTO #Data
SELECT 500010,'Ap',24524540 UNION ALL
SELECT 500020,'KA',47857441 UNION ALL
SELECT 500030,'TN',89456655 UNION ALL
SELECT 500040,'KL',45775475 UNION ALL
SELECT 500050,'UP',47411189
DECLARE #N INT = 3 -- Specify highest total as you required
Using Co related sub query
SELECT * FROM #Data
Go
SELECT zipcode,
[state],
[total_population]
FROM #Data e1
WHERE #N-1 = ( SELECT COUNT(DISTINCT [total_population])
FROM #Data e2
WHERE e2.[total_population] > e1.[total_population] )

Related

Is there a way to display the total count of rows in a separate row?

I have a table that looks like this:
City_Id
City
41
Athena
39
Beijing
35
London
30
Rio de Janeiro
28
Salt Lake City
18
Sochi
7
Sydney
4
Torino
is there a way to display another row in the bottom that will display the total count of rows?
City_Id
City
41
Athena
39
Beijing
35
London
30
Rio de Janeiro
28
Salt Lake City
18
Sochi
7
Sydney
4
Torino
Total
8
You can actually use GROUPING SETS for this. This avoids having to scan the table twice.
However you still have the data-type mismatch problem. You could solve it by casting, but it's probably easier to just swap the columns around
SELECT
CASE WHEN GROUPING(City) = 0 THEN City ELSE 'Total' END AS City,
CASE WHEN GROUPING(City_Id) = 0 THEN City_Id ELSE COUNT(*) END AS City_Id
FROM Table1
GROUP BY GROUPING SETS (
(City_Id, City),
()
)
ORDER BY GROUPING(City_Id);
SQL Fiddle
What this does is generate separate result-sets, unioned together. You can differentiate between a grouped row and a non-grouped row using the GROUPING function.
I would agree with most of the other comments that acquiring a result set count would be more appropriate from the application code (which usually has a mechanism specifically for this purpose).
However...
If you must have a TSQL solution for your question, an option is to return the count in a separate column. This is different than returning it in a separate row, of course. There are pros & cons with each approach.
DROP TABLE IF EXISTS #Cities;
CREATE TABLE #Cities (
City_Id INT,
City VARCHAR(128)
);
INSERT INTO #Cities
VALUES
(41, 'Athena'),
(39, 'Beijing'),
(35, 'London'),
(30, 'Rio de Janeiro'),
(28, 'Salt Lake City'),
(18, 'Sochi'),
(7 , 'Sydney'),
(4 , 'Torino');
SELECT *, COUNT(*) OVER(ORDER BY (SELECT NULL)) AS Total
FROM #Cities;
--Count is properly reflected based on WHERE clause.
SELECT *, COUNT(*) OVER(ORDER BY (SELECT NULL)) AS Total
FROM #Cities
WHERE City LIKE 'S%';
--Be careful with this one--the COUNT(*) may not be what you expected.
SELECT TOP(4) *, COUNT(*) OVER(ORDER BY (SELECT NULL)) AS Total
FROM #Cities;
NOTE: be aware that this approach may not scale (perform) well for large result sets. Be sure to do some testing!
As you know already, it should be done in the presentation layer. But if you just want to know if there is any way, then I would suggest to use UNION ALL
select cast(City_Id as varchar(10)) City_Id, City from Table1
union all
select 'Total' as City_Id, cast(count(*) as varchar(14)) from Table1
Here is the sql fiddle

Select MAX between 2 similar ID [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I want to select maximum number of wins from many teams
Table looks like-
NAME WINS LOSES ID_TEAM
Gordon 4 0 5
Garry 7 0 5
Uldis 5 7 2
Armands 9 2 2
Bjorn 12 2 8
Erwin 1 0 8
I tried to select max wins from team 1 but it select booth teammate
select max(wins) as max_wins from (select wins from fighter where id_team=1) group by wins;
getting the max() win of same team.
select ID_TEAM, max(wins)
from fighter
where ID_TEAM = 1
group by ID_TEAM
selecting multiple teams, use INkeyword
select * from fighter f
inner join (
select ID_TEAM, max(wins)
from fighter
where ID_TEAM in (1,5,6)
group by ID_TEAM) t1 on t1.ID_TEAM = f.ID_TEAM
I would suggest using an analytical function considering that there may be a case where maximum fights are won by multiple fighters and also the following query will give all the details of the fighter who won maximum games in his team.
SELECT
*
FROM
(
SELECT
T.*,
DENSE_RANK() OVER(
PARTITION BY ID_TEAM
ORDER BY
WINS DESC NULLS LAST
) AS RN
FROM
FIGHTER T
WHERE
ID_TEAM = 1
) -- IF YOU WANT TO GET DATA FOR ALL THE TEAMS THEN REMOVE THIS WHERE CLAUSE
WHERE
RN = 1;
Cheers!!
A correlated subquery is often the most efficient method:
select f.*
from fighter f
where f.wins = (select max(f2.wins)
from fighter f2
where f2.id_team = f.id_team
);
For performance, you want an index on fighter(id_team, wins).

Remove duplicates based on common where condition in sql [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
Select * from Table_name i am getting below result.
S.no Emp_id Date Description Amount Splitup amount
2667737 12345 8/12/2019 Icecream 50 30
2667738 12345 8/12/2019 Icecream 50 20
2667739 12346 8/12/2019 Chocolate 50 20
But i need the result
S.no Emp_id Date Description Amount Splitup amount
2667737 12345 8/12/2019 Icecream 50 30
2667738 12345 Icecream 20
2667739 12346 8/12/2019 Chocolate 50 20
i need only the first as amount .For same s.no and same emp_id was to have only one date and amount, remaining rows i want to make it empty.
You can consider using lag() windows analytic function :
select [S.no], [Emp_id],
case when lag([Date],1,null) over
(partition by [Date] order by [S.no]) = [Date] then
null
else
[Date]
end as [Date], [Description],
case when lag([Amount],1,null) over
(partition by [Amount] order by [S.no]) = [Amount] then
null
else
[Amount]
end as [Amount], [Splitup amount]
from tab;
Demo
You can use conditional logic with row_number():
select s.s_no, s.emp_id,
(case when row_number() over (partition by emp_id, description order by s_no) = 1
then date
end) as date,
description,
(case when row_number() over (partition by emp_id, description order by s_no) = 1
then amount
end) as amount,
splitup
from t
order by emp_id, s_no;
Note the outer order by and how it matches the conditions in the window clause. SQL result sets are unordered unless there is an explicit order by. If you want the "first" row to have the values, then you need to be sure that the result set is in the right order.

Oracle select similar values [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
i have a database table with a lot of values like this: 340.13 and 232.89.
Now i want to select the value with the best match with a comparison value.
Is this possible without great effort?
This will match values that are within +-10% of the search value and, if there are multiple values, will find the closest match by absolute difference.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TABLE_NAME ( VALUE ) AS
SELECT 340.13 FROM DUAL UNION ALL
SELECT 232.89 FROM DUAL UNION ALL
SELECT 224.73 FROM DUAL UNION ALL
SELECT 100.00 FROM DUAL;
Query 1:
WITH search_values ( search_value ) AS (
SELECT 330 FROM DUAL UNION ALL
SELECT 230 FROM DUAL
)
SELECT search_value,
value
FROM (
SELECT search_value,
value,
RANK() OVER ( PARTITION BY Search_value
ORDER BY ABS( value - search_value ) ) AS rnk
FROM table_name t
INNER JOIN
search_values v
ON ( t.value BETWEEN search_value * 0.9 AND search_value * 1.1 )
)
WHERE Rnk = 1
Results:
| SEARCH_VALUE | VALUE |
|--------------|--------|
| 230 | 232.89 |
| 330 | 340.13 |
This is a pretty basic and common task so here is the general approach.
First you need to decide on "best-match-criteria". Basically it as a function of value stored in row and input value. So you can implement this function and evaluate it calling something like MATCH_RATING(COLUMN, :value) for each row. Now that you have this rating for every row, you can sort rows in any way you like and filter the most fitting one (ROWNUM is great for this as are analytic functions like RANK or ROW_NUMBER).
SELECT *
FROM (
SELECT VALUE,
MATCH_RATING(VALUE, :input_value) RATING
FROM YOUR_TABLE
ORDER BY RATING DESC)
WHERE ROWNUM = 1
Then a good idea is to check whether your chosen criteria are implemented in language because if they are, using SQL features will surely be bettter performance-wise.
For example, if distance between two numbers is the only thing that concerns you, SQL will look something like this.
SELECT VALUE
FROM (
SELECT VALUE,
ABS(VALUE - :input_value) DISTANCE
FROM YOUR_TABLE
ORDER BY DISTANCE)
WHERE ROWNUM = 1
If your function assumes 0 value on some interval meaning some rows should never get into your resultset then you should also use WHERE clause filtering useless rows (WHERE MATCH_RATING(COLUMN, :value) > 0).
Back to our distance example: let's accept distance not more than 5% of input value.
SELECT VALUE
FROM (
SELECT VALUE,
ABS(VALUE - :input_value) DISTANCE
FROM YOUR_TABLE
WHERE VALUE BETWEEN 0.95 * :input_value AND 1.05 * :input_value
ORDER BY DISTANCE)
WHERE ROWNUM = 1
By the way, index on YOUR_TABLE.VALUE will surely be helpful for this example.

Select unique records [duplicate]

This question already has answers here:
Fetch the rows which have the Max value for a column for each distinct value of another column
(35 answers)
Closed 2 years ago.
I'm working with a table that has about 50 colums and 100,000 rows.
One column, call it TypeID, has 10 possible values:
1 thourgh 10.
There can be 10,000 records of TypeID = 1, and 10,000 records of TypeID = 2 and so one.
I want to run a SELECT statement that will return 1 record of each distinct TypeID.
So something like
TypeID JobID Language BillingDt etc
------------------------------------------------
1 123 EN 20130103 etc
2 541 FR 20120228 etc
3 133 FR 20110916 etc
4 532 SP 20130822 etc
5 980 EN 20120714 etc
6 189 EN 20131009 etc
7 980 SP 20131227 etc
8 855 EN 20111228 etc
9 035 JP 20130615 etc
10 103 EN 20100218 etc
I've tried:
SELECT DISTINCT TypeID, JobID, Language, BillingDt, etc
But that produces multiple TypeID rows of the same value. I get a whole bunch of '4', '10', and so on.
This is an ORACLE Database that I'm working with.
Any advise would be greatly appreciated; thanks!
You can use ROW_NUMBER() to get the top n per group:
SELECT TypeID,
JobID,
Language,
BillingDt,
etc
FROM ( SELECT TypeID,
JobID,
Language,
BillingDt,
etc,
ROW_NUMBER() OVER(PARTITION BY TypeID ORDER BY JobID) RowNumber
FROM T
) T
WHERE RowNumber = 1;
SQL Fidle
You may need to change the ORDER BY clause to fit your requirements, as you've not said how to pick one row per TypeID I had to guess.
WITH RankedQuery AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY TypeID ORDER BY [ordercolumn] DESC) AS rn
FROM [table]
)
SELECT *
FROM RankedQuery
WHERE rn = 1;
This will return the top row for each type id, you can add an order by if you want a specific row, not just any.