select records with two different values [duplicate] - sql

This question already has answers here:
Oracle query to match all values in the list among all rows in table
(3 answers)
Closed last month.
Using Oracle SQL, If I have this dataset, how can I select only those records which has value of both Europe and America? In other words I don't wanna see Johnny Bravo on the report.
Name
Surname
Continent
Johnny
Bravo
America
Pier
Ruso
Europe
Pier
Ruso
America
Thank you

Here's one option; it expects that there are two distinct continents per name, where one of them is America and another Europe.
Johnny isn't returned as he has only one continent (America), and Mike isn't in result set as he has 3 continents (two of them are America and Europe, but - there are 3 continents in a table for that person):
Sample data:
SQL> with test (name, surname, continent) as
2 (select 'Johnny', 'Bravo', 'America' from dual union all
3 --
4 select 'Pier' , 'Ruso' , 'Europe' from dual union all
5 select 'Pier' , 'Ruso' , 'America' from dual union all
6 --
7 select 'Mike' , 'Tiger', 'Europe' from dual union all
8 select 'Mike' , 'Tiger', 'Asia' from dual union all
9 select 'Mike' , 'Tiger', 'America' from dual
10 )
Query:
11 select name, surname
12 from test
13 group by name, surname
14 having count(distinct continent) = 2
15 and min(continent) = 'America'
16 and max(continent) = 'Europe';
NAME SURNAME
------ ----------
Pier Ruso
SQL>

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

[1]: ORA-00904: "VW_D"."CL_NAME": invalid identifier

I am trying to run this code in Oracle database but it's giving error :
ORA-00904: "vw_d"."cl_name": invalid identifier
What's wrong with the query:
SELECT *
FROM vw_doctrans vw_d
WHERE (SELECT COUNT(*)
FROM (SELECT *
FROM vw_doctrans vw
WHERE vw.cl_name = vw_d.cl_name
GROUP BY vw.country)) > 1
I tried this query in MySQL and works fine
To me, it looks like
Sample data:
SQL> with vw_doctrans (id, cl_name, country) as
2 (select 1, 'Bob', 'UK' from dual union all
3 select 2, 'Bob', 'USA' from dual union all
4 select 3, 'Bob', 'UAE' from dual union all
5 select 4, 'Bob', 'UAE' from dual union all
6 select 5, 'Bob', 'UAE' from dual union all
7 --
8 select 6, 'John', 'Canada' from dual union all
9 select 7, 'John', 'Canada' from dual union all
10 --
11 select 8, 'Caroline', 'India' from dual union all
12 select 9, 'Caroline', 'USA' from dual union all
13 select 10, 'Caroline', 'USA' from dual union all
14 select 11, 'Caroline', 'USA' from dual
15 ),
Query begins here:
16 temp as
17 (select v.*,
18 count(distinct country) over (partition by cl_name) cnt
19 from vw_doctrans v
20 )
21 select distinct cl_name, country
22 from temp
23 where cnt >= 2
24 order by cl_name, country;
CL_NAME COUNTR
-------- ------
Bob UAE
Bob UK
Bob USA
Caroline India
Caroline USA
SQL>
[EDIT: if the table already existed (i.e. without a CTE)]
Table contents:
SQL> select * from vw_doctrans;
ID CL_NAME COUNTR
---------- -------- ------
1 Bob UK
2 Bob USA
3 Bob UAE
4 Bob UAE
5 Bob UAE
6 John Canada
7 John Canada
8 Caroline India
9 Caroline USA
10 Caroline USA
11 Caroline USA
11 rows selected.
Here's how to use a CTE (that's line #16 in previous query):
SQL> with temp as
2 (select v.*,
3 count(distinct country) over (partition by cl_name) cnt
4 from vw_doctrans v
5 )
6 select distinct cl_name, country
7 from temp
8 where cnt >= 2
9 order by cl_name, country;
CL_NAME COUNTR
-------- ------
Bob UAE
Bob UK
Bob USA
Caroline India
Caroline USA
SQL>
You are way overthinking it. This is just:
SELECT vw_d.cl_name, vw_d.country
FROM vw_doctrans vw_d
WHERE EXISTS (
SELECT *
FROM vw_doctrans vw
WHERE vw.cl_name = vw_d.cl_name AND vw.country != vw_d.country
)
GROUP BY vw_d.cl_name, vw_d.country
But your "I need also other columns too: Bob with countries, date, message of text. Not only cl_name and country column" directly conflicts with your "if message came from same country 2-3times show only one time the country." You can't have both; if you want only one row for each name/country combination, you need to decide how to pick which values for the other columns you want.

Find rows with duplicate values in two columns where at least one value in one column is a specific value

So, I'm not sure how it works and I haven't found a sufficient answer by googleing (probably not using the right buzz words). So here it comes:
Let's say I have a table like this, let's call it persons
ID
Name
First Name
Country
1
Doe
John
USA
2
Doe
John
UK
3
Doe
John
Brazil
4
Meyer
Julia
Germany
5
Meyer
Julia
Austria
6
Picard
Jean-Luc
France
7
Picard
Jean-Luc
UK
8
Nakamura
Hikaro
Japan
Ok, so now I want to select all the rows that have the same name and first name and where at least one country is the UK. So my result set should look like this.
ID
Name
First_Name
Country
1
Doe
John
USA
2
Doe
John
UK
3
Doe
John
Brazil
6
Picard
Jean-Luc
France
7
Picard
Jean-Luc
UK
I mean, I know how to find doubles in general like this
SELECT *
FROM persons p1
JOIN (SELECT NAME, FIRST_NAME, count(*) FROM PERSONS
GROUP BY FIRST_NAME, NAME having count(*) >1) p2
ON p1.NAME = p2.NAME
AND p1.FIRST_NAME = p2.FIRST_NAME;
But this also results in having Julia Meyer in there and I don't want her in there.
Any suggestions?
Count country of interest conditionally
SELECT *
FROM persons p1
JOIN (
SELECT NAME, FIRST_NAME
FROM PERSONS
GROUP BY FIRST_NAME, NAME
having count(*) > 1 and count(case country = 'UK' then 1 end) >= 1
) p2 ON p1.NAME = p2.NAME
AND p1.FIRST_NAME = p2.FIRST_NAME;
Use EXISTS:
SELECT p1.*
FROM persons p1
WHERE EXISTS (
SELECT *
FROM persons p2
WHERE p2.ID <> p1.ID
AND p2.Name = p1.Name AND p2.FirstName = p1.FirstName
AND 'UK' IN (p1.Country, p2.Country)
);
See the demo.
I want to select all the rows that have the same name and first name and where at least one country is the UK.
You can use the COUNT analytic function with conditional aggregation (and solve the problem in a single table scan and without any self-joins):
SELECT id, name, first_name, country
FROM (
SELECT t.*,
COUNT(CASE country WHEN 'UK' THEN 1 END)
OVER (PARTITION BY name, first_name) AS cnt
FROM table_name t
)
WHERE cnt > 0;
Which, for the sample data:
CREATE TABLE table_name (ID, Name, First_Name, Country) AS
SELECT 1, 'Doe', 'John', 'USA' FROM DUAL UNION ALL
SELECT 2, 'Doe', 'John', 'UK' FROM DUAL UNION ALL
SELECT 3, 'Doe', 'John', 'Brazil' FROM DUAL UNION ALL
SELECT 4, 'Meyer', 'Julia', 'Germany' FROM DUAL UNION ALL
SELECT 5, 'Meyer', 'Julia', 'Austria' FROM DUAL UNION ALL
SELECT 6, 'Picard', 'Jean-Luc', 'France' FROM DUAL UNION ALL
SELECT 7, 'Picard', 'Jean-Luc', 'UK' FROM DUAL UNION ALL
SELECT 8, 'Nakamura', 'Hikaro', 'Japan' FROM DUAL;
Outputs:
ID
NAME
FIRST_NAME
COUNTRY
1
Doe
John
USA
2
Doe
John
UK
3
Doe
John
Brazil
6
Picard
Jean-Luc
France
7
Picard
Jean-Luc
UK
If you want to find duplicate rows where at least one is UK then also count all the rows in the partition:
SELECT id, name, first_name, country
FROM (
SELECT t.*,
COUNT(CASE country WHEN 'UK' THEN 1 END)
OVER (PARTITION BY name, first_name) AS cnt_uk,
COUNT(*)
OVER (PARTITION BY name, first_name) AS cnt_all
FROM table_name t
)
WHERE cnt_uk > 0
AND cnt_all >= 2;
Which gives the same output for the sample data.
db<>fiddle here
There are 2 conditions, 1) containing 'UK' AND 2) having count(1) > 1. So, this query below would work.
SELECT p1.*
FROM persons p1
WHERE (p1.NAME, p1.FIRST_NAME) IN (
SELECT p2.NAME, p2.FIRST_NAME
FROM persons p2
WHERE p2.Country = 'UK') AND
AND (p1.NAME, p1.FIRST_NAME) IN (
SELECT p3.NAME, p3.FIRST_NAME
FROM persons p3
GROUP BY p3.NAME, p3.FIRST_NAME
HAVING COUNT(1) > 1)

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>

Problem with using regular expression in SQL

I have a column with name "data-description" which has entries like
Mumbai,Maharastra,India
London,London, Britain
Chandigarh,Haryana,India
Lahore, Punjab, Non-India
Each line describes the value of one data-description column.
Now I need to update another table which will have three columns which will have
<City> => <Citycode> ---> Every City
<Statename> => <Statename>
<Country> => <Country>
I have a table where a mapping between City and City-Code is made. Now I need to make another table with the three columsn Citycode, Statename, Country
How do I do this with a couple of SQl statements and without using any PL/SQL?
Also, The order may not be the same in rows. Like some rows have order City,State,County. Others may have the order State,Country,City.
you can use REGEXP_SUBSTR to extract information from your source column:
SQL> WITH my_data AS (
2 SELECT 'Mumbai,Maharastra,India' d FROM dual
3 UNION ALL SELECT 'London,London, Britain' d FROM dual
4 UNION ALL SELECT 'Chandigarh,Haryana,India' d FROM dual
5 UNION ALL SELECT 'Lahore, Punjab, Non-India' d FROM dual
6 )
7 SELECT regexp_substr(d, '[^, ]+', 1, 1) City,
8 regexp_substr(d, '[^, ]+', 1, 2) Statename,
9 regexp_substr(d, '[^, ]+', 1, 3) Country
10 FROM my_data;
CITY STATENAME COUNTRY
------------------------- ------------------------- -------------------------
Mumbai Maharastra India
London London Britain
Chandigarh Haryana India
Lahore Punjab Non-India