Calculate number of rows as a column in a query - sql

Sorry about the title, it's hard to summarize what I am asking for.
Given this:
SELECT [FirstName], [LastName], '-', [Thing] FROM.....
John Smith - Plow
James Jones - Plow
James Jones - Shovel
James Jones - Axe
Sarah Lee - Hammer
Sarah Lee - Pliers
I need to get this:
John Smith - Plow - 1
James Jones - Plow - 3
James Jones - Shovel - 3
James Jones - Axe - 3
Sarah Lee - Hammer - 2
Sarah Lee - Pliers - 2
I need to include as a column the sum number of times that same person has appeared in the rows.
This is sounding like a pivot solution, but pivots make my brain hurt. Is there another way? if not, can anyone explain the pivot, if that's what it has to come to?
Thanks!

SELECT *,
COUNT(*) OVER (PARTITION BY FirstName, LastName) cnt
FROM mytable

This may not be the most efficient way to write it but gets the job done.
select
firstname
,Surname
,count(firstname + Surname) over (partition by firstname + surname) as NameOccurences
from table

I actually found a way on my own. I like the "OVER/Partition by" solutions though. Much shorter, but not as obvious to me what they are doing.
Here's what I eventually came up with:
with cte as (
select last_name, first_name, count(1) as theCount
from MetalThings
group by last_name, first_name
)
select m.*,
cte.theCount
from MetalThings m
JOIN cte on (m.last_name = cte.last_name and m.first_name = cte.first_name)

Related

SQL count in a table

I'm looking to add some form of count function to my table, but am not quite sure how to do it. The table I have is:
First name
Surname
Tom
James
Mike
James
Tom
James
Mike
Hamilton
William
Morris
Mike
James
Mike
James
I would like it to have a count, of the full names that come up twice or more, like so:
First name
Surname
Count
Tom
James
1
Mike
James
1
Tom
James
2
Mike
Hamilton
1
William
Morris
1
Mike
James
2
Mike
James
3
What is the best way to go about this in SQL? Unfortunately I need the result as per the table above, rather than simply:
First name
Surname
Count
Tom
James
2
Mike
James
3
Mike
Hamilton
1
William
Morris
1
row_number function should work
select *,
row_number() over(partition by [first name],surname order by [first name]) as count
from table_name
I believe using group by on multiple columns would be a more appropriate approach to
select [first name], surname, COUNT(*) from Employee Group BY [first name], surname;
I believe using group by on multiple columns would be a more appropriate approach to
select [first name], surname, COUNT(*) from Employee Group BY [first name], surname;
Result:

How do I transpose multiple rows to columns in SQL

My first time reading a question on here.
I am working at a university and I have a table of student IDs and their supervisors, some of the students have one supervisor and some have two or three depending on their subject.
The table looks like this
ID Supervisor
1 John Doe
2 Peter Jones
2 Sarah Jones
3 Peter Jones
3 Sarah Jones
4 Stephen Davies
4 Peter Jones
4 Sarah Jones
5 John Doe
I want to create a view that turns that into this:
ID Supervisor 1 Supervisor 2 Supervisor 3
1 John Doe
2 Peter Jones Sarah Jones
3 Peter Jones Sarah Jones
4 Stephen Davies Peter Jones Sarah Jones
5 John Doe
I have looked at PIVOT functions, but don't think it matches my needs.
Any help is greatly appreciated.
PIVOT was the right clue, it only needs a little 'extra' :)
DECLARE #tt TABLE (ID INT,Supervisor VARCHAR(128));
INSERT INTO #tt(ID,Supervisor)
VALUES
(1,'John Doe'),
(2,'Peter Jones'),
(2,'Sarah Jones'),
(3,'Peter Jones'),
(3,'Sarah Jones'),
(4,'Stephen Davies'),
(4,'Peter Jones'),
(4,'Sarah Jones'),
(5,'John Doe');
SELECT
*
FROM
(
SELECT
ID,
'Supervisor ' + CAST(ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Supervisor) AS VARCHAR(128)) AS supervisor_id,
Supervisor
FROM
#tt
) AS tt
PIVOT(
MAX(Supervisor) FOR
supervisor_id IN ([Supervisor 1],[Supervisor 2],[Supervisor 3])
) AS piv;
Result:
ID Supervisor 1 Supervisor 2 Supervisor 3
1 John Doe NULL NULL
2 Peter Jones Sarah Jones NULL
3 Peter Jones Sarah Jones NULL
4 Peter Jones Sarah Jones Stephen Davies
5 John Doe NULL NULL
You will notice that the assignment to Supervisor X is done by ordering by the Supervisor-VARCHAR. If you want the ordering done differently, you might want to include an [Ordering] column; then change to ROW_NUMBER() OVER(PARTITION BY ID ORDER BY [Ordering]). Eg an [Ordering] column could be an INT IDENTITY(1,1). I'll leave that as an excercise to you if that's what's really needed.

pl/sql query to remove duplicates and replace the data

I have the following table:
data_id new_data_id first_name last_name
1 john smith
2 john smith
3 john smith
4 jeff louis
5 jeff louis
6 jeff louis
The above table has duplicate first and last names, and the data_id is different for all of them. In order to remove these duplicates, I would need to write a SQL query to replace the highest data_id in new_data_id column. My output would look something like this:
data_id new_data_id first_name last_name
1 3 john smith
2 3 john smith
3 3 john smith
4 6 jeff louis
5 6 jeff louis
6 6 jeff louis
How would I do this?
What you're looking for is an Oracle analytic function.
The aggregate function MAX can be used to select the highest data_id from your entire resultset, but that's not exactly what you need. Instead, use its alter ego, the MAX analytic function like so:
SELECT
data_id,
MAX(data_id) OVER (PARTITION BY first_name, last_name) AS new_data_id,
first_name,
last_name
FROM employees
ORDER BY data_id
This works by "partitioning" your resultset by first_name and last_name, and then it performs the given function within that subset.
Good luck!
Here's a fiddle: http://sqlfiddle.com/#!4/48b29/4
More info can be found here:
http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions004.htm#SQLRF06174
If you need a change in place, a correlated update is probably the simplest way to write that:
UPDATE T
SET "new_data_id" =
(SELECT MAX("data_id") FROM T T2
WHERE T2."first_name" = T."first_name"
AND T2."last_name" = T."last_name")
See http://sqlfiddle.com/#!4/51a69/1

SQL: Determine if a record (First/Last Name) occurs more than once in the Date Column

I have a table with FirstName, SecondName and Date Columns. A number of records occur more than once in the date field.
First_Name Last_Name Date
Amy James 1/1/2011
Amy James 1/1/2012
John Jones 1/2/2011
James Anyone 2/2/2011
James Anyone 2/2/2012
I am trying to query the distinct First and Last Names that occur in both 2011 and 2012 only.
Thanks,
J
You need to look at GROUP BY and YEAR functions. Try something like this:
SELECT First_Name, Last_Name
FROM TableName
GROUP BY First_Name, Last_Name
HAVING COUNT(Year([Date])) > 1
Here is the SQL Fiddle.

SQL: Add counters in select

I have a table which contains names:
Name
----
John Smith
John Smith
Sam Wood
George Wright
John Smith
Sam Wood
I want to create a select statement which shows this:
Name
'John Smith 1'
'John Smith 2'
'Sam Wood 1'
'George Wright 1'
'John Smith 3'
'Sam Wood 2'
In other words, I want to add separate counters to each name. Is there a way to do it without using cursors?
Use ROW_NUMBER():
SELECT Name, ROW_NUMBER() OVER(Partition BY Name ORDER BY Name) as [Rank]
FROM MyTable
Doing:
select name, count(*) as total from table group by name;
will get you something that looks like this:
name | total
-------------+------------
John Smith | 2
-------------+------------
Sam Wood | 2
-------------+------------
George Wright| 1
This isn't what you really wanted though - ROW_NUMBER(), as ck pointed out, is what you want, but not all databases support it - mysql doesn't, for example. If you're using MySQL, this might help:
ROW_NUMBER() in MySQL