Oracle SQL displaying data from multiple records - sql

Sorry if I am not explaining this properly, I am relatively new to SQL.
In oracle have a table describing properties (city, property type, cost of rent per month, other information)
My question is: assuming 3 unique property types (hotel, house, empty lot), how can I show which cities do not have all 3 types of properties?

GROUP BY solution, make sure there are less than 3 different property types for each city returned:
select city
from tablename
where property_type in ('hotel', 'house', 'empty lot')
group by city
having count(distinct property_type) < 3

Your SQL query should be
SELECT City
FROM YourTable
WHERE hotel <> 'hotelname' and house <> 'housename' and emptylot <> 'name'
assuming
Hotel, House, Emptylot is column name in your database.

There are two ways,
GROUP BY
Analytic COUNT() OVER()
For example, Let's say I have sample data of 3 cities, where city 1 has all the property types satisfied, rest other cities are not having all the required property types.
Using GROUP BY
SQL> -- sample table data
SQL> WITH DATA AS(
2 SELECT 1 city, 'hotel' property FROM dual UNION ALL
3 SELECT 1 city, 'house' property FROM dual UNION ALL
4 SELECT 1 city, 'empty' property FROM dual UNION ALL
5 SELECT 2 city, 'hotel' property FROM dual UNION ALL
6 SELECT 2 city, 'house' property FROM dual UNION ALL
7 SELECT 2 city, 'scrap' property FROM dual UNION ALL
8 SELECT 3 city, 'empty' property FROM dual UNION ALL
9 select 3 city, 'house' property from dual
10 )
11 -- query
12 SELECT city
13 FROM data
14 WHERE property IN ('hotel', 'house', 'empty')
15 GROUP BY city
16 HAVING COUNT(property) < 3
17 /
CITY
----------
2
3
SQL>
Using Analytic COUNT() OVER()
SQL> -- sample table data
SQL> WITH DATA AS(
2 SELECT 1 city, 'hotel' property FROM dual UNION ALL
3 SELECT 1 city, 'house' property FROM dual UNION ALL
4 SELECT 1 city, 'empty' property FROM dual UNION ALL
5 SELECT 2 city, 'hotel' property FROM dual UNION ALL
6 SELECT 2 city, 'house' property FROM dual UNION ALL
7 SELECT 2 city, 'scrap' property FROM dual UNION ALL
8 SELECT 3 city, 'empty' property FROM dual UNION ALL
9 select 3 city, 'house' property from dual
10 )
11 -- query
12 SELECT DISTINCT city
13 FROM
14 (SELECT t.* ,
15 COUNT(property) OVER(PARTITION BY city ORDER BY city) rn
16 FROM DATA t
17 WHERE property IN ('hotel', 'house', 'empty')
18 )
19 WHERE rn < 3
20 /
CITY
----------
2
3
SQL>

Could be something like this:
SELECT City
FROM YourTable
WHERE [property type] != 'hotel' OR
[property type] != 'empty lot' OR
[property type] != 'house'

(Edited)Try this query :
select t.city from table_name t
where t.city NOT IN
(select city from table_name
where ( property_type ='hotel' or
property_type ='house' or
property_type ='Empty lot')
);
(Query returning cities where all three types of property are not present):
select t.city from table t inner join
(select city from table
where property_type not in ('House','Hotel','Empty lot')) x
on t.city=x.city
group by t.city
having count(*)<3 ;

Related

I want to count city column's values which are repeated

id city
1 London
2 Rome
3 London
4 Rome
Expected output like this:
London Rome
2 2
Using case expression...
How can I solve this query?
This is a standard aggregation + group by + having problem.
Sample data:
SQL> with test (id, city) as
2 (select 1, 'London' from dual union all
3 select 2, 'Rome' from dual union all
4 select 3, 'London' from dual union all
5 select 4, 'Rome' from dual union all
6 select 5, 'Zagreb' from dual
7 )
Query:
8 select city,
9 count(*) cnt
10 from test
11 group by city
12 having count(*) > 1;
CITY CNT
------ ----------
London 2
Rome 2
SQL>
What does case expression have to do with it?
You can get your output using conditional aggregation:
SELECT COUNT(CASE city WHEN 'London' THEN 1 END) AS London,
COUNT(CASE city WHEN 'Rome' THEN 1 END) AS Rome
FROM table_name
WHERE city IN ('London', 'Rome')
Which, for the sample data:
CREATE TABLE table_name (id, city) AS
SELECT 1, 'London' FROM DUAL UNION ALL
SELECT 2, 'Rome' FROM DUAL UNION ALL
SELECT 3, 'London' FROM DUAL UNION ALL
SELECT 4, 'Rome' FROM DUAL;
Outputs:
LONDON
ROME
2
2
However, in this case, it is unclear how to handle your requirement for repeated values if the values were not repeated.
fiddle

Printing data from sub-queries SQL

I have 2 tables: SalesPeople and Customers that have snum and cnum as primary key respectively; both tables have city column as well.
Without using joins, we have to tell the names of customers and salespeople that belong to same city.
I have used nested queries to print the salespeople that belong to the city of customers, but cant figure out how to print customer names with this .
SELECT S.*
FROM SalesPeople S
WHERE City IN(
SELECT City
FROM Customers CX
);
How about this? (Disregard the fact that the WITH factoring clause doesn't exist in Oracle 9i (at least, I think so); you already have those tables).
Sample data:
SQL> with
2 salespeople (snum, city) as
3 (select 1, 'London' from dual union all
4 select 2, 'Paris' from dual union all
5 select 3, 'Rome' from dual
6 ),
7 customers (cnum, city) as
8 (select 100, 'Zagreb' from dual union all
9 select 101, 'Rome' from dual union all
10 select 102, 'Rome' from dual union all
11 select 103, 'Paris' from dual
12 )
Query:
13 select person_num
14 from (select snum as person_num, city from salespeople
15 union
16 select cnum, city from customers
17 )
18 where city = 'Rome';
PERSON_NUM
----------
3
101
102
SQL>

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;

BigQuery to aggregate with array

Given 2 tables below
WITH id_tags AS
(
SELECT 1 as ID, ['Michael','New York'] as tags UNION ALL
SELECT 2 as ID, ['Michael','Jon', 'Texas'] as tags UNION ALL
SELECT 3 as ID, ['abcd','Washington'] as tags UNION ALL
SELECT 4 as ID, ['Washington','New York','Michael'] as tags UNION ALL
SELECT 5 as ID, ['America','Michael'] as tags UNION ALL
SELECT 6 as ID, ['Washington','Michael', 'defg'] as tags UNION ALL
SELECT 7 as ID, ['America','Burqq','defg'] as tags
),
tagsCategory AS(
SELECT 'Michael' as tags, 'Person' as category UNION ALL
SELECT 'Burqq' as tags, 'Person' as category UNION ALL
SELECT 'New York' as tags, 'City' as category UNION ALL
SELECT 'Washington' as tags, 'City' as category UNION ALL
SELECT 'Texas' as tags, 'City' as category
)
I want to display an exception list. The exception list is when id_tags has 0 or more than 1 person
and when id_tags has 0 or more than 1 city. (basically, it is only 1 per category)
Expected results:
----------------------------------
ID | Reason
----------------------------------
2 | Person more than 1
3 | Only 1 city
4 | More than 1 city detected
5 | No City Detected
7 | No City Detected
Explanation
ID 1 is totally fine, it has 1 City and has 1 person therefore it is not in the list
ID 2 it is because it has 2 people
ID 3 because it has 1 city. we can ignore 'abcd' as it is not in the tags category
ID 4 is is because it has 2 cities
ID 5 because America is not city and therefore no city in that row
ID 6 is fine. We can ignore 'defg' as it is not in the list
ID 7 (the same reason as ID 5)
It looks easy for me at the first glance, however, I always find bugs in my query. Do you have any suggestion/help me with the logic or even query example?
I use standardBigQuery.
WITH id_tags AS
(
SELECT 1 AS ID, ['Michael','New York'] AS tags UNION ALL
SELECT 2 AS ID, ['Michael','Jon', 'Texas'] AS tags UNION ALL
SELECT 3 AS ID, ['abcd','Washington'] AS tags UNION ALL
SELECT 4 AS ID, ['Washington','New York','Michael'] AS tags UNION ALL
SELECT 5 AS ID, ['America','Michael'] AS tags UNION ALL
SELECT 6 AS ID, ['Washington','Michael', 'defg'] AS tags UNION ALL
SELECT 7 AS ID, ['America','Burqq','defg'] AS tags
),
tagsCategory AS(
SELECT 'Michael' AS tags, 'Person' AS category UNION ALL
SELECT 'Jon' AS tags, 'Person' AS category UNION ALL
SELECT 'Burqq' AS tags, 'Person' AS category UNION ALL
SELECT 'New York' AS tags, 'City' AS category UNION ALL
SELECT 'Washington' AS tags, 'City' AS category UNION ALL
SELECT 'Texas' AS tags, 'City' AS category
)
SELECT id,
COUNTIF(category = 'City') AS cities,
COUNTIF(category = 'Person') AS names
FROM id_tags, UNNEST(tags) tag
JOIN tagsCategory ON tag = tagsCategory.tags
GROUP BY id
HAVING NOT cities = 1 OR NOT names = 1

ORACLE SQL JOINS

I have the two tables:
TABLE1:
id name values
1 john AB
2 marry CD
3 sreya YG
TABLE2:
pid country values
45 india JKABHJ
46 usa YURRRCD
47 uk YGHJJKLJL
output
name values country
john AB india
marry CD usa
sreya YG uk
I want to join these two tables on the common columns values, but the other table columns contain extra data. How to overcome this?
table2 column "values" contains data matching to table1 "values"
values
AB
CD
YG
values
JKABHJ
YURRRCD
YGHJJKLJL
You can use like operator in query for matching values in table1 and table2.
For this query:
WITH table1 as (
select 1 as id, 'john' as name, 'AB' as value from dual union all
select 2 as id, 'marry' as name, 'CD' as value from dual union all
select 3 as id, 'sreya' as name, 'YG' as value from dual
),
table2 as (
select 45 as id, 'india' as country, 'JKABHJ' as value from dual union all
select 46 as id, 'usa' as country, 'YURRRCD' as value from dual union all
select 47 as id, 'uk' as country, 'YGHJJKLJL' as value from dual
)
select a.name, a.value, b.country
from table1 a
join table2 b on b.value like '%'||a.value||'%';
Output:
NAME VALUE COUNTRY
john AB india
marry CD usa
sreya YG uk
But I would recommend you to change a structure to make it more efficient. For example, by adding new table table2_values with column id referenced to table2.id and split values:
WITH table1 as (
select 1 as id, 'john' as name, 'AB' as value from dual union all
select 2 as id, 'marry' as name, 'CD' as value from dual union all
select 3 as id, 'sreya' as name, 'YG' as value from dual
),
table2 as (
select 45 as id, 'india' as country from dual union all
select 46 as id, 'usa' as country from dual union all
select 47 as id, 'uk' as country from dual
),
table2_values as (
select 45 as id, 'JK' as value from dual union all
select 45 as id, 'AB' as value from dual union all
select 45 as id, 'HJ' as value from dual union all
select 46 as id, 'YU' as value from dual union all
select 46 as id, 'RRR' as value from dual union all
select 46 as id, 'CD' as value from dual union all
select 47 as id, 'YG' as value from dual union all
select 47 as id, 'HJ' as value from dual
)
select a.name, a.value, c.country
from table1 a
join table2_values b on b.value = a.value
join table2 c on c.id = b.id;
You should use like operator while joining the two tables.
As below
SELECT *
FROM TABLE1
JOIN TABLE2
ON TABLE1.values like CONCAT('%',TABLE2.values,'%')