SQL - Display Name ID from Consecutive Occurrences of values in a Table - sql

I have a table created, as an example 'Table1', see below;
Name Year
John 2003
Lyla 1994
Faith 1996
John 2002
Carol 2000
Carol 1999
John 2001
Carol 2002
Lyla 1996
Lyla 1997
Carol 2001
John 2009
Based on the above table, I have summarised my findings.
Carol participated for 4 years in a row; 1999, 2000, 2001, 2002
John participated for 3 years in a row; 2001, 2002, 2003 – John also participated in 2009, but this does not count as part of the streak.
Lyla participated in 1994, 1996, 1997 but these were not three consecutive years.
Faith participated only 1 time.
What I am looking to do is write a SQL query where only the Name Id in the table are displayed where the users have participated for 3 consecutive years or more, so I should only be getting the names of only 'Carol' and 'John' based on the above.
I am not exactly sure how to write this and would hope that someone could guide me.
I have only come up with a short and basic start like the one below, but in all honesty I am not sure that is even the correct way to go about it.
Select Name From Table1
Where Year = ?
Order by Name asc
Group by Year

Assuming you have one row per person per year, you can use lag() and select distinct:
select distinct name
from (select t.*,
lag(year, 2) over (partition by name order by name) as prev2_year
from table1 t
) t
where prev2_year = year - 2;
This simply looks back two rows for each name and compares the year on that row to the year on the current row. If there are three years in a row, then that year is exactly year - 2.
You could also do this with joins, but the above probably performs better:
select distinct t1.name
from table1 t1 join
table1 t1_1
on t1.name = t1_1.name and
t1.year = t1_1.year + 1 join
table1 t1_2
on t1.name = t1_2.name and
t1.year = t1_2.year + 2;

select
n1.name,
SUM(CASE WHEN n2.year is null then 0 else 1 end)+1 YearsInRow
from Table1 n1
left join Table1 n2 on n2.name=n1.name and (n2.year=n1.year+1 )
GROUP by n1.name
HAVING SUM(CASE WHEN n2.year is null then 0 else 1 end)+1 >=3
output:
name YearsInRow
---------- -----------
Carol 4
John 3

Related

Create column in SQL that indicates if at least one row meets a condition for a given ID

I have a table as follows:
ID
YearlyAwardStatus
Year
101
Awarded
2014
101
Not Awarded
2015
102
Not Awarded
2014
102
Not Awarded
2015
I want to create a column via a SQL query that will show if a given ID has ever been 'Awarded' across multiple years.
ID
YearlyAwardStatus
Year
EverAwarded
101
Awarded
2014
Yes
101
Not Awarded
2015
Yes
102
Not Awarded
2014
No
102
Not Awarded
2015
No
I have tried using CASE but have not been able to get it to return a result that analyzes more than one row at a time.
You can use a correlated subquerys tochekc if a ID has a award recieved
SELECT
ID, YearlyAwardStatus, Year
, CASE WHEN EXISTS (SELECT1 FROM table1 t2 WHERE t1.ID = t2.ID and t2.YearlyAwardStatus = 'Awarded') THEM 'Yes' ELSE 'No' END EverAwarded
FROM table1 t1

How to group two fields together in SQL?

say I have a sql that currently returns all soccer players who has played during each years. Like so:
name year goals
john 2010 1
john 2006 2
john 2006 8
fred 2006 1
But I want the result to be grouped by the years they played, but do not compress player names if they are from different years, like so:
name year goals
john 2010 1
john 2006 10 <--- This is compressed, but there are still 2 johns
fred 2006 1 since they are from different years
say I have done this so far.
(select name, year, goals
from table) as T
If I just do
select *
from
(select name, year, goals
from table) as T
group by year;
Fred will disappear, but if I do "group by name", there are only 1 john left. Any help?
select name, year, sum(goals) as totalgoals
from table
group by name, year

sql group by find all combinations of two columns distinct values

I have following table
ORDID EMPID ITEMCOST TIME
-------------------------------------
10023 B2690 675 1992
10024 C3467 8078 1992
10025 B2690 15481 1992
10026 C5621 22884 1992
10027 B2109 30287 1992
10030 B3297 52496 1993
10031 C3467 59899 1993
10032 F5621 67302 1993
10033 G3467 74705 1993
and so on many rows.....
I am trying to find out empid who purchased some item in each and every year.
in other words want to find out empid which exist in each and every year in that table.
BTB I am using Oracle 11g Express.
Thanks in advance.
You can do this with a having clause where you compare the number of distinct years for each empid to the number of distinct years in the data:
select empid
from followingtable
group by empid
having count(distinct time) = (select count(distinct time) from followingtable);
Below query will also work.
SELECT TAB.EMPID FROM
(
SELECT A.EMPID, COUNT(DISTINCT A.TIME) YEARCOUNT FROM MY_TABLE A GROUP BY EMPID
) TAB
WHERE TAB.YEARCOUNT = (SELECT COUNT(DISTINCT B.TIME) FROM MY_TABLE B)

Sql list display duplicates

I have a table with names and years.
Name Year
Adam 1960
Adam 1970
Adam 1980
Alex 1955
Alex 1956
Brian 1963
Cody 1959
.... ....
How can I list and display duplicates of names and years so that it shows 3 columns: name and 2 "year" columns to produce a result like:
Adam 1960 1970
Adam 1960 1980
Adam 1970 1980
Alex 1955 1956
Adam has 3 results so it appears as 3 different rows:
However in the case of Alex(2 results) it only shows one row.
The non-duplicate names do now appear.
It also needs to be sorted by left-most year value, and then right-most year value
Also, is there a way to do this without using "GROUP BY"?
Thanks
Basically, just join the tables using INNER JOIN.
SELECT a.Name, a.Year MinYear, b.Year MaxYEar
FROM TableName a
INNER JOIN TableName b
ON a.Name = b.Name AND a.Year < b.Year
SQLFiddle Demo
Can you try this solution:
SELECT t1.name, t1.age, t2.age FROM dbo.Table_1 AS t1
CROSS APPLY dbo.Table_1 AS t2
WHERE t1.name = t2.name
AND t1.age < t2.age

How to calculate the difference between values in two rows of one table using MS Access 2003 SQL? with EXTRA CRITERIA

Name ExactDate Presents
bob 2011 1
bob 2008 2
bob 2012 3
mary 1986 4
mary 2001 5
mary 2012 6
kate 2011 7
kate 2012 8
kate 2013 9
celia 2011 10
celia 1986 11
celia 1972 12
celia 2012 13
celia 1991 14
So the goal is we subtract the amount of presents kate got from celia on the same day and out put should be something like the following:
Name ExactDate Presents
celiaminuskate 2011 3
celiaminuskate 2012 5
Thank you so much I am a first time user of access and SQL . and have a data management task required of me at work. so this has really go me stuck
This is done in ms access 2003 SQL
HEY SO I GOT THE FIRST PART THERE AND NOW IT GETS HARDER ASSUMING THE DATA SET IS NOW LIKE THIS
Name ExactDate Presents Location
bob 2011 1 home
bob 2008 2 school
bob 2012 3 school
mary 1986 4 school
mary 2001 5 home
mary 2012 6 homw
kate 2011 7 home
kate 2012 8 home
kate 2011 9 school
celia 2011 10 school
celia 1986 11 school
celia 1972 12 home
celia 2012 14 home
celia 2012 13 school
So the goal is we subtract the amount of presents kate got from celia on the same year ( but since there are a few different present values for the same year we choose to have priority of home > school....for example celia and kate both recieves presents in 2012 but celia gets both home presents and school presents in 2012 in which case we choose her home present value to do the calculation) and out put should be something like the following:
Name ExactDate Presents
celiaminuskate 2011 3
celiaminuskate 2012 6
This should do it:
SELECT
'celiaminuskate' AS [NAME],
T1.[date] AS [EXACT DATE],
T1.presents - T2.presents AS [PRESENTS DIFF]
FROM
Some_Table T1
INNER JOIN Some_Table T2 ON
T2.[name] = 'kate' AND
T2.[date] = T1.[date]
WHERE
T1.[name] = 'celia'
ORDER BY
T1.[date]
A couple of suggestions since you're new to SQL:
Try to avoid using keywords, like "date" for column names
Your "date" column looks like a year, not a date. It should be named appropriately and you should make sure that it's the correct data type.
Since it sounds like the version of Access that you're using doesn't support the now standard JOIN syntax, here is another query which should be equivalent:
SELECT
'celiaminuskate' AS [NAME],
T1.[date] AS [EXACT DATE],
T1.presents - T2.presents AS [PRESENTS DIFF]
FROM
Some_Table T1, Some_Table T2
WHERE
T1.[name] = 'celia' AND
T2.[name] = 'kate' AND
T2.[date] = T1.[date]
ORDER BY
T1.[date]
T1 and T2 in this query are simply aliases for the tables in the FROM clause so that you can distinguish them.
If you're trying to put the results into another table then you will need this to be part of an INSERT statement. Or, with Access you might be able to use a query to generate a table as part of some wizard. I'm afraid that I don't have a copy handy to give more specifics. In any case, here is what the INSERT statement would look like:
INSERT INTO Some_New_Table (name, exactdate, presentsdiff)
SELECT ...
(The ellipsis just means to use the query as I have it up above)
You will need to do a self-join, because you are comparing rows from the same table.
Below we join table1 to itself using simular dates, but different names.
A more realistic answer would use unique row_ids instead of names.
Next we tell the database that we want only celia's rows in part1 and only kate's rows in part2.
SELECT 'celiaminuskate' AS useless_filler
, a.[date] AS whendidthishappen
, (celia.presents - kate.presents) AS outcome
FROM table1 AS kate
INNER JOIN table1 AS celia ON (a.[date] = b.[date] and a.name <> b.name)
WHERE celia.name = 'celia' and kate.name = 'kate'
Note that date is a reserved word and you will need to enclose it in square brackets []
The key to answering this is a self-join:
SELECT 'Celia - Kate' AS tag, C.ExactDate, C.Presents - K.Presents
FROM (SELECT ExactDate, Presents FROM AnonymousTable WHERE Name = 'celia') AS C
JOIN (SELECT ExactDate, Presents FROM AnonymousTable WHERE Name = 'kate') AS K
ON C.ExactDate = K.ExactDate
ORDER BY C.Date;
SELECT 'celiaminuskate', p1.exactdate, p1.presents - p2.presents
FROM presents p1 JOIN presents p2 ON p1.exactdate = p2.exactdate
WHERE p1.name = 'celia' AND p2.name = 'kate'