ORA-00907: missing right parenthesis in Select query - sql

This is the table
City
Def
Abc
Ijkl
Mnop
And
I want the output, where the smallest city name is returned, who have same number of characters.
OUTPUT
Abc 3
Ijkl 4
Notice that there were 2 cities with same number of characters Abc and Def, and only Abc will be returned.
The Oracle SQL query which i am trying to run is -
Select a.city,a.leng from
(
Select city,length(city) as leng from station
order by 2,1
) as a where a.leng in (
Select distinct(length(city)) from station
order by 1);
I hope there will be numerous ways to solve but i want to correct my approach.

A simple group by should give you the desired result
Query
WITH
station (city)
AS
(SELECT 'Def' FROM DUAL
UNION ALL
SELECT 'Abc' FROM DUAL
UNION ALL
SELECT 'Ijkl' FROM DUAL
UNION ALL
SELECT 'Mnop' FROM DUAL)
SELECT MIN (city) as city, LENGTH (city) as leng
FROM station
GROUP BY LENGTH (city)
order by leng;
Result
CITY LENG
_______ _______
Abc 3
Ijkl 4

There is no reason to over complicate this with subqueries.
This should give you the desired result
Select MIN(City), LENGTH(City)
From station
Group By LENGTH(City)

Related

Get highest value ID

I need to print the Region ID and the count of countries he holds, but only for the highest one.
My table is like this:
COUNTRY_ID COUNTRY_NAME REGION_ID
AR Argentina 2
AU Belgium 3
BE Brazil 1
BR Canada 2
CA Switzerland 2
CN China 1
DE Germany 3
And the result must be something like:
REGION_ID Quantity
2 3
You can use below sql for that purpose.
I use row_number analytic function to rank the rows after being grouped by REGION_ID column. Then, I filter by rnb = 1 to get the row with maximun quantity.
select REGION_ID, QUANTITY
from (
select t.REGION_ID, count(*)quantity, row_number()over(order by count(*) desc) rnb
from YourTable t
group by t.REGION_ID
)
where rnb = 1
demo
From Oracle 12c, you can use:
SELECT region_id,
COUNT(*) AS quantity
FROM table_name
GROUP BY region_id
ORDER BY quantity DESC
FETCH FIRST ROW ONLY;
Before that:
SELECT *
FROM (
SELECT REGION_ID,
COUNT(*) AS quantity
FROM table_name
GROUP BY region_id
ORDER BY quantity DESC
)
WHERE ROWNUM = 1;
Which, for your sample data:
CREATE TABLE table_name (COUNTRY_ID, COUNTRY_NAME, REGION_ID) AS
SELECT 'AR', 'Argentina', 2 FROM DUAL UNION ALL
SELECT 'AU', 'Belgium', 3 FROM DUAL UNION ALL
SELECT 'BE', 'Brazil', 1 FROM DUAL UNION ALL
SELECT 'BR', 'Canada', 2 FROM DUAL UNION ALL
SELECT 'CA', 'Switzerland', 2 FROM DUAL UNION ALL
SELECT 'CN', 'China', 1 FROM DUAL UNION ALL
SELECT 'DE', 'Germany', 3 FROM DUAL;
Both output:
REGION_ID
QUANTITY
2
3
db<>fiddle here
In Oracle you may nest aggregate functions to calculate total on group by result. So you may use last aggregate function to get highest id:
select
max(region_id) keep(
dense_rank last
/*
region_id for highest count(*)
calculated per region_id
*/
order by count(*) asc
) as region_id,
max(count(*)) as quantity
from table_name
group by region_id
REGION_ID | QUANTITY
--------: | -------:
2 | 3
db<>fiddle here

Hackerrank SQL problem to solve in Oracle's SQL version

Query the two cities in STATION with the shortest and longest CITY names, as well as their respective lengths (i.e.: number of characters in the name). If there is more than one smallest or largest city, choose the one that comes first when ordered alphabetically.
The STATION table is described as follows:
Sample Input
For example, CITY has four entries: DEF, ABC, PQRS and WXY.
Sample Output
ABC 3
PQRS 4
Explanation
When ordered alphabetically, the CITY names are listed as ABC, DEF, PQRS, and WXY, with lengths and . The longest name is PQRS, but there are options for shortest named city. Choose ABC, because it comes first alphabetically.
A little bit of analytic functions; sample data in lines #1 - 6; query begins at line #7.
SQL> with station (city) as
2 (select 'DEF' from dual union all
3 select 'ABC' from dual union all
4 select 'PQRS' from dual union all
5 select 'WXY' from dual
6 )
7 select city, len
8 from (select city,
9 length(city) len,
10 rank() over (partition by length(city) order by city) rn
11 from station
12 )
13 where rn = 1
14 order by city;
CITY LEN
---- ----------
ABC 3
PQRS 4
SQL>
Reading your comment, it seems you want something like this:
SQL> with station (city) as
2 (select 'DEF' from dual union all
3 select 'ABC' from dual union all
4 select 'PQRS' from dual union all
5 select 'WXY' from dual union all
6 select 'XX' from dual union all
7 select 'ABCDE' from dual
8 )
9 select city, len
10 from (select city,
11 length(city) len,
12 rank() over (order by length(city) , city) rna,
13 rank() over (order by length(city) desc, city) rnd
14 from station
15 )
16 where rna = 1
17 or rnd = 1
18 order by len, city;
CITY LEN
----- ----------
XX 2
ABCDE 5
SQL>
Try this SQL statement with the fetch first row only clause:
with station (city) as
(select 'DEF' from dual union all
select 'ABC' from dual union all
select 'PQRS' from dual union all
select 'WXY' from dual)
(select city,
length(city)
from station
order by 2, 1
fetch first row only)
union
(select city,
length(city)
from station
order by 2 desc, 1
fetch first row only);
I solved the question this way:
select min(tt.city), tt.city_length
from (select s.city, length(s.city) city_length
from station s
where length(s.city) = (select max(length(t.city)) from station t)
or length(s.city) = (select min(length(p.city)) from station p)
order by 2, 1) tt
group by tt.city_length;
You can use the ROW_NUMBER analytic function in the ORDER BY clause and then FETCH FIRST ROW WITH TIES:
SELECT city,
LENGTH(city) AS length
FROM station
ORDER BY
LEAST(
ROW_NUMBER() OVER ( ORDER BY LENGTH( city ) ASC, city ),
ROW_NUMBER() OVER ( ORDER BY LENGTH( city ) DESC, city )
)
FETCH FIRST ROW WITH TIES;
Which, for the sample data:
CREATE TABLE station ( city ) AS
SELECT 'ABC' FROM DUAL UNION ALL
SELECT 'DEF' FROM DUAL UNION ALL
SELECT 'PQRS' FROM DUAL UNION ALL
SELECT 'XYZ' FROM DUAL;
Outputs:
CITY | LENGTH
:--- | -----:
PQRS | 4
ABC | 3
db<>fiddle here
select min(city) || ' ' ||length(min(city)) from station
UNION
select max(city) || ' ' ||length(max(city)) from station;

How can I select unique and duplicated rows exlude with different values

How can I fetch this table as expected in Oracle. I'm try to do this like below select but its not give me the right result. What I expect is fetch only the unique ones and exclude if these is a record like different values. Sorry for if asked before but I couldn't find it.
SELECT *
FROM ...
WHERE number IN ( SELECT name
FROM (SELECT *
FROM table
WHERE number IN ('Mel','Jose','Kim')
) ds
GROUP BY number
HAVING COUNT (*) = 1)
Current result:
number name
aaa Mel
asd Jose
fsa Jose
xdf Jose
zzz Kim
zzz Kim
Expected result:
aaa Mel
zzz Kim
You're close - I think you were just missing the distinct in the count in your having clause.
E.g.:
WITH your_table AS (SELECT 100 nmbr, 'Mel' NAME FROM dual UNION ALL
SELECT 112 nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 212 nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 313 nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 101 nmbr, 'Kim' NAME FROM dual UNION ALL
SELECT 101 nmbr, 'Kim' NAME FROM dual)
-- end of mimicking data in your table
-- you already have this table, so you would just need the below sql:
SELECT min(nmbr) nmbr,
NAME
FROM your_table
GROUP BY NAME
HAVING COUNT(DISTINCT nmbr) = 1;
NMBR NAME
---------- ----
101 Kim
100 Mel
Just to prove that it doesn't matter whether the nmbr column is of NUMBER or VARCHAR2 datatype:
WITH your_table AS (SELECT 'aaa' nmbr, 'Mel' NAME FROM dual UNION ALL
SELECT 'asd' nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 'fsa' nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 'xfd' nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 'zzz' nmbr, 'Kim' NAME FROM dual UNION ALL
SELECT 'zzz' nmbr, 'Kim' NAME FROM dual)
-- end of mimicking data in your table
-- you already have this table, so you would just need the below sql:
SELECT min(nmbr) nmbr,
NAME
FROM your_table
GROUP BY NAME
HAVING COUNT(DISTINCT nmbr) = 1;
NMBR NAME
---- ----
zzz Kim
aaa Mel
You can do by nested sql with the inner part eliminate repeating ones with respect to id & name, and in the outer part eliminate repeating ones with only name like in the following statement :
SELECT MAX(id),name
FROM (SELECT id,name FROM mytable GROUP BY id, name)
GROUP BY name
HAVING COUNT(1) = 1
ORDER BY MAX(id);
OUTPUT:
ID NAME
----- ------
100 Mel
101 Kim
D e m o 1
exactly the same sql works for your second case :
D e m o 2

Oracle query for grouping

I have a requirement for fetching records from a group which met some condition.Please find my input set of records below
ID FIRSTNAME SURNAME
123 E Mcilwham
123 Emma Mcilwham
123 Enda Mcilwham
321 Lion Mark
321 Lous Mark
342 L Isaac
342 L Isaac
455 Lewis hoting
455 L hoting
325 D Mark
In this record I need to do a group by based on ID and Surname.I need output in such a way that, for the same ID there should be at least one record whose length is 1 and for the same ID there should be other records whose length is greater that 1 and those record should start with the same letter as of the record whose length is 1.
In the above example ID:- 123,455 will cover the above said scenario.
Also I am not expecting any record in output where there is only record for that ID.(ID:- 325).
With the case of ID 342, this shouldn't come in the output as there are no records for this ID whose length is greater than 1.
Hope this is clear to every one. Please feel free to ask me if require more clarifications on this
Please find the query which I have used below, which is not giving me proper result as expected.
SELECT
C.ID,
C.FIRST_NAME,
C.SURNAME
FROM TABLE1 C
WHERE C.ID IN
(SELECT DISTINCT A.ID
FROM TABLE1 A ,
TABLE1 B
WHERE A.ID = B.ID
AND LENGTH(TRIM(A.FIRST_NAME)) <> LENGTH(TRIM(B.FIRST_NAME))
-- AND LENGTH(TRIM(B.FIRST_NAME)) <> LENGTH(TRIM(A.FIRST_NAME))
AND LENGTH(TRIM(A.FIRST_NAME)) = 1 OR LENGTH(TRIM(B.FIRST_NAME)) = 1
AND SUBSTR(TRIM(A.FIRST_NAME),1,1) = SUBSTR(TRIM(B.FIRST_NAME),1,1)
--AND SUBSTR(TRIM(B.FIRST_NAME),1,1) = SUBSTR(TRIM(A.FIRST_NAME),1,1)
AND TRIM(A.SURNAME) = TRIM(B.SURNAME)
)
ORDER BY 1
Use conditional aggregation over ID and surname:
select
id,
firstname,
surname
from
(
select
id,
firstname,
surname,
min(length(firstname)) over (partition by id, surname) as min_length,
max(length(firstname)) over (partition by id, surname) as max_length,
count(distinct substr(firstname, 1, 1))
over (partition by id, surname) as count_distinct_initials
from table1
)
where min_length = 1
and max_length > 1
and count_distinct_initials = 1
order by id, surname, firstname;
The following query satisfies all requirements that you specified for your specific data set. Depending on the actual data that you have to work with, you may need to be more specific.
with sample_data as(
select 123 as id, 'E' as firstname, 'Mcilwham' as surname from dual union all
select 123 as id, 'Emma' as firstname, 'Mcilwham' as surname from dual union all
select 123 as id, 'Enda' as firstname, 'Mcilwham' as surname from dual union all
select 321 as id, 'Lion' as firstname, 'Mark' as surname from dual union all
select 321 as id, 'Lous' as firstname, 'Mark' as surname from dual union all
select 342 as id, 'L' as firstname, 'Isaac' as surname from dual union all
select 342 as id, 'L' as firstname, 'Isaac' as surname from dual union all
select 455 as id, 'Lewis' as firstname, 'hoting' as surname from dual union all
select 455 as id, 'L' as firstname, 'hoting' as surname from dual union all
select 325 as id, 'D' as firstname, 'Mark' as surname from dual
)
select id
,surname
,listagg(firstname, ',') within group (order by firstname) as firstnames
,count(*) as nof_firstnames
from sample_data a
group
by id
,surname
having count(*) > 1 -- at least one record
and min(length(firstname)) = 1 -- at least one record has length = 1
and max(length(firstname)) > 1 -- at least one record has a length greater than 1
In this record I need to do a group by based on ID and Surname.I need
output in such a way that, for the same ID there should be at least
one record whose length is 1 and for the same ID there should be other
records whose length is greater that 1 and those record should start
with the same letter as of the record whose length is 1.
What would happen when there are multiple records for length = 1 and length > 1?For example Alexander does not start with 'R'. Bengt does not start with 'A' but there is a record 'B'. Cedric starts with 'C' but it doesn't match the 'A' record.
ID FIRSTNAME SURNAME
1 R Bahlsten
1 Ronnie Bahlsten
1 Alexander Bahlsten
2 A Andersson
2 Anna Andersson
2 B Andersson
2 Bengt Andersson
3 C Diggory
3 A Diggory
3 Cedric Diggory

SQL find nearest number

Say I have a table like the following (I'm on Oracle 10g btw)
NAME VALUE
------ ------
BOB 1
BOB 2
BOB 4
SUZY 1
SUZY 2
SUZY 3
How can I select all rows where value is closest to, but not greater than, a given number. For example if I want to find all the rows where value is closest to 3 I would get:
NAME VALUE
------ ------
BOB 2
SUZY 3
This seems like it should be simple... but I'm having no luck.
Thanks!
SELECT name, max(value)
FROM tbl
WHERE value <= 3
GROUP BY name
This works (SQLFiddle demo):
SELECT name, max(value)
FROM mytable
WHERE value <= 3
GROUP BY name
Based on hagensofts answer:
SELECT name, max(value)
FROM tbl
WHERE value <= 3 AND ROWNUM <=2
GROUP BY name
With ROWNUM you can limit the output rows, so if you want 2 row, then you can limit the rownum.
WITH v AS (
SELECT 'BOB' NAME, 1 value FROM dual
UNION ALL
SELECT 'BOB', 2 FROM dual
UNION ALL
SELECT 'BOB', 4 FROM dual
UNION ALL
SELECT 'SUZY', 1 FROM dual
UNION ALL
SELECT 'SUZY', 2 FROM dual
UNION ALL
SELECT 'SUZY', 3 FROM dual
)
SELECT *
FROM v
WHERE (name, value) IN (SELECT name, MAX(value)
FROM v
WHERE value <= :num
GROUP BY name)
;