Transpose vertical input data to horizontal output in Oracle - sql

I need to transpose rows to columns in Oracle. I've the data in this format:
Apple Orange Mango Banana
15 20 12 67
The required result is:
Fruit Number
Apple 15
Orange 20
Mango 12
Banana 67
I used Union to get this result but this is not the generic one.
SELECT ‘Apple’ AS Fruit, Apple AS Number FROM fruits_tbl UNION
SELECT ‘Orange’, Orange FROM fruits_tbl UNION
SELECT ‘Mango’, Mango FROM fruits_tbl UNION
SELECT ‘Banana’, Banana FROM fruits_tbl;
I want standard procedure to get the output as suggested.
Update: Figured out Pivot is the correct approach!

Since Oracle 11g (tab is your table name):
select * from tab
UNPIVOT (num for fruit in (apple as 'apple', orange as 'orange', mango as 'mango', banana as 'banana'));
Oracle 10g:
with col_names as (
select 'apple' fruit from dual
union all select 'orange' from dual
union all select 'mango' from dual
union all select 'banana' from dual
)
select c.fruit,
case c.fruit
when 'apple' then t.apple
when 'orange' then t.orange
when 'mango' then t.mango
when 'banana' then t.banana
end as num
from tab t
cross join col_names c;

Related

Selecting MAX of a Value from multiple categories from a table

I am looking to get the max weight of Apple, Orange, Mango - there could be any number of fruits. Bold items from the table is what i would like to have my query response.
I know this can be done by partitioning the table for example:
SELECT fruits,max(weight) OVER(PARTITION BY fruits)
FROM fruitstat
GROUP BY fruits;
But this is not getting my expected results. I need the ones which are the max weight fruits in its category.
Fruits
Color
Weight
Apple
red
23
Orange
orange
6
Mango
yellow
13
Apple
red
15
Orange
orange
19
Mango
yellow
16
Apple
red
44
Orange
orange
31
Mango
yellow
12
Apple
red
14
Orange
orange
22
Mango
yellow
11
Just group the MAX(weight) by fruits:
WITH fruit AS
(
SELECT 'Apple' as fruits,'red' as color ,23 as weight FROM dual UNION ALL
SELECT 'Orange','orange',6 FROM dual UNION ALL
SELECT 'Mango','yellow',13 FROM dual UNION ALL
SELECT 'Apple','red',15 FROM dual UNION ALL
SELECT 'Orange','orange',19 FROM dual UNION ALL
SELECT 'Mango','yellow',16 FROM dual UNION ALL
SELECT 'Apple','red',44 FROM dual UNION ALL
SELECT 'Orange','orange',31 FROM dual UNION ALL
SELECT 'Mango','yellow',12 FROM dual UNION ALL
SELECT 'Apple','red',14 FROM dual UNION ALL
SELECT 'Orange','orange',22 FROM dual UNION ALL
SELECT 'Mango','yellow',11 FROM dual
)
SELECT fruits, MAX(weight)
FROM fruit
GROUP BY fruits;
P.S. MAX for the apple is 44, not 23, at least in your sample data
You don't need to use group by on window functions. You can do this, instead.
First, sort the fruits weight by using rank.
select rank() over (partition by fruits order by weight) as rank, fruits, weight
from fruitstat
After that, you can use subquery to return the first value only.
select fruits, weight
from (select rank() over (partition by fruits order by weight) as rank, fruits, weight from fruitstat) a
where rank = 1

Transfer to data in right place in Oracle

I have a table like below. My aim is to count apple and mango under fruit.
I want to do this using case when statement. I run this query but it didn't work.
This works:
CASE
WHEN Food_type = 'vegetables'
AND Names IN ('apple', 'mango')
THEN 1
ELSE 0
END IN (0)
CASE
WHEN Names IN ('apple', 'orange', 'mango')
THEN 'fruit'
END Food_type2
Output:
Names
Food_type
apple
vegetables
eggplant
vegetables
carrot
vegetables
orange
fruit
onion
vegetables
spinach
vegetables
mango
vegetables
How can I do this ? Thank you.
This? Sample data till line #9; query begins at line #10.
SQL> with test (names, food_type) as
2 (select 'apple' , 'vegetables' from dual union all
3 select 'eggplant', 'vegetables' from dual union all
4 select 'carrot' , 'vegetables' from dual union all
5 select 'orange' , 'fruit' from dual union all
6 select 'onion' , 'vegetables' from dual union all
7 select 'spinach' , 'vegetables' from dual union all
8 select 'mango' , 'vegetables' from dual
9 )
10 select case when names in ('apple', 'mango') or food_type = 'fruit' then 'fruit'
11 else 'vegetables'
12 end food_type,
13 count(*)
14 from test
15 group by
16 case when names in ('apple', 'mango') or food_type = 'fruit' then 'fruit'
17 else 'vegetables'
18 end;
FOOD_TYPE COUNT(*)
---------- ----------
vegetables 4
fruit 3
SQL>

Count the number of times word appears in a single column

I'm attempting to count the number of times apples and oranges appear in my fruit column.
The table looks like this:
Fruit
-------
Apples
Apples Oranges
Apples Oranges
Apples
Oranges
Expected output:
Apples 4
Oranges 3
My code thus far. I'm not sure how to do it when both appear and how to add them to the totals. I'm sure there is an easier way that this.
SELECT
COUNT (CASE WHEN Fruit LIKE '%Apples%' THEN '1' END) AS Apples
COUNT (CASE WHEN Fruit LIKE '%Oranges%' THEN '1' END) AS Oranges
FROM Fruits
Cheers
If those fruits are single-worded and separated by a space, then such a generic approach might be interesting for you.
Lines #1 - 8 represent sample data; you already have that so you don't type it. Code you might need starts at line #10.
SQL> with fruit (fruit) as
2 -- sample data; you have that in a table
3 (select 'Apples' from dual union all
4 select 'Apples Oranges' from dual union all
5 select 'Apples Oranges' from dual union all
6 select 'Apples Lemon' from dual union all
7 select 'Oranges Plums' from dual
8 ),
9 -- split fruits to rows
10 temp as
11 (select regexp_substr(fruit, '[^ ]+', 1, column_value) fruit
12 from fruit cross join
13 table(cast(multiset(select level from dual
14 connect by level <= regexp_count(fruit, ' ') + 1
15 ) as sys.odcinumberlist))
16 )
17 select fruit, count(*)
18 from temp
19 group by fruit
20 order by fruit;
FRUIT COUNT(*)
-------------------------------------------------------- ----------
Apples 4
Lemon 1
Oranges 3
Plums 1
SQL>
Either with sum or count, it works
Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
SQL> with t as
(
select 'Apples' as fruits from dual union all
select 'Apples Oranges' as fruits from dual union all
select 'Apples Oranges' as fruits from dual union all
select 'Apples' as fruits from dual union all
select 'Oranges' as fruits 6 from dual
) select
SUM (CASE WHEN fruits LIKE '%Apples%' THEN '1' END) AS Apples ,
SUM (CASE WHEN fruits LIKE '%Oranges%' THEN '1' END) AS Oranges
FROM t
;
APPLES ORANGES
---------- ----------
4 3
SQL> with t as
(
select 'Apples' as fruits from dual union all
select 'Apples Oranges' as fruits from dual union all
select 'Apples Oranges' as fruits from dual union all
select 'Apples' as fruits from dual union all
select 'Oranges' as fruits from dual
) select
COUNT (CASE WHEN fruits LIKE '%Apples%' THEN '1' END) AS Apples ,
COUNT (CASE WHEN fruits LIKE '%Oranges%' THEN '1' END) AS Oranges
FROM t ;
APPLES ORANGES
---------- ----------
4 3
SQL>

How to return distinct rows meeting condition

I have an example table in the format below with sample data:
=cust_table
Customer: Liked_Color:
Adam Blue
Adam Green
Adam Yellow
Adam Red
Bob Yellow
Bob Yellow
Bob Yellow
Bob Yellow
Charlie Red
Charlie Red
Charlie Red
Charlie Red
How can I select distinct customers and only return them if they DO NOT like the color Blue?
So, the returned results would be:
Customer: Bob, Charlie
If I do:
SELECT DISTINCT Customer
FROM cust_table
WHERE Liked_Color NOT LIKE Blue
I get: Adam, Bob, Charlie
How would I make sure the Customer is only returned when Blue is not a Liked_Color for a Customer?
I would use aggregation:
select customer
from cust_table
group by customer
having sum(case when color = 'Blue' then 1 else 0 end) = 0;
However, a customer table should have one row per customer (at least per unit time). If you had such a table and a customer_colors table, then I would use not exists:
select c.*
from customers c
where not exists (select 1
from customer_colors cc
where cc.customer = c.customer and cc.color = 'Blue'
);
This would also return customers with no preferred color at all, which you cannot do with your single table.
Alternatively, see whether sets do any good:
SQL> with cust (customer, liked_color) as
2 (select 'Adam' , 'Blue' from dual union all
3 select 'Adam' , 'Green' from dual union all
4 select 'Bob' , 'Yellow' from dual union all
5 select 'Bob' , 'Red' from dual union all
6 select 'Charlie', 'Red' from dual union all
7 select 'Charlie', 'Red' from dual
8 )
9 select customer from cust where liked_color <> 'Blue'
10 minus
11 select customer from cust where liked_color = 'Blue';
CUSTOME
-------
Bob
Charlie
SQL>
this will work the simplest of them all :
select distinct a from Table1 where a not in
(select distinct a from Table1 where b like 'Blue');
check fiddle:http://sqlfiddle.com/#!9/7034f/10

Oracle - update , decode and set value

I have a table e.g.
**Fruit Number**
Apple 5
Grape 9
Orange 1
Coconut 54
Mango 22
I want to :
Select the whole list
Put 'Apple, Mango,Coconut' at top of the list.
Update the current order, where number = rownum
The list should look as follows :
**Fruit Number**
Apple 1
Mango 2
Coconut 3
Grape 4
Orange 5
I tried the following however getting syntax issues ..
update tablename
set id = rownum
where fruit in (select fruit from table order by decode(fruit,'Apple',1,'Mango',2,'Coconut',3))
UPDATE (
SELECT ROWNUM+5 AS r, fruit, number FROM TABLE
WHERE fruit NOT IN ('Apple', 'Mango', 'Coconut', 'Grape', 'Orange')
UNION
SELECT 1 AS r, 'Apple' AS fruit, number FROM TABLE
UNION
SELECT 2 AS r, 'Mango' AS fruit, number FROM TABLE
UNION
SELECT 3 AS r, 'Coconut' AS fruit, number FROM TABLE
UNION
SELECT 4 AS r, 'Grape' AS fruit, number FROM TABLE
UNION
SELECT 5 AS r, 'Orange' AS fruit, number FROM TABLE
)
SET number = r;
Following query will do that for you.
UPDATE table SET number =
CASE fruit
WHEN 'Apple' THEN 1
WHEN 'Mango' THEN 2
WHEN 'Coconut' THEN 3
WHEN 'Grape' THEN 4
WHEN 'Orange' THEN 5
END;