How to find Column with same (some x value) value repeated more than once? Needs to return those rows. - oracle

There is a table called contacts with columns id, name, address, ph_no etc.
I need to find out rows with the same name, if the rows count is more than 1, show those rows.
For example:
Table: contacts
id--------name--------address---------ph_no--------
111 apple U.K 99*******
112 banana U.S 99*******
123 grape INDIA 99*******
143 orange S.AFRICA 99*******
152 grape KENYA 99*******
For the above table I need to get rows with same column name data like the below:
id--------name--------address---------ph_no--------
123 grape INDIA 99*******
152 grape KENYA 99*******
I need to get the rows based on the name what I given as argument like below example syntax:
select * from contacts where name='grape' and it's count(*) >1 return those rows.
How can I achieve the solution for above problem.

As #vc74 suggests analytic functions would work work a lot better here; especially if your data has any volume.
select id, name, address, ph_no ...
from ( select c.*, count(name) over ( partition by name ) as name_ct
from contacts c )
where name_ct > 1
;
EDIT
restricting on specific names the table contacts should really have an index on name and the query would look like this:
select id, name, address, ph_no ...
from ( select c.*, count(name) over ( partition by name ) as name_ct
from contacts c
where name = 'grape' )
where name_ct > 1
;

select id, name, address, ph_no
from contacts
where name in
(
select name from contacts
group by name
having count(*) > 1
)
If you have access to Oracle's analytical functions there might be a more straightforward way

select *
from contacts c
where c.name in ( select cc.name
from contacts
group by cc.name
having count(1) > 1 );

Related

How to select rows from a table based on duplicated values in a column Snowflake

I have a table A that looks similar to:
ID
PET
COUNTRY
45
DOG
US
72
DOG
CA
15
CAT
CA
36
CAT
US
37
CAT
SG
12
SNAKE
IN
20
PIG
US
14
PIG
RS
33
HORSE
IQ
(has about a few hundred rows)
I would like to retain the rows that have a duplicated "PET" value, so the result looks like:
|ID|PET |COUNTRY
|--| --- |---|
|45| DOG |US|
|72 |DOG|CA|
|15 |CAT |CA|
|36 |CAT|US|
|37 |CAT|SG|
|20|PIG|US|
|14|PIG|RS|
How can I remove the rows that do not have duplicated PET values? Would it be something like
SELECT ID, PET, COUNTRY, COUNT(*)
FROM A
GROUP BY PET, COUNTRY, ID
HAVING COUNT(*) >1
I am not sure how to group the values by PET and pick out the groups only containing one row. Thanks!
What about simply doing:
WITH
RES AS (SELECT PET, COUNT(*) FROM A GROUP BY PET HAVING COUNT(*) > 1)
SELECT ID, PET, COUNTRY FROM A WHERE PET IN (SELECT PET FROM RES);
This would give you all rows with pets present in more than one row.
A shorter way is to use QUALIFY:
SELECT *
FROM tab
QUALIFY COUNT(*) OVER(PARTITION BY PET) > 1;

Deletting duplicate data on oracle using sql failed

I have a table abc as:
acc subgroup
720V A
720V A
720V A
720V A
111 C
222 D
333 E
My expected output is:
acc subgroup
720V A
111 C
222 D
333 E
Since 720V A is duplicate i want to delete all three duplicate data and only want one data in my table.
So,i tried
DELETE FROM (
select t.*,rownum rn from abc t where acc='720V') where rn>1;
So,I get error as:
ORA-01732: data manipulation operation not legal on this view
How i can get my expected output?
Your table seems to be lacking a primary key column, which is a big problem here. Assuming there actually is a primary key column PK, we can try using ROW_NUMBER to identify any "duplictes":
DELETE
FROM abc t1
WHERE pk IN (SELECT pk
FROM (
SELECT t.pk, ROW_NUMBER() OVER (PARTITION BY acc, subgroup ORDER BY pk) rn
FROM abc t) x
WHERE rn > 1
);
Note that if you can live with keeping your original data, then the most expedient thing to do might be to create a distinct view:
CREATE VIEW abc_view AS
SELECT DISTINCT acc, subgroup
FROM abc;

Oracle 'Partition By' and 'Row_Number' keyword along with pivot

I have this query written by someone else and I am trying to figure out how is it working. I have general idea about all these things such as row_number() , partition by, pivot but I am unable to understand them all together.
For this query :
select
d, p, s, a
from
(
select name,occupation, (ROW_NUMBER() OVER (partition by occupation order by name)) as rownumber from occupations
)
pivot
(
max(name)
for occupation
in ('Doctor' as d, 'Professor' as p, 'Singer' as s, 'Actor' as a)
)
order by rownumber;
This is the input table on which the above query works :
This it the output generated by the query which is correct as per the question :
Jenny Ashley Meera Jane
Samantha Christeen Priya Julia
NULL Ketty NULL Maria
Now, I want to know how the output is generated by the query i.e. step by step with flow of execution. Explanation with easy examples matching the above situation would be much appreciated. Thanks in advance.
After from clause you have following :
select name,occupation, (ROW_NUMBER() OVER (partition by occupation order by name))
Above virtually restack your table data in three columns - Name, occupation, rownumber. rownumber will reset itself as soon as occupation column changes. Output data will be like :
NAME OCCUPATION ROWNUMBER
-------------------- -------------------- ----------
Jane ACTOR 1
Julia ACTOR 2
Maria ACTOR 3
JENNY DOCTOR 1 <-- rownumber reset to 1
Sammantha DOCTOR 2
Pivot function let you aggregate result & rotate rows into columns.
Pivot usage code is :
PIVOT
(
aggregate_function(column2)
FOR column2
IN ( expr1, expr2, ... expr_n) | subquery
)
So your PIVOT function have name stacked NAME based on OCCUPATION . Each stack (column in output) is ordered by rownumber column inserted via first subquery.

pl-sql include column names in query

A weird request maybe but. My boss wants me to create an admin version of a page we have that displays data from an oracle query in a table.
The admin page, instead of displaying the data (query returns 1 row), needs to return the table name and column name
Ex: Instead of:
Name Initial
==================
Bob A
I want:
Name Initial
============================
Users.FirstName Users.MiddleInitial
I realize I can do this in code but would rather just modify the query to return the data I want so I can leave the report generation code mostly alone.
I don't want to do it in a stored procedure.
So when I spit out the data in the report using something like:
blah blah = MyDataRow("FirstName")
I can leave that as is but instead of it displaying "BOB" it would display "Users.FirstName"
And I want to do the query using select * if possible instead of listing all the columns
So for each of the columns I am querying in the * , I want to get (instead of the column value) the tablename.ColumnName or tablename|columnName
hope you are following- I am confusing myself...
pseudo:
select tablename + '.' + Columnname as WhateverTheColumnNameIs
from Table1
left join Table2 on whatever...
Join Table_Names on blah blah
Whew- after writing all this I think I will just do it on the code side.
But if you are up for it maybe a fun challenge
Oracle does not provide an authentic way(there is no pseudocolumn) to get the column name of a table as a result of a query against that table. But you might consider these two approaches:
Extract column name from an xmltype, formed by passing cursor expression(your query) in the xmltable() function:
-- your table
with t1(first_name, middle_name) as(
select 1,2 from dual
), -- your query
t2 as(
select * -- col1 as "t1.col1"
--, col2 as "t1.col2"
--, col3 as "t1.col3"
from hr.t1
)
select *
from ( select q.object_value.getrootelement() as col_name
, rownum as rn
from xmltable('//*'
passing xmltype(cursor(select * from t2 where rownum = 1))
) q
where q.object_value.getrootelement() not in ('ROWSET', 'ROW')
)
pivot(
max(col_name) for rn in (1 as "name", 2 as "initial")
)
Result:
name initial
--------------- ---------------
FIRST_NAME MIDDLE_NAME
Note: In order for column names to be prefixed with table name, you need to list them
explicitly in the select list of a query and supply an alias, manually.
PL/SQL approach. Starting from Oracle 11g you could use dbms_sql() package and describe_columns() procedure specifically to get the name of columns in the cursor(your select).
This might be what you are looking for, try selecting from system views USER_TAB_COLS or ALL_TAB_COLS.

Select all rows from SQL based upon existence of multiple rows (sequence numbers)

Let's say I have table data similar to the following:
123456 John Doe 1 Green 2001
234567 Jane Doe 1 Yellow 2001
234567 Jane Doe 2 Red 2001
345678 Jim Doe 1 Red 2001
What I am attempting to do is only isolate the records for Jane Doe based upon the fact that she has more than one row in this table. (More that one sequence number)
I cannot isolate based upon ID, names, colors, years, etc...
The number 1 in the sequence tells me that is the first record and I need to be able to display that record, as well as the number 2 record -- The change record.
If the table is called users, and the fields called ID, fname, lname, seq_no, color, date. How would I write the code to select only records that have more than one row in this table? For Example:
I want the query to display this only based upon the existence of the multiple rows:
234567 Jane Doe 1 Yellow 2001
234567 Jane Doe 2 Red 2001
In PL/SQL
First, to find the IDs for records with multiple rows you would use:
SELECT ID FROM table GROUP BY ID HAVING COUNT(*) > 1
So you could get all the records for all those people with
SELECT * FROM table WHERE ID IN (SELECT ID FROM table GROUP BY ID HAVING COUNT(*) > 1)
If you know that the second sequence ID will always be "2" and that the "2" record will never be deleted, you might find something like:
SELECT * FROM table WHERE ID IN (SELECT ID FROM table WHERE SequenceID = 2)
to be faster, but you better be sure the requirements are guaranteed to be met in your database (and you would want a compound index on (SequenceID, ID)).
Try something like the following. It's a single tablescan, as opposed to 2 like the others.
SELECT * FROM (
SELECT t1.*, COUNT(name) OVER (PARTITION BY name) mycount FROM TABLE t1
)
WHERE mycount >1;
INNER JOIN
JOIN:
SELECT u1.ID, u1.fname, u1.lname, u1.seq_no, u1.color, u1.date
FROM users u1 JOIN users u2 ON (u1.ID = u2.ID and u2.seq_no = 2)
WHERE:
SELECT u1.ID, u1.fname, u1.lname, u1.seq_no, u1.color, u1.date
FROM users u1, thetable u2
WHERE
u1.ID = u2.ID AND
u2.seq_no = 2
Check out the HAVING clause for a summary query. You can specify stuff like
HAVING COUNT(*) >= 2
and so forth.

Resources