Get first N rows from table based on condition - Oracle SQL - sql

I have a table:
table1
Type Attribute Value Count
Fruit Apple Sweet 1772
Fruit Apple Sour 1021
Fruit Apple Sweetest 930
Fruit Apple Sweetest 930
Fruit Orange Sweetest 200
Fruit Orange Sour 190
Fruit Orange Sweetest 160
Fruit Orange Sweetest 140
I need the first 3 rows based on type and attribute and count.
So, the output should be:
Type Attribute Value Count
Fruit Apple Sweet 1772
Fruit Apple Sour 1021
Fruit Apple Sweetest 930
Fruit Orange Sweetest 200
Fruit Orange Sour 190
Fruit Orange Sweetest 160
How can I grab the first 3 rows for each type, attribute, count?

The other answers by #GordonLinoff and #LukaszSzozda were based on the original post, and not on the clarification added later by the OP. The SQL Fiddle based on original post, using SQL in answer by #Gordon (which is basically identical to answer by #Lukasz as they posted the answers about the same time, before the clarification) returns 4 rows per Apple and 4 rows per Orange:
FOOD_TYPE ATTRIBUTE VALUE CNT SEQNUM
Fruit Apple Sour 1021 1
Fruit Apple Sweet 1772 1
Fruit Apple Sweetest 930 1
Fruit Apple Sweetest 930 2
Fruit Orange Sour 190 1
Fruit Orange Sweetest 200 1
Fruit Orange Sweetest 160 2
Fruit Orange Sweetest 140 3
Modified SQL here
select t.*
from (select Food.*,
row_number() over (partition by food_type, attribute order by cnt desc) as seqnum
from Food
) t
where seqnum <= 3;
returns the desired result:
FOOD_TYPE ATTRIBUTE VALUE CNT SEQNUM
Fruit Apple Sweet 1772 1
Fruit Apple Sour 1021 2
Fruit Apple Sweetest 930 3
Fruit Orange Sweetest 200 1
Fruit Orange Sour 190 2
Fruit Orange Sweetest 160 3

Use row_number():
select t.*
from (select t.*,
row_number() over (partition by type, attribute, value order by count desc) as seqnum
from t
) t
where seqnum <= 3;

You could use ROW_NUMBER:
WITH cte AS (
SELECT t.*, ROW_NUMBER(PARTIION BY "Type", Attribute ORDER BY "count" DESC) AS rn
FROM tab t
)
SELECT *
FROM cte
WHERE rn <= 3;

Related

How can I give specific number by group of identical values in a select clause?

I have this :
Person
Dinner
Paul
Apple
Alfred
Banana
John
Apple
Jimmy
Banana
Johnny
Strawberry
I want to give a specific number for each distinct value in the Dinner column in a select clause like this :
Person
Dinner
Group
Paul
Apple
1
Alfred
Banana
2
John
Apple
1
Jimmy
Banana
2
Johnny
Strawberry
3
I tried this get the groups :
SELECT case when (lag(Dinner) OVER (ORDER BY id) = Dinner) or (lead(Dinner) OVER (ORDER BY Dinner) = Dinner) then 1 else 0 end,* FROM restaurant ORDER BY Dinner desc)
And it gives me this :
Person
Dinner
Group
Paul
Apple
1
John
Apple
1
Alfred
Banana
0
Jimmy
Banana
0
Johnny
Strawberry
1
It only gives me 1 or 0 because of the case when case.
I'm pretty sure there's easier way to do it, but I didn't find any.
Any help ?
Why not use DENSE_RANK?
SELECT Person,
Dinner,
DENSE_RANK() OVER (ORDER BY Dinner ASC) AS [Group]
FROM (VALUES('Paul','Apple'),
('Alfred','Banana'),
('John','Apple'),
('Jimmy','Banana'),
('Johnny','Strawberry'))V(Person, Dinner);

Partition by multiple columns having duplicate values in MS SQL

As an example, I have two columns in a table
**Fruit Color**
Mango Yellow
Mango Yellow
Apple Red
Apple Red
Expected Output
**Rank Fruit Color**
1 Mango Yellow
1 Mango Yellow
2 Apple Red
2 Apple Red
Tried Row_number() but it doesn't seem to yield the expected output. Tried Rank() and Dense_Rank() as well but didn't get the expected outcome
SELECT ROW_NUMBER() OVER (PARTITION BY Fruit,Color order by Fruit) , Fruit,Color
from #temp
ORDER BY FRUIT
rwno Fruit Color
1 Apple Red
2 Apple Red
1 Mango Yellow
2 Mango Yellow
You want dense_rank() and no partition by:
SELECT DENSE_RANK() OVER (ORDER BY Fruit, Color), Fruit, Color
from #temp
ORDER BY FRUIT

hive sql adding record count as column

I have records similar to the below
fruit day
apple 1/1/1990
apple 1/2/1990
apple 1/3/1990
plum 1/1/1990
orange 1/1/1990
orange 1/2/1990
orange 1/3/1990
I want to keep a running total for items for each day assuming item will increase by 1 every day. For example
fruit day count
apple 1/1/1990 1
apple 1/2/1990 2
apple 1/3/1990 3
plum 1/1/1990 1
orange 1/1/1990 1
orange 1/2/1990 2
You could use windowed COUNT:
SELECT *, COUNT(*) OVER(PARTITION BY fruit ORDER BY day)
FROM tab;
DBFiddle Demo
You can also use subquery:
select *,
(select count(*) from table where fruit = t.fruit and day <= t.day) count
from table t;

Using a query to return the most frequent value and the count within a group using SQL in MS Access

Say I have a table showing the type of fruit consumed by an individual over a 24 hour period that looks like this:
Name Fruit
Tim Apple
Tim Orange
Tim Orange
Tim Orange
Lisa Peach
Lisa Apple
Lisa Peach
Eric Plum
Eric Orange
Eric Plum
How would I get a table that shows only the most consumed fruit for each person, as well as the number of fruits consumed. In other words, a table that looks like this:
Name Fruit Number
Tim Orange 3
Lisa Peach 2
Eric Plum 2
I tried
SELECT Name, Fruit, Count(Fruit)
FROM table
GROUP BY Name
But that returns an error because Name needs to be in the GROUP BY statement as well. Every other method I've tried returns the counts for ALL values rather than just the maximum values. MAX(COUNT()) doesn't appear to be a valid statement, so I'm not sure what else to do.
This is a pain, but you can do it. Start with your query and then use join:
SELECT n.Name, n.Fruit
FROM (SELECT Name, Fruit, Count(Fruit) as cnt
FROM table as t
GROUP BY Name, Fruit
) as t INNER JOIN
(SELECT Name, max(cnt) as maxcnt
FROM (SELECT Name, Fruit, Count(Fruit) as cnt
FROM table
GROUP BY Name, Fruit
) as t
GROUP BY Name
) as n
ON t.name = n.name and t.cnt = n.maxcnt;

SQL calculate item frequency using multiple / dependent columns?

I'm completely new to SQL, and have read StackOverflow posts on SQL to try and figure this out, and other sources and unable to do this in SQL. Here goes...
I have a table of 3 columns and thousands of rows, with data for first 2 columns. The third column is currently empty and I need to populate the third column based on data already in the first and second columns.
Say I have states in the first column and fruit entries in the second column. I need to write an SQL statement(s) that calculates the number of different states where each fruit comes from, and then inserts this popularity number into the third column for every row. A popularity number of 1 in that row means that fruit only comes from one state, a popularity number of 4 means the fruit comes from 4 states. So my table is currently like:
state fruit popularity
hawaii apple
hawaii apple
hawaii banana
hawaii kiwi
hawaii kiwi
hawaii mango
florida apple
florida apple
florida apple
florida orange
michigan apple
michigan apple
michigan apricot
michigan orange
michigan pear
michigan pear
michigan pear
texas apple
texas banana
texas banana
texas banana
texas grape
And I need to figure out how to calculate and then update the third column, named popularity, which is the number of states that exports that fruit. The goal is to produce (sorry bad pun) the table below, where based on above table, "apple" appears in all 4 states, oranges and banana appear in 2 states, and kiwi, mango, pear, and grape only appear in 1 state, hence their corresponding popularity numbers.
state fruit popularity
hawaii apple 4
hawaii apple 4
hawaii banana 2
hawaii kiwi 1
hawaii kiwi 1
hawaii mango 1
florida apple 4
florida apple 4
florida apple 4
florida orange 2
michigan apple 4
michigan apple 4
michigan apricot 1
michigan orange 2
michigan pear 1
michigan pear 1
michigan pear 1
texas apple 4
texas banana 2
texas banana 2
texas banana 2
texas grape 1
My small programmer brain says to try and figure out a way to loop through the data in some kind of script, but reading up a little on SQL and databases, it seems like you don't write long and slow looping scripts in SQL. I'm not even sure if you can? but instead that there are better/faster ways to do this in SQL.
Anyone know how to, in SQL statement(s), calculate and update the third column for each row, which is here called popularity and corresponds to the number of states that each fruit comes from? Thanks for reading, very grateful for any help.
So far I have tried these SQL statements below, which output but don't quite get me what I need:
--outputs those fruits appearing multiple times in the table
SELECT fruit, COUNT(*)
FROM table
GROUP BY fruit
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC
--outputs those fruits appearing only once in the table
SELECT fruit, COUNT(*)
FROM table
GROUP BY fruit
HAVING COUNT(*) = 1
--outputs list of unique fruits in the table
SELECT COUNT (DISTINCT(fruit))
FROM table
If you want to simply update your table with the priority it would look like:
update my_table x
set popularity = ( select count(distinct state)
from my_table
where fruit = x.fruit )
If you want to select the data then you can use an analytic query:
select state, fruit
, count(distinct state) over ( partition by fruit ) as popularity
from my_table
This provides the number of distinct states, per fruit.
I ran this and got (what I think) is what you want:
WITH t
AS (SELECT 'hawaii' as STATE, 'apple' as fruit FROM dual
UNION ALL
SELECT 'hawaii' as STATE, 'apple' as fruit FROM dual
UNION ALL
SELECT 'hawaii' as STATE, 'banana' as fruit FROM dual
UNION ALL
SELECT 'hawaii' as STATE, 'kiwi' as fruit FROM dual
UNION ALL
SELECT 'hawaii' as STATE, 'kiwi' as fruit FROM dual
UNION ALL
SELECT 'hawaii' as STATE, 'mango' as fruit FROM dual
UNION ALL
SELECT 'florida' as STATE, 'apple' as fruit FROM dual
UNION ALL
SELECT 'florida' as STATE, 'apple' as fruit FROM dual
UNION ALL
SELECT 'florida' as STATE, 'apple' as fruit FROM dual
UNION ALL
SELECT 'florida' as STATE, 'orange' as fruit FROM dual
UNION ALL
SELECT 'michigan' as STATE, 'apple' as fruit FROM dual
UNION ALL
SELECT 'michigan' as STATE, 'apple' as fruit FROM dual
UNION ALL
SELECT 'michigan' as STATE, 'apricot' as fruit FROM dual
UNION ALL
SELECT 'michigan' as STATE, 'orange' as fruit FROM dual
UNION ALL
SELECT 'michigan' as STATE, 'pear' as fruit FROM dual
UNION ALL
SELECT 'michigan' as STATE, 'pear' as fruit FROM dual
UNION ALL
SELECT 'michigan' as STATE, 'pear' as fruit FROM dual
UNION ALL
SELECT 'texas' as STATE, 'apple' as fruit FROM dual
UNION ALL
SELECT 'texas' as STATE, 'banana' as fruit FROM dual
UNION ALL
SELECT 'texas' as STATE, 'banana' as fruit FROM dual
UNION ALL
SELECT 'texas' as STATE, 'banana' as fruit FROM dual
UNION ALL
SELECT 'texas' as STATE, 'grape' as fruit FROM dual)
SELECT state,
fruit,
count(DISTINCT state) OVER (PARTITION BY fruit) AS popularity
FROM t;
Returned
florida apple 4
florida apple 4
florida apple 4
hawaii apple 4
hawaii apple 4
michigan apple 4
michigan apple 4
texas apple 4
michigan apricot 1
hawaii banana 2
texas banana 2
texas banana 2
texas banana 2
texas grape 1
hawaii kiwi 1
hawaii kiwi 1
hawaii mango 1
florida orange 2
michigan orange 2
michigan pear 1
michigan pear 1
Obviously, you'd only need to run:
SELECT state,
fruit,
count(DISTINCT state) OVER (PARTITION BY fruit) AS popularity
FROM table_name;
Hope it helps...
If your table is #fruit...
To count the different states for each fruit
select fruit, COUNT(distinct state) statecount from #fruit group by fruit
and so to update the table with these values
update #fruit
set popularity
= statecount
from
#fruit
inner join
(select fruit, COUNT(distinct state) statecount from #fruit group by fruit) sc
on #fruit.fruit = sc.fruit
This should get you most of the way there. Basically you want to get a count of distinct states that the fruit is in and then use that to join back to the original table.
update table
set count = cnt
from
(
select fruit, count(distinct state) as cnt
from table
group by fruit) cnts
inner join table t
on cnts.fruit = t.fruit
Another option:
SELECT fruit
, COUNT(*)
FROM
(
SELECT state
, fruit
, ROW_NUMBER() OVER (PARTITION BY state, fruit ORDER BY NULL) rn
FROM t
)
WHERE rn = 1
GROUP BY fruit
ORDER BY fruit;
Try this:
select a.*,b.total
from [table] as a
left join
(
SELECT fruit,count(distinct [state]) as total
FROM [table]
group by fruit
) as b
on a.fruit = b.fruit
Note this is SQL Server code, do your own tweaks if necessary.
try this
create table states([state] varchar(10),fruit varchar(10),popularity int)
INSERT INTO states([state],fruit)
VALUES('hawaii','apple'),
('hawaii','apple'),
('hawaii','banana'),
('hawaii','kiwi'),
('hawaii','kiwi'),
('hawaii','mango'),
('florida','apple'),
('florida','apple'),
('florida','apple'),
('florida','orange'),
('michigan','apple'),
('michigan','apple'),
('michigan','apricot'),
('michigan','orange'),
('michigan','pear'),
('michigan','pear'),
('michigan','pear'),
('texas','apple'),
('texas','banana'),
('texas','banana'),
('texas','banana'),
('texas','grape')
update t set t.popularity=a.cnt
from states t inner join
(SELECT fruit,count(distinct [state]) as cnt
FROM states
group by fruit) a
on t.fruit =a.fruit