select only one row that has the highest count in sql - 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;

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 create a oracle view of the max sum of a sum of values of a column based on the values of another

I need to create a view in Oracle 11g that would take these tables:
employees
FirstName | LastName | EmployeeID
-----------------------------------
joe | shmo | 1
bob | moll | 2
salesData
Employee ID | commission on sale
----------------------------------
1 | $20
1 | $30
2 | $50
2 | $60
and then sum up the total commission each employee earned and return the employee who earned the most commission.
So using the sample data the view will contain the employee id :: 2 or bob moll.
This should get you what you need
Create someviewname as view
Select EmployeeID, sum (commision)
from employees
left outer join salesData on salesData.EmployeeID = employees.EmployeeID
Group by EmployeeID, commision
order by commission desc
SELECT employeeID
FROM
(SELECT employeeID,
SUM(commission)
FROM sales
GROUP BY employeeID
ORDER BY SUM(commission)
)
WHERE rownum = 1
Not sure why you want a view of that, but hopefully, you can figure that out.
In Oracle 12g+, you can use fetch:
select employeeid
from sales
group by employeeid
order by sum(commission) desc
fetch first 1 row only;
In earlier versions, one method is to use rownum:
select s.*
from (select employeeid
from sales
group by employeeid
order by sum(commission) desc
) s
where rownum = 1;

How to count occurrences of a column value in SQL?

I have a table of students:
id | age|num
-------------
0 | 25| 10
1 | 25| 5
2 | 23| 5
I want to query for all students, and an additional column that counts how many students are of the same age:
id | num | age | agecount|numcount
-------------------------------------
0 | 10 | 25 | 2 |1
1 | 5 | 23 | 1 |2
What's the most efficient way of doing this? if there's a better way**. Is there?
You have two queries:
One for the list of the students:
SELECT
id, age, num
FROM
students
And one for the count of students with the same age:
SELECT
age
, count(1)
FROM
students
GROUP BY
age
Now you have to combine these two queries:
You can JOIN one or more tables or subqueries. Lets do it:
SELECT
S.id, S.age, S.num, age.cnt
FROM
-- List of all students
(
SELECT
id, age, num
FROM
students
) S
-- Ages with student counts
INNER JOIN (
SELECT
age
, count(1) AS cnt
FROM
students
GROUP BY
age
) A
ON S.age = A.age
You can simplify the above query with removing the first subquery and use the students table instead:
SELECT
S.id, S.age, S.num, A.cnt
FROM
students S
-- Ages with student counts
INNER JOIN (
SELECT
age
, count(1) AS cnt
FROM
students
GROUP BY
age
) A
ON students.age = age.age
Now you can modify this sample query to achieve your goal.
To count student with the same age :
select age ,count(age) from s_table group by age

INNER JOIN on CTE (Common Table Expression) Without PK

I have a CTE in which I am finding duplicate records matching on 5 columns:
;WITH DuplicateCount AS
(
SELECT
FirstName,
LastName,
DateofBirth,
Email,
c1.Status,
Count(*) AS TotalCount
FROM Customer c
INNER JOIN Customer_1 c1 ON c1.customerID = c.customerID
GROUP BY FirstName, LastName, DateofBirth, Email, c1.Status
HAVING COUNT(*) > 1
)
I am then selecting Status and TotalCount from that CTE and joining an Enum table to produce readable data
;WITH DuplicateCount AS
(
SELECT
FirstName,
LastName,
DateofBirth,
Email,
c1.Status,
Count(*) AS TotalCount
FROM Customer c
INNER JOIN Customer_1 c1 ON c1.customerID = c.customerID
GROUP BY FirstName, LastName, DateofBirth, Email, c1.Status
HAVING COUNT(*) > 1
)
SELECT e.Display, dc.TotalCount
FROM DuplicateCount dc
INNER JOIN Enum e ON dc.Status = e.Index
In this scenario, I am able to pull back readable data and use Excel to spit out a graph report of duplicates by Status.
Problem
I need to join the Customer_1 table once again to gather one more column: Stage. Here is how I tried to do it:
;WITH DuplicateCount AS
(
SELECT customerID,
FirstName,
LastName,
DateofBirth,
Email,
c1.Status,
Count(*) AS TotalCount
FROM Customer c
INNER JOIN Customer_1 c1 ON c1.customerID = c.customerID
GROUP BY customerID, FirstName, LastName, DateofBirth, Email, c1.Status
HAVING COUNT(*) > 1
)
SELECT e.Display,
CASE
WHEN c1.Stage = 6 THEN 'First'
WHEN c1.Stage = 7 THEN 'Second'
WHEN c1.Stage = 8 THEN 'Third'
WHEN c1.Stage = 11 THEN 'Fourth'
WHEN c1.Stage = 9 THEN 'Fifth'
WHEN c1.Stage = 10 THEN 'Sixth'
WHEN c1.Stage = 12 THEN 'Unknown'
ELSE ''
END AS Stage,
dc.TotalCount
FROM DuplicateCount dc
INNER JOIN Enum e ON dc.Status = e.Index
INNER JOIN Customer_1 c1 ON c1.customerID = dc.customerID
Obviously, that didn't work because none of my records will have duplicate PKs.
Is there a way to join a table to my CTE without a PK? Or somehow add a PK to my CTE without grouping by it?
Edit: This is what I am trying to achieve
|FirstName | LastName | Stage | Total Count
| John | Smith | First | 2
| John | Smith | Third | 2
| Alex | Smith | First | 2
| Jane | Smith | Third | 2
| Jane | Smith | First | 2
| Jack | Smith | Second | 2
Then, when reporting on this data:
John Smith has 4 total records. Two in First, two in Third
Alex Smith has 2 total records. Two in First
Jane Smith has 4 total records. Two in First and two in Third
Jack Smith has 2 total records. Two in Second.
When graphing this data, I should be able to see:
First: 6 total.
Second: 2 total.
Third: 4 total.
Ideally, I could then also bring in CreatedDate and begin to gather data-over-time reports for:
How many duplicates per Stage.
How many duplicates per Person.
How many duplicates for specific date ranges, events, etc.
The cardinality of the two sets of data don't match. By that I mean the first set of data with the identified duplicates in is aggregated data across a number of customers (without identifying any customers). You can't then take the multiple separate Customer IDs and attribute them back to the aggregated rows.
I think what you need to do is re-frame what you are trying to get out of your data and work backwards. Post an example set of results that you are trying to achieve.
UPDATE:
It seems you want a list of customer\stage groups with counts?:
SELECT customerID,
FirstName,
LastName,
DateofBirth,
Email,
c1.Status,
CASE
WHEN c1.Stage = 6 THEN 'First'
WHEN c1.Stage = 7 THEN 'Second'
WHEN c1.Stage = 8 THEN 'Third'
WHEN c1.Stage = 11 THEN 'Fourth'
WHEN c1.Stage = 9 THEN 'Fifth'
WHEN c1.Stage = 10 THEN 'Sixth'
WHEN c1.Stage = 12 THEN 'Unknown'
ELSE ''
END AS Stage,
Count(*) AS TotalCount
FROM Customer c
INNER JOIN Customer_1 c1 ON c1.customerID = c.customerID
GROUP BY customerID, FirstName, LastName, DateofBirth, Email, c1.Status, c1.Stage
HAVING COUNT(*) > 1

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

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(...)