I have a table that contain the following:
Fruit_id Fruit1 Fruit2
-------------------------------------
1 Apple Orange
2 Orange Orange
3 Orange Orange
4 Banana Banana
5 Apple Orange
I would like to count the total number for each fruit so that the output is something like
Fruit Frequency
---------------------------
Apple 2
Banana 2
Orange 6
I have tried
select distinct Fruit1, count(Fruit1 Fruit2) from Fruits group by Fruit1 order by count(Fruit1 Fruit2);
I also tried:
select distinct Fruit1, count(Fruit1 || Fruit2) from Fruits group by Fruit1 order by count(Fruit1 Fruit2);
I'm new to oracle sql so please understand my ignorance
You could get the count for each distinct fruit value in the Fruit1 and Fruit2 columns, and then add those together with a SUM aggregate.
The "trick" is to use an inline view that concatenates the two results together with a UNION ALL set operator.
SELECT f.fruit, SUM(f.cnt) AS cnt
FROM ( SELECT d.Fruit1 AS fruit, COUNT(1) AS cnt FROM Fruits d GROUP BY d.Fruit1
UNION ALL
SELECT e.Fruit2 AS fruit, COUNT(1) AS cnt FROM Fruits e GROUP BY e.Fruit2
) f
GROUP BY f.fruit
ORDER BY f.fruit
You could use the following:
select fruits, count(*) as freq
from (select fruit1 as fruits
from tbl
union all
select fruit2 as fruits
from tbl)
group by fruits
Related
I have the following table for 4 individuals with their favorite fruit:
tbl:
ID FRUIT
personA banana
personB apple
personC orange
personD grapefruit
personA avocado
personB banana
personC melon
personD pear
personA banana
I would like to extract all the entries for the IDs that are associated with only one of the following: banana, apple, orange.
This means that I am only hoping to extract the rows for person A and person C. person B has both ("apple" AND "banana"). person D has none of the three desired fruits.
I currently have:
select *
from tbl t1
where exists (select 1
from tbl t2
where t1.ID=t2.ID and
(t2.fruit='banana' or
t2.fruit='apple' or
t2.fruit='orange'))
join (select ID, count(*) over (partition by t3.fruit)
from (select distinct ID, fruit
from tbl
where fruit='banana' or
fruit='apple' or
fruit='orange')) t3
on t3.ID=t.ID and
t3.cnt=1
Is there a better/simpler way to execute this? I would like to optimize it to reduce run time given the tables are quite large.
desired table:
ID FRUIT
personA banana
personC orange
personA avocado
personC melon
personA banana
The subquery determines all IDs which have those three fruits and count how many individual fruits they have.
You know can join the ID to the table and only take those IDs which have only 1 fruit, if you also want three fruits you and add this in the join condition
SELECT
t1.ID, FRUIT
FROM
tbl t1
JOIN
(SELECT
ID, COUNT(DISTINCT FRUIT) countf
FROM
tbl
WHERE
FRUIT IN ('banana', 'apple', 'orange')
GROUP BY 1) t2 ON t1.ID = t2.ID AND t2.countf = 1;
We can use GROUP BY and HAVING COUNT(DISTINCT) to find the persons we want.
SELECT
a.ID,
b.FRUITID
FROM tb1 a
JOIN tb1 b ON a.ID = b.ID
WHERE a.FRUITID IN ('banana', 'apple', 'orange')
GROUP BY
a.ID,
b.FRUITID
HAVING COUNT(DISTINCT a.FRUITID) = 1;
GO
ID | FRUITID
:------ | :------
personA | avocado
personA | banana
personC | melon
personC | orange
db<>fiddle here
Alternative approach is to use COUNT_IF:
SELECT *
FROM tbl t
QUALIFY COUNT_IF(t.fruit = 'banana') OVER(PARTITION BY ID) = 1
AND COUNT_IF(t.fruit = 'apple') OVER(PARTITION BY ID) = 1
AND COUNT_IF(t.fruit = 'orange') OVER(PARTITION BY ID) = 1;
Answer:
This can be done with:
select *
from data
qualify count( distinct iff(fruit in ('apple','banana','orange'), fruit, null))
over(partition by id) = 1
which gives:
ID
FRUIT
personA
avocado
personA
banana
personA
banana
personC
melon
personC
orange
How that works:
this can be shown how it works by showing the intermediate state of the IFF and the COUNT DISTINCT like so:
select *
,iff(fruit in ('apple','banana','orange'), fruit, null) as v
,count( distinct v) over(partition by id) as c
from data
gives:
ID
FRUIT
V
C
personA
avocado
1
personA
banana
banana
1
personA
banana
banana
1
personB
apple
apple
2
personB
banana
banana
2
personC
melon
1
personC
orange
orange
1
personD
grapefruit
0
personD
pear
0
Thus personD is eliminated for have no magic fruit, and personB is eliminated for have too much.
If you are deeply caring about performance (which I would test) I assume nbk's solution would perform the fastest.
I have table 1 like this:
id
Country
1
Germany
1
USA
1
Japan
2
France
Table 2 like this
id
Color
1
Green
2
Red
2
Yellow
Is it possible to get result like this using SQL statement?:
id
Country
Color
1
Germany
Green
1
USA
1
Japan
2
France
Red
2
Yellow
It means that, if id 1 has 3 countries and 1 color --> The result should return only 3 countries and 1 color in any order (and color can be in the same row with any country). Generally, if id 1 has m countries and n color --> The result should return only m countries and n colors ?
Thank you very much <3
Note: I'm using Oracle Database
You can number your countries and colors per ID and then use a full outer join on the ID and that number:
with cntr as
(
select id, row_number() over (partition by id order by country) as subid, country
from country
)
, clr as
(
select id, row_number() over (partition by id order by color) as subid, color
from color
)
select id, cntr.country, clr.color
from cntr full outer join clr using (id, subid)
order by id, subid nulls last;
Demo: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=e74ece8cb4571d7998014f8c55bd8d7a
with src as (
select n.id,n.country,l.color,
(select count(id)-1
from countries where id=n.id) total_countries
,(
select count(id)-1
from colors where id=l.id
) total_colors
from countries n
inner join colors l
on n.id = l.id
)
select
id,
country,
lag(color, total_countries) over (partition by id order by color) color
from
src
where total_countries > 0
union all
select
id,
lag(country, total_colors) over (partition by id order by country) country
,color
from
src
where total_colors > 0
order by id, country nulls last, color nulls last
fiddle
I have a Table as follows
IDNumber
Name
123
Apple
123
Mango
123
Banana
126
Apple
126
Mango
126
Orange
128
Apple
128
Mango
128
Banana
151
Apple
151
Mango
151
Banana
I have used the partition by clause to partition the group based on ID Number.
with part as (Select IDNumber,count(IDNumber) over(Partition by IDNumber) cnt from myTable)
Select IDNumber from myTable where do not exists ???"Orange in partitionGroup"????
Problem:I am not really sure how this can be achieved.For a given ID, i would need a partition group to NOT select if a given value is present.
This gives me a partition where every group has three Names, But i do not want the IDNumber to be sselected if it has Orange as Name.
Please let me know in case any other details are required. Any help is highly appreciated.
You may use aggregation here:
SELECT IDNumber
FROM yourTable
GROUP BY IDNumber
HAVING COUNT(CASE WHEN Name = 'Orange' THEN 1 END) = 0;
Another way:
SELECT IDNumber
FROM yourTable
WHERE IDNumber NOT IN (
SELECT IDNumber FROM yourTable WHERE Name = 'Orange'
);
But i do not want the IDNumber to be selected if it has Orange as Name.
You can use not exists for this:
select t.*
from myTable t
where not exists (select 1
from myTable t2
where t2.id = t.id and t2.name = 'Orange'
);
You can also phrase this using window functions, but that seems unnecessary.
How to delete duplicate rows based on select columns without leaving original? In this example, deleting based on Name and Animal.
ID Name Animal Fruit
1 Bob Dog Orange
2 Adam Dog Orange
3 Bob Dog Apple
4 Adam Cat Orange
5 Bob Cat Apple
6 Bob Hamster Apple
7 Adam Cat Apple
So the expected result would be:
ID Name Animal Fruit
2 Adam Dog Orange
5 Bob Cat Apple
6 Bob Hamster Apple
You can use a delete with join the subquery grouped by name and animal having count > 1
delete m
from my_table m
inner join (
select name, animal
from my_table
group by name, animal
having count(*) > 1
) t on t.name = m.name
and t.animal = m.animal
try this:
first, select the duplicates in a subquery.
then, delete all results
delete from mytable T
left join
(select count(*) cnt, Name, Animal
from mytable
group by Name, Animal) X
on t.Name = X.Name
and t.Animal = X.Animal
where cnt>1
I would do this using exists:
delete from t
where exists (select 1
from t t2
where t2.name = t.name and t2.animal = t.animal and t2.id <> t.id
);
Can someone help me out with how I can find the 'Fruit' that no-one loves?
Fruit LoveIt Name
Apple Y John
Apple N Mary
Apple Y Stephen
Pear N Lois
Pear N Jo
Pear N Fiona
Thanks,
Here's a variant that doesn't rely on counting but stresses thinking in sets (relational algebra style, if you will): the fruits no one loves are all fruits but those that are loved by somebody:
SELECT DISTINCT f.Fruit
FROM fruits f
EXCEPT
SELECT f.Fruit
FROM fruits f
WHERE f.LoveIt = 'Y'
EXCEPT is SQL's set difference operator.
Using aggregation:
select fruit
from fruits
group by fruit
having count(case when LoveIt = 'Y' then 1 end) = 0;
I would try this:
select fruit, loveit, count(*)
from survey
group by 1,2
having loveit = 'N'
and count(*) = 0;
Select distinct fruit from tab x where fruit not in (select fruit from tab where love it = 'Y')