Find all possible combinations column value in ORACLE SQL - sql

Could you please help me to solve this Below Query:
I have below table of data.
EmpNo
Name
City
1
John
US
2
Miranda
US
3
Pete
US
4
Jack
US
5
Kathy
UK
6
Tanni
UK
7
Sally
UAE
I want output as like below:
City
Name1
Name2
US
John
Miranda
US
John
Pete
US
John
Jack
US
Miranda
Pete
US
Miranda
Jack
US
Pete
Jack
UK
Kathy
Tanni
PLSQL we can write block to get this output. But is it possible to get output using SQL code alone?

Looks like a self join.
SQL> with temp (empno, name, city) as
2 (select 1, 'John' , 'US' from dual union all
3 select 2, 'Miranda', 'US' from dual union all
4 select 3, 'Pete' , 'US' from dual union all
5 select 4, 'Jack' , 'US' from dual union all
6 select 5, 'Kathy' , 'UK' from dual union all
7 select 6, 'Tanni' , 'UK' from dual union all
8 select 7, 'Sally' , 'UAE' from dual
9 )
10 select a.city, a.name, b.name
11 from temp a join temp b on a.city = b.city and a.name < b.name
12 order by a.city, a.name;
CIT NAME NAME
--- ------- -------
UK Kathy Tanni
US Jack Miranda
US Jack John
US Jack Pete
US John Pete
US John Miranda
US Miranda Pete
7 rows selected.
SQL>

with
input_table (empno, name, city) as (
select 1, 'John' , 'US' from dual union all
select 2, 'Miranda', 'US' from dual union all
select 3, 'Pete' , 'US' from dual union all
select 4, 'Jack' , 'US' from dual union all
select 5, 'Kathy' , 'UK' from dual union all
select 6, 'Tanni' , 'UK' from dual union all
select 7, 'Sally' , 'UAE' from dual
)
-- end of sample data (for testing only, not part of the query)
-- remove WITH clause and use your actual table name below
select t1.city, t1.name as name1, t2.name as name2
from input_table t1 inner join input_table t2
on t1.city = t2.city and t1.empno < t2.empno
order by t1.empno, t2.empno -- if needed
;
CITY NAME1 NAME2
----- -------- --------
US John Miranda
US John Pete
US John Jack
US Miranda Pete
US Miranda Jack
US Pete Jack
UK Kathy Tanni

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.

sql query want to list employeeId,EmployeeName,ManagerId,ManagerName,TopManagerId,TopManagerName

output like
EmpId,EmpName,ManagerId,ManagerName,TopManagerId,TopManagerName
Employee Table has 3 columns
EmpId,EmpName,ManagerId
In Oracle, you can use a hierarchical query:
SELECT empid,
empname,
managerid,
PRIOR empname AS managername,
CONNECT_BY_ROOT Empid AS topmanagerid,
CONNECT_BY_ROOT empname AS topmanagername
FROM table_name
START WITH managerid IS NULL
CONNECT BY PRIOR empid = managerid
ORDER SIBLINGS BY EmpName
Which, for the sample data:
CREATE TABLE table_name (EmpId,EmpName,ManagerId) AS
SELECT 1, 'Alice', NULL FROM DUAL UNION ALL
SELECT 2, 'Betty', 1 FROM DUAL UNION ALL
SELECT 3, 'Carol', 2 FROM DUAL UNION ALL
SELECT 4, 'Debra', 3 FROM DUAL UNION ALL
SELECT 5, 'Emily', 2 FROM DUAL;
Outputs:
EMPID
EMPNAME
MANAGERID
MANAGERNAME
TOPMANAGERID
TOPMANAGERNAME
1
Alice
null
null
1
Alice
2
Betty
1
Alice
1
Alice
3
Carol
2
Betty
1
Alice
4
Debra
3
Carol
1
Alice
5
Emily
2
Betty
1
Alice
db<>fiddle here

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)

Also display the model of computer allocated to the employee and the manager, how to do thi

Display id, name, manager id and manager name of those employees who are allocated a computer and whose manager is also allocated a computer. Also display the model of computer allocated to the employee and the manager.
expected output: ID ENAME MGRID MGRNAME E_MODEL M_MODEL
5 Ayaz Mohammad 1 James Potter Edge Vostro
select
e.id, e.ename, e.mgrid, m.mgrname, e.e_model, m.m_model
from (
select e.id, e.ename, e.manager mgrid, c.model e_model
from employee e, computer c
where e.compid = c.compid
) e, (
select e.id mgrid, e.ename mgrname, c.model m_model
from employee e, computer c
where e.compid = c.compid
) m
where e.mgrid = m.mgrid
You should consider attempting to do your own homework
CREATE TABLE computers (serial_number, manufacturer, model) AS
SELECT 'D123', 'Dell', 'laptop' FROM DUAL UNION ALL
SELECT 'D124', 'Dell', 'laptop' FROM DUAL UNION ALL
SELECT 'A1424', 'Apple', 'laptop' FROM DUAL UNION ALL
SELECT 'A1425', 'Apple', 'laptop' FROM DUAL UNION ALL
SELECT 'C1725', 'compaq', 'tower' FROM DUAL UNION ALL
SELECT 'C1726', 'compaq', 'tower' FROM DUAL UNION ALL
SELECT 'C1727', 'compaq', 'tower' FROM DUAL;
CREATE TABLE employees (employee_id, manager_id, first_name, last_name, serial_number) AS
SELECT 1, NULL, 'Alice', 'Abbot', 'D123' FROM DUAL UNION ALL
SELECT 2, 1, 'Beryl', 'Baron','D124' FROM DUAL UNION ALL
SELECT 3, 1, 'Carol', 'Chase','A1424' FROM DUAL UNION ALL
SELECT 4, 2, 'Debra', 'Doris','A1425' FROM DUAL UNION ALL
SELECT 5, 3, 'Emily', 'Evans','C1725' FROM DUAL UNION ALL
SELECT 6, 3, 'Fiona', 'Frank','C1726' FROM DUAL UNION ALL
SELECT 7, 6, 'Gemma', 'Grace','C1727' FROM DUAL;
select
EMP.EMPLOYEE_ID,
EMP.FIRST_NAME,
EMP.LAST_NAME,
EMP.MANAGER_ID,
M.FIRST_NAME,
M.LAST_NAME,
EMP.serial_number,
C.manufacturer,
C.model
from
employees emp
JOIN computers c ON emp.serial_number = c.serial_number
LEFT OUTER JOIN employees m ON emp.MANAGER_ID = m.EMPLOYEE_ID
ORDER BY EMP.EMPLOYEE_ID;
EMPLOYEE_ID FIRST_NAME LAST_NAME MANAGER_ID FIRST_NAME LAST_NAME SERIAL_NUMBER MANUFACTURER MODEL
1 Alice Abbot - - - D123 Dell laptop
2 Beryl Baron 1 Alice Abbot D124 Dell laptop
3 Carol Chase 1 Alice Abbot A1424 Apple laptop
4 Debra Doris 2 Beryl Baron A1425 Apple laptop
5 Emily Evans 3 Carol Chase C1725 compaq tower
6 Fiona Frank 3 Carol Chase C1726 compaq tower
7 Gemma Grace 6 Fiona Frank C1727 compaq tower