what is wrong with my query in oracle live sql? - sql

I ran the following code in oracle live SQL but it gives an error. What is the problem?
select * from bricks full join
((select count(*) from bricks) as "counts"
inner join (select count(*) from bricks group by colour) as "colours"
on counts.colour=colours.colour)
on bricks.colour=bricks.colour; --a dummy condition just for connecting tables without a specific column
output:
ORA-00907: missing right parenthesis

The problems are:
AS before a table/sub-query alias is invalid syntax in Oracle. Remove the AS keywords.
The aliases you are using are quoted identifiers which are case-sensitive and you do not use quoted identifiers with the same case when you refer to the aliases. Remove the double quotes.
Neither the counts nor colours sub-query has a colour column in the SELECT clause and you cannot subsequently refer to non-existent columns in the ON clause of the join condition.
You can fix it using:
select *
from bricks
CROSS JOIN (select count(*) AS cnt from bricks) counts
LEFT OUTER JOIN (
select colour, count(*) AS colour_cnt
from bricks
group by colour
) colours
on bricks.colour=colours.colour
Which, for the sample data:
CREATE TABLE bricks (id, colour) AS
SELECT 1, 'red' FROM DUAL UNION ALL
SELECT 2, 'red' FROM DUAL UNION ALL
SELECT 3, 'red' FROM DUAL UNION ALL
SELECT 4, 'green' FROM DUAL UNION ALL
SELECT 5, 'green' FROM DUAL UNION ALL
SELECT 6, 'blue' FROM DUAL;
Outputs:
ID
COLOUR
CNT
COLOUR
COLOUR_CNT
1
red
6
red
3
2
red
6
red
3
3
red
6
red
3
4
green
6
green
2
5
green
6
green
2
6
blue
6
blue
1
However, you probably want to simplify things and use the analytic COUNT() OVER (...) function and eliminate the self-joins:
select b.*,
COUNT(*) OVER () AS cnt,
COUNT(*) OVER (PARTITION BY colour) AS colour_cnt
from bricks b;
Which outputs:
ID
COLOUR
CNT
COLOUR_CNT
6
blue
6
1
5
green
6
2
4
green
6
2
2
red
6
3
1
red
6
3
3
red
6
3
(identical other than not duplicating the colours column)
db<>fiddle here

Related

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

How to pull entries with 'Shared' Foreign Keys from a Single Table

Let's say that I have a table called Color_Size_Rel that looks like this
Color_Size_ID Color Size
1 Blue L
2 Blue M
3 Green L
4 Purple L
5 Pink XL
6 White S
7 Blue L
What would be the query to pull the colors / the number of colors with the same Size? The expected result set is below:
Blue
Green
Purple
I've tried the following to no avail (I'm really stuck and have no idea how this would be done):
select color
from color_size_rel
where size = size;
Thanks in advance.
You can try to use exists subquery to make it.
Query 1:
SELECT DISTINCT t1.color
FROM Color_Size_Rel t1
WHERE exists (
SELECT 1
FROM Color_Size_Rel tt
WHERE t1.Size = tt.Size
HAVING COUNT(*) > 1
)
Results:
| color |
|--------|
| Blue |
| Green |
| Purple |
This should do the trick:
WITH color_size_rel AS (SELECT 1 color_size_id, 'Blue' color, 'L' "SIZE" FROM dual UNION ALL
SELECT 2 color_size_id, 'Blue' color, 'M' "SIZE" FROM dual UNION ALL
SELECT 3 color_size_id, 'Green' color, 'L' "SIZE" FROM dual UNION ALL
SELECT 4 color_size_id, 'Purple' color, 'L' "SIZE" FROM dual UNION ALL
SELECT 5 color_size_id, 'Pink' color, 'XL' "SIZE" FROM dual UNION ALL
SELECT 6 color_size_id, 'White' color, 'S' "SIZE" FROM dual UNION ALL
SELECT 6 color_size_id, 'Orange' color, 'S' "SIZE" FROM dual UNION ALL
SELECT 7 color_size_id, 'Blue' color, 'L' "SIZE" FROM dual)
SELECT "SIZE", color
FROM (SELECT DISTINCT "SIZE",
color,
COUNT(DISTINCT color) OVER (PARTITION BY "SIZE") cnt
FROM color_size_rel)
WHERE cnt > 1
ORDER BY "SIZE", color;
SIZE COLOR
---- ------
L Blue
L Green
L Purple
S Orange
S White
(I added an extra colour in size "S" to demonstrate the output when there are multiple sizes with more than one colour.)
This finds the count of distinct colours per size, and then distincts the result set, so that if there are duplicate colours in each size, only one is reported. Finally, we filter the results to show those sizes which have a count that is greater than 1.
N.B. Please don't use size as a column name - it's a reserved word, hence why I had to use double-quotes every time I referenced it.
Select distinct colour from colour_size_rel where size=size

SELECTING aggregate data using CASE statement issue

I'm trying to create a query to obtain zone data in preparation to moving the column to another table. How our DB is set up is that we have assets and cables. One asset can have many cables but a cable cannot have multiple assets. We're currently trying to move the Zone field from the Cable table (ex. Below) to the Asset table.
A_ID C_ID Zone
--------------------------
1 1 Green
1 2 Green
1 3 Yellow
2 4 Green
2 5 Red
3 6 Yellow
3 7 Yellow
3 8 Yellow
3 9 Red
The way I want it to be set up for the Asset table is if the Asset contains multiple cables with different zones, if one of the zones is Yellow it defaults to Yellow (ex. 3 green cables, 1 yellow cable - Asset_ID has Yellow zone). Next if it doesn't have any Yellows but has at least 1 red, it defaults to Red (ex. 2 green cables, 3 red cables - Asset_ID has Red Zone). Only if it just has Green zones then it defaults to Green.
Using the sample table above these are the results I would expect.
Expected Results
A_ID Zone
-------------
1 Yellow
2 Red
3 Yellow
I'm trying to use CASE statements but I'm having difficulty formulating the query to group the results correctly.
Any help would be greatly appreciated, thank you in advance.
One way to do it using conditional aggregation and a case expression.
select a_id
,case when yellow_count >=1 then 'Yellow'
when yellow_count = 0 and red_count >=1 then 'Red'
when yellow_count = 0 and red_count = 0 and green_count >=1 then 'Green'
end zone
from (select a_id,
count(case when zone = 'Yellow' then 1 end) yellow_count,
count(case when zone = 'Red' then 1 end) red_count
count(case when zone = 'Green' then 1 end) green_count
from cable_table
group by a_id) t
No case or if statement needed. Think in sets. You need to assign a priority join to the priority and select the one with the highest priority first. Like this
WITH Priority AS
(
SELECT * FROM (
VALUES
('Yellow', 1),
('Red', 2),
('Green', 3)
) AS P(Zone,P)
)
SELECT A_ID, Zone
FROM (
SELECT A_ID, Zone
ROW_NUMBER() OVER (PARTITION BY A_ID ORDER BY P.P ASC) AS RN
FROM AssetTable A
LEFT JOIN Priority P ON A.Zone = P.Zone
) SUB
WHERE RN = 1
Not sure if my syntax is right for VALUES in CTE for Oracle. if that gives an error replace with this:
WITH Priority AS
(
SELECT 'Yellow' AS Zone, 1 AS P
UNION ALL
SELECT 'Red' AS Zone, 2 AS P
UNION ALL
SELECT 'Green' AS Zone, 3 AS P
)
Why just don't do a simple:
SELECT A_ID, MAX( Zone )
FROM table
GROUP BY A_ID
if some A_ID has Yellow then max( Zone ) returns Yellow
if some A_ID hasn't Yellow, but has Red then max( Zone ) returns Red<br>
otherwise (noYellownorRed) max( Zone ) returnsGreen`
and example:
with data as (
select 1 a_id, 1 c_id , 'Green' zone from dual union all
select 1 , 2 , 'Green' from dual union all
select 1 , 3, 'Yellow' from dual union all
select 2 , 4 , 'Green' from dual union all
select 2 , 5 , 'Red' from dual union all
select 3 , 6 , 'Yellow' from dual union all
select 3 , 7 , 'Yellow' from dual union all
select 3 , 8 , 'Yellow' from dual union all
select 3 , 9 , 'Red' from dual
)
select a_id, max( zone )
from data
group by a_id
A_ID MAX(ZO
---------- ------
1 Yellow
2 Red
3 Yellow

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;

Select All Right Hand Rows for Each Left Hand Row SQL.. HELP!

I am currently looking for a Select statement which will do this..
|------Apples------|
|--id--|
- 1
- 16
- 23
- 42
|------Oranges------|
|--id--|
- a
- b
- c
*SELECT STATEMENT*
|------Fruit Cocktail------|
|--AppleID--|--OrangeID--|
1 a
1 b
1 c
16 a
16 b
16 c
etc...
So basically for every left hand column select that and every right hand column
Thanks
Daniel
This is simple cross join
SELECT * FROM Apples, Oranges;
or
SELECT * FROM Apples CROSS JOIN Oranges;
SELECT *
FROM Apples
CROSS JOIN
Oranges
or, using implicit join syntax, just that:
SELECT *
FROM Apples, Oranges
Thanks guys!
The Boss Answered it for me heres a simulation:
Select A.Apple,P.Peach From
(
Select 1 As Apple
Union
Select 2 As Apple
Union
Select 3 As Apple
Union
Select 4 As Apple
Union
Select 5 As Apple
Union
Select 6 As Apple
) A
Cross Join
(
Select 'a' As Peach
Union
Select 'b'
Union
Select 'c'
Union
Select 'd'
Union
Select 'e'
) P