SQL: Select rows with a column value that occurs at least N times? - sql

Suppose I have a SQL table "Celebrities" with two columns: "fname" and "lname":
fname | lname
---------+-------
Bill | Clinton
Bill | Gates
George | Bush
George | Clinton
Barack | Obama
I would like to write a query that returns the first and last name of each person in the table whose last name appears at least twice in the column "lname". How do I write this SQL query?

SELECT fname, lname FROM Celebrities
WHERE lname IN
(SELECT lname FROM Celebrities
GROUP BY lname HAVING COUNT (lname) >1)

Using a JOIN:
SELECT a.*
FROM CELEBRITIES a
JOIN (SELECT c.lname
FROM CELEBRITIES c
GROUP BY c.lname
HAVING COUNT(*) >= 2) b ON b.lname = a.lname
Using EXISTS:
SELECT a.*
FROM CELEBRITIES a
WHERE EXISTS (SELECT NULL
FROM CELEBRITIES c
WHERE c.lname = a.lname
GROUP BY c.lname
HAVING COUNT(*) >= 2)

select fname, lname
from
(
select fname, lname, count(*) over(partition by lname) as lcount
from Celebrities
) as S
where lcount > 1
Tested in SQL Server 2008. Might work in other DBMS that support count(*) over(...)

Related

SQL Server: finding duplicates between two parameters in different tables

I am trying to find duplicates in SQL Server where customers with the same forename, surname, and mobile number match. The thing is they are in different tables.
custid forename surname dateofbirth
-----------------------------------
1 David John 16-09-1985
2 David Jon 16-09-1985
3 Sarah Smith 10-08-2015
4 Peter Proca 11-06-2011
5 Peter Broca 11-06-2011
addid custid line1
-------------------------
1 1 0504135846
2 2 0504135846
3 3 0506523145
4 4 0503698521
5 5 0503698521
I am currently able to find duplicates by forename and surname, but if I want to find based on mobile numbers how can I bring it in?
select c.*
from
(select
c.*,
count(*) over (partition by left(surname, 3)) as cnt
from
customers c) c
order by
surname;
Use join:
select c.*
from (select c.*, t2.line1
count(*) over (partition by surname, forename, line1) as cnt
from customers c join
table2 t2
on t2.custid = c.custid
) c
order by surname;
Here you go, just JOIN on the table. Using HAVING might simplify your query as well
SELECT COUNT(*), c.forename, c.surname, mn.line1
FROM customers c
INNER JOIN mobilenumber mn ON c.custid=mn.custid
GROUP BY c.forename, c.surname, mn.line1
HAVING COUNT(*)>1
Also, you might need to LEFT JOIN if there is a chance that some records wont be in the mobilenumbers table.

How to Retrieve a Listing of Employee's Superiors in SQL

Essentially, I have a table that lists an employee's number and the employeeNumber of who they report to.
EmpNum | Name | ReportsTo
---------------------------------
1234 | John Smith | 4523
3245 | Annie Apples | 1234
1532 | Bob Rogers | 3245
6574 | Dong Wong | 1532
Etc. Etc. So Dong Wong's hierarchy would be: He reports to -> 1532 which reports to -> 3245 which reports to -> 1234.
(I'm new to SQL, so clean and understandable solutions would be appreciated)
By doing a join...
select e1.EmpNum, e1.name, e2.EmpNum as BossNum, e2.name as BossName from empTable e1 join empTable e2 on e1.ReportsTo=e2.EmpNum
The join can then be as long as you want, e3, e4... But doing it programatically is probably easier in the front end.
You didn't specify your DBMS so this is standard ANSI SQL
with recursive report_tree as (
select empnum, name, reportsto
from employees
where empnum = 6574
union all
select c.empnum, c.name, c.reportsto
from employees c
join report_tree p on p.reportsto = c.empnum
)
select *
from report_tree;
If you want a "graphical" display, you can do something like this (still standard ANSI SQL):
with recursive report_tree as (
select empnum, name, reportsto, name as report_path, 1 as level
from employee
where empnum = 6574
union all
select c.empnum, c.name, c.reportsto, p.report_path || ' -> ' || c.name, p.level + 1
from employee c
join report_tree p on p.reportsto = c.empnum
)
select *
from report_tree
order by level desc
fetch first 1 row only;
Try this, cte is best for recursion. SO already has many solutions for such problem
create table #emp(
EmpNum int,
Name varchar(50),
ReportsTo int
);
insert into #emp
values
(1234,'John',4523),
(3245,'Annie',1234),
(1532,'Bob',3245),
(6574,'Dong',1532)
with rec as (
select #emp.ReportsTo, #emp.EmpNum, #emp.Name, 1 as level from #emp where Name = 'Bob'
union all
select #emp.ReportsTo, #emp.EmpNum, #emp.Name, level + 1 as level from #emp
inner join rec
on #emp.EmpNum = rec.ReportsTo
)
select ReportsTo, EmpNum, Name, level from rec
where level = (select max(level) from rec)
OPTION (MAXRECURSION 0)

select only one row that has the highest count in sql

I need to select one row only which has the highest count. How do I do that?
This is my current code:
select firstname, lastname, count(*) as total
from trans
join work
on trans.workid = work.workid
join artist
on work.artistid = artist.artistid
where datesold is not null
group by firstname, lastname;
Example current:
FIRSTNAME | LASTNAME | TOTAL
------------------------------
Tom | Cruise | 3
Angelina | Jolie | 9
Britney | Spears | 5
Ellie | Goulding | 4
I need it to select only this:
FIRSTNAME | LASTNAME | TOTAL
--------------------------------
Angelina | Jolie | 9
You can add order by total desc and fetch first 1 row only (since Oracle 12c r1 only, otherwise you should use your result as temp table and select from it to use rownum = 1 limitation in the where clause) , in case you total can't be the same for different groups. The other way is to add this having clause, so you can list all people with maximum total:
having count(*) = (select max(total) from (select count(*) as total from <your_query>) tmp)
or that:
having count(*) = (select count(*) as total from <your_query> order by total desc fetch first 1 row only)
In Oracle 12, you can do:
select firstname, lastname, count(*) as total
from trans join
work
on trans.workid = work.workid join
artist
on work.artistid = artist.artistid
where datesold is not null
group by firstname, lastname
order by count(*) desc
fetch first 1 row only;
In older versions, you can do this with a subquery:
select twa.*
from (select firstname, lastname, count(*) as total
from trans join
work
on trans.workid = work.workid join
artist
on work.artistid = artist.artistid
where datesold is not null
group by firstname, lastname
order by count(*) desc
) twa
where rownum = 1;
this will work sql server 2012..
with CTECount (firstname, lastname,total)
as
(
select firstname, lastname, count(1) as total
from trans
join work
on trans.workid = work.workid
join artist
on work.artistid = artist.artistid
where datesold is not null
group by firstname, lastname
)
select top(1) with ties from CTECount
order by total desc
Thanks
You could do like this, very simple:
select TOP 1 firstname, lastname, count(*) as total from trans
join work on trans.workid=work.workid
join artist on work.artistid=artist.artistid
where datesold is not null
group by firstname, lastname
Order By Total DESC;

Count distinct same names

I have table where have over 100k information.
ID FirstName
1 Bob
2 Bob
3 Tom
4 John
5 John
6 John
.. ....
Want procedure which will be count how much names are same, For example it must be like :
FirstName Count
Bob 2
Tom 1
John 3
Please help me to write it
It's very basic SQL example, group by column + aggregating results
select
FirstName, count(*)
from Table1
group by FirstName
Try this
select FirstName,Count(FirstName) From TableA group by FirstName
Try this
SELECT FirstName, COUNT(*) As Count
FROM YourTable
GROUP BY FirstName
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC
Create Procedure GetCount
as
BEGIN
Select FirstName,Count(*) from tablename group by FirstName
END

oracle duplicate rows based on a single column

How can I find out duplicate rows based on a single column. I have a table in oracle which has data as given below and it has duplicates. I'm trying to select and view all rows with duplicate employee ids as explained below
EMP table:
EmpId Fname Lname Mname Jobcode Status exp_date
1 Mike Jordan A IT W 12/2014
1 Mike Jordan A IT A 12/2014
2 Angela ruth C sales P 12/2015
2 Angela ruth C IT W 12/2015
3 Kelly Mike B sales W 12/2015
From the above table i want to select all rows which duplicate empids such as below
EmpId Fname Lname Mname Jobcode Status exp_date
1 Mike Jordan A IT W 12/2014
1 Mike Jordan A IT A 12/2014
2 Angela ruth C sales P 12/2015
2 Angela ruth C IT W 12/2015
How can I do this? thank you!
SELECT a.*
FROM TableName a
INNER JOIN
(
SELECT EmpID
FROM TableName
GROUP BY EmpID
HAVING COUNT(*) > 1
) b ON a.EmpID = b.EmpID
SQLFiddle Demo
Another way, although I prefer above, is to use IN
SELECT a.*
FROM TableName a
WHERE EmpId IN
(
SELECT EmpId
FROM TableName
GROUP BY EmpId
HAVING COUNT(*) > 1
)
SQLFiddle Demo
Here's another option using a subquery and COUNT OVER PARTITION BY since you're using Oracle 11:
SELECT *
FROM (
SELECT EmpId, Fname, Lname, Mname, Jobcode, Status, exp_date,
COUNT(EmpId) OVER (PARTITION BY EmpId) EmpCount
FROM TableName
) T
WHERE EmpCount > 1
SQL Fiddle Demo (Borrowed from JW)