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

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.

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

JOIN Two tables in SQL with one to many mapping and do not join for an Id if any one of the row does not statisfy the condition

I have to join 2 tables with one to many mapping. I have to select the rows for an Id of all rows satisfy the condition or else do not select it.
Example:
Table A
Id Company_Name
1 ABC
2 DEF
3 GHI
4 JKL
TABLE B
ID REGION BRANCH Number
1 ASIA 1
1 AMERICA 1
1 AUSTRALIA 2
2 ASIA. 1
2 AFRICA. 2
3 ASIA. 3
3 AMERICA. 3
4.ASIA. 1
4. ASIA. 2
4 ASIA. 3
Here I want to join table A and table B only when the company of present in both asia and America only.
Output:
ID company_name region branch_number
3. GHI Asia 3
3. GHI America. 3
4. JKL ASIA. 1
4. JKL ASIA. 2
4. JKL ASIA. 3
It should not select ID 1 since it is also present in Australia.
It should also not select 2 as it is not present in America.
It selects 3 as ASIA and AMERICA is present.
IT selects 4 AS ASIA is present.
Here's one option; subquery calculates whether certain ID has any rows for regions not begin Asia and America (for them, sumreg value is larger than 0 so you omit them from the final result).
Sample data:
SQL> with
2 a (id, company_name) as
3 (select 1, 'abc' from dual union all
4 select 2, 'def' from dual union all
5 select 3, 'ghi' from dual union all
6 select 4, 'jkl' from dual
7 ),
8 b (id, region, branch) as
9 (select 1, 'asia' , 1 from dual union all
10 select 1, 'america' , 1 from dual union all
11 select 1, 'australia', 2 from dual union all
12 select 2, 'asia' , 1 from dual union all
13 select 2, 'africa' , 2 from dual union all
14 select 3, 'asia' , 3 from dual union all
15 select 3, 'america' , 3 from dual union all
16 select 4, 'asia' , 1 from dual union all
17 select 4, 'asia' , 2 from dual union all
18 select 4, 'asia' , 3 from dual
19 )
Query begins here:
20 select b.id, a.company_name, b.region, b.branch
21 from a join b on a.id = b.id
22 join -- the C subquery returns only IDs that are valid only for Asia and America
23 (select x.id,
24 sum(case when x.region not in ('asia', 'america') then 1 else 0 end) sumreg
25 from b x
26 group by x.id
27 ) c on c.id = b.id and c.sumreg = 0;
ID COM REGION BRANCH
---------- --- --------- ----------
3 ghi america 3
3 ghi asia 3
4 jkl asia 3
4 jkl asia 2
4 jkl asia 1
SQL>

Find all possible combinations column value in ORACLE 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

How to find partial duplicate values in Oracle

I have table in which one of the columns is having 1000s of records out which most of them are duplicates. Finding duplicates are easy but in this situation, they are partial duplicates e.g
ID NAME Status
1 abc Capital Approved
2 (abc Capital) Terminated
3 abc capital (dupe) Null
4 abc capitalx Null
5 BT Capital Approved
6 XE Capital Approved
7 xyz Finance Approved
8 xyz Finance X Null
9 xyz finance dupe Null
So from the above data, I want to retrieve duplicate names which are partially duplicate E.g
output:
1 abc Capital Approved
2 (abc Capital) Terminated
3 abc capital (dupe) Null
4 abc capitalx Null
5 xyz Finance Approved
6 xyz Finance X Null
7 xyz finance dupe Null
One option might be to use UTL_MATCH package and one of its functions. I chose edit_distance_similarity for this demonstration, but you might pick another.
SQL> with test (id, name) as
2 (select 1, 'abc Capital' from dual union all
3 select 2, '(abc Capital)' from dual union all
4 select 3, 'abc capital (dupe)' from dual union all
5 select 4, 'abc capitalx' from dual union all
6 select 5, 'BT Capital' from dual union all
7 select 6, 'XE Capital' from dual union all
8 select 7, 'xyz Finance' from dual union all
9 select 8, 'xyz Finance X' from dual union all
10 select 9, 'xyz finance dupe' from dual
11 ),
12 simil as
13 (select a.id, a.name aname, b.name bname,
14 utl_match.edit_distance_similarity(a.name, b.name) simil
15 from test a cross join test b
16 )
17 select distinct id, aname as name
18 from simil
19 where aname <> bname
20 and simil > 80
21 order by id;
ID NAME
---------- ------------------
1 abc Capital
2 (abc Capital)
4 abc capitalx
7 xyz Finance
8 xyz Finance X
SQL>

How can I output all columns on a group by without putting them in the group by clause?

Suppose I have a table like this:
Name Priority Country SomeData
Paul 1 USA 456
Paul 2 England 7898
Paul 3 Austria 56
Fred 2 Belgium 156
Fred 4 France 8979
Carl 3 Canada 569
Jane 1 Peru 69
I want to do something like this:
select Name, min(Priority), Country, SomeData
from dual
group by Name
But I don't want to group by all the columns.
Result should look like this:
Name Priority Country SomeData
Paul 1 USA 456
Fred 2 Belgium 156
Carl 3 Canada 569
Jane 1 Peru 69
I know it's something simple but I couldn't find anything.
How can I do it?
You can use an inline view (or CTE) to add an extra column ranking the data in the order you want, and then an outer query that only gets the highest rank:
select name, priority, country, somedata
from (
select t.*, dense_rank() over (partition by name order by priority) as rn
from your_table t
)
where rn = 1;
Quick demo with your data in a CTE:
with t(Name, Priority, Country, SomeData) as (
select 'Paul', 1, 'USA', 456 from dual
union all select 'Paul', 2, 'England', 7898 from dual
union all select 'Paul', 3, 'Austria', 56 from dual
union all select 'Fred', 2, 'Belgium', 156 from dual
union all select 'Fred', 4, 'France', 8979 from dual
union all select 'Carl', 3, 'Canada', 569 from dual
union all select 'Jane', 1, 'Peru', 69 from dual
)
select name, priority, country, somedata
from (
select t.*, row_number() over (partition by name order by priority) as rn
from t
)
where rn = 1;
NAME PRIORITY COUNTRY SOMEDATA
---- ---------- ------- ----------
Carl 3 Canada 569
Fred 2 Belgium 156
Jane 1 Peru 69
Paul 1 USA 456
or if you want to stick with grouping you can use keep dense_rank first syntax:
with your_table (name, priority, country, somedata) as (
select 'Paul', 1, 'USA', 456 from dual
union all select 'Paul', 2, 'England', 7898 from dual
union all select 'Paul', 3, 'Austria', 56 from dual
union all select 'Fred', 2, 'Belgium', 156 from dual
union all select 'Fred', 4, 'France', 8979 from dual
union all select 'Carl', 3, 'Canada', 569 from dual
union all select 'Jane', 1, 'Peru', 69 from dual
)
select name,
min(priority) as priority,
min(country) keep (dense_rank first order by priority) as country,
min(somedata) keep (dense_rank first order by priority) as somedata
from your_table
group by name;
NAME PRIORITY COUNTRY SOMEDATA
---- ---------- ------- ----------
Carl 3 Canada 569
Fred 2 Belgium 156
Jane 1 Peru 69
Paul 1 USA 456