How to create an internal numbering of occurrences with SQL - sql

How can I create a new column (inCount) with numbering of occurrences in a specific column?
Here is an example:
id name inCount
1 Orly 1
2 Ernest 1
3 Rachel 1
4 Don 1
5 Don 2
6 Ernest 2
7 Angela 1
8 Ernest 3
9 David 1
10 Rachel 2
11 Sully 1
12 Sully 2
13 Rachel 3
14 David 2
15 David 3
16 Kevin 1
17 Kevin 2
18 Orly 2
19 Angela 2
20 Sully 3
21 Kevin 3
22 Don 3
23 Orly 3
24 Angela 3
Don from id 5 is numbered 2 because Don appears in id 4 too.
Don from id 22 is numbered 3 due to the above preceding occurrences.
I use MS SQL SERVER 2008 R2 Express edition.
Thanks.

You could use partition by, like:
select row_number() over (partition by name order by id) as inCount
, *
from YourTable
order by
id

This should work
SELECT id, Name, ROW_NUMBER() OVER(PARTITION BY Name ORDER BY id)
FROM table
ORDER BY id
EDIT: Added order by clause on the select in order to show results in same order indicated by OP. The ORDER BY in the ROW_NUMBER did not change the outcome, but I changed to id as it will keep the row_number correct for the sample data.

Related

SQL Temp table Array to perfrom rolling caluclations

I wish to use some sort of SQL array to subtract values from a certain row (QTYOnHand) that decreases that row value every time and throws it into a rolling calculation for the other rows. I've been thinking of some sort of Self Join/Temp Table solution, but not sure how to formulate. Also, All the results will be partitioned by the ItemID below. Help would be appreciated.
Here's some data, If I do a simple row by row subtraction I will get this: 17-3 = 14, 17-5 = 12 and so on.
(Item_ID) (ItemQty) (QTYOnHand) (QtyOnHand - ItemQty)
123 3 17 14
123 5 17 12
123 4 17 13
456 7 12 5
456 8 12 4
456 2 12 10
456 3 12 9
789 2 6 4
789 2 6 4
789 2 6 4
These are the results that I want, where I subtract every next value from the new QTYOnHand-ItemQty column value. Looks like 17-3 then 14 -5 then 9 -4 for Item_ID (123):
(Item_ID) (ItemQty) (QTYOnHand) (QtyOnHand - ItemQty)
123 3 17 14
123 5 17 9
123 4 17 5
456 7 12 5
456 8 12 -3
456 2 12 -5
456 3 12 -8
789 2 6 4
789 2 6 2
789 2 6 0
try the following:
;with cte as
(
select *, ROW_NUMBER() over (partition by Item_ID order by Item_ID) rn
from YourTable
)
, cte2 as
(
select Item_ID, ItemQty, QTYOnHand, Case when rn = 1 then QTYOnHand else 0 end - ItemQty as calc, rn
from cte
)
select Item_ID, ItemQty, QTYOnHand, sum(calc) over (partition by Item_ID order by rn) as [QtyOnHand - ItemQty]
from cte2 t1
Please find the db<>fiddle here.

Distinguish the first rows where a given column's value changes in a grouped result

I want to create a select query in SQL Server where I group the rows by a column (BaseId) and also order them by Status, RTime and Version. I want to add a column "isFirst" that has the value 1 if the BaseId value is the first in the group, and 0 if it's not.
My sample table:
Table name: Head
Id BaseId Name RTime Status Version
2 2 abc 04-12 12:34 1 1
3 3 xyz 04-12 13:10 9 1
4 2 abc 04-13 14:25 0 2
5 3 xyz 04-14 12:34 0 2
6 3 xyz 04-14 13:10 9 3
7 3 xyz 04-16 14:25 1 4
8 2 abc 04-16 17:40 1 3
9 9 sql 04-17 02:23 9 1
10 9 sql 04-17 07:31 0 2
Expected result:
isFirst Id BaseId Name RTime Status Version
1 10 9 sql 04-17 07:31 0 2
0 9 9 sql 04-17 02:23 9 1
1 5 3 xyz 04-14 12:34 0 2
0 7 3 xyz 04-16 14:25 1 4
0 6 3 xyz 04-14 13:10 9 3
0 3 3 xyz 04-12 13:10 9 1
1 4 2 abc 04-13 14:25 0 2
0 8 2 abc 04-16 17:40 1 3
0 2 2 abc 04-12 12:34 1 1
My query now looks like this:
SELECT *
FROM Head
ORDER BY BaseId desc, Status, RTime desc, Version desc
I think I should use CASE to create the isFirst column, but I've had no luck so far. Anyone could help me?
You can use row_number() and a case expression:
select
case when row_number() over(
partition by BaseId
order by Status, RTime desc, Version desc
) = 1
then 1
else 0
end isFirst,
h.*
from head h
order by BaseId desc, Status, RTime desc, Version desc

Running total of rows by ID

I have a list of IDs, transactions, and the date of those transactions. I want to create a count of each transaction within each ID.
The starting table I have is looks something like this:
id trxn_dt trxn_amt
1 10/31/2014 58
1 11/9/2014 34
1 12/10/2014 12
2 7/8/2014 78
2 11/20/2014 99
3 1/5/2014 120
4 2/17/2014 588
4 2/18/2014 8
4 3/9/2014 65
4 4/25/2014 74
and I want the end result to look something like this:
id trxn_dt trxn_amt trxn_count
1 10/31/2014 58 1
1 11/9/2014 34 2
1 12/10/2014 12 3
2 7/8/2014 78 1
2 11/20/2014 99 2
3 1/5/2014 120 1
4 2/17/2014 588 1
4 2/18/2014 8 2
4 3/9/2014 65 3
4 4/25/2014 74 4
Count(distinct(id)) would only give me the overall number of distinct IDs and not a running total by each ID that restarts at each new ID.
Thank you!
In SQL-Server you can use ROW_NUMBER in following:
SELECT id,
trxn_dt,
trxn_amt,
ROW_NUMBER() OVER(PARTITION BY Id ORDER BY Id, trxn_dt) AS trxn_count
FROM StarningTable
In MySQL you can do in following:
SELECT
t.id,
t.trxn_dt,
t.trxn_amt,
#cur:= IF(id=#id, #cur+1, 1) AS RowNumber,
#id := id
FROM
StarningTable t
CROSS JOIN
(SELECT #id:=(SELECT MIN(id) FROM StarningTable t), #cur:=0) AS init
ORDER BY
t.id
using Row_number we can achieve this
Select *,
ROW_NUMBER()OVER(PARTITION BY id ORDER BY (SELECT NULL))trxn_count
from Transactions

Access SQL - Select only the last sequence

I have a table with an ID and multiple informative columns. Sometimes however, I can have multiple data for an ID, so I added a column called "Sequence". Here is a shortened example:
ID Sequence Name Tel Date Amount
124 1 Bob 873-4356 2001-02-03 10
124 2 Bob 873-4356 2002-03-12 7
124 3 Bob 873-4351 2006-07-08 24
125 1 John 983-4568 2007-02-01 3
125 2 John 983-4568 2008-02-08 13
126 1 Eric 345-9845 2010-01-01 18
So, I would like to obtain only these lines:
124 3 Bob 873-4351 2006-07-08 24
125 2 John 983-4568 2008-02-08 13
126 1 Eric 345-9845 2010-01-01 18
Anyone could give me a hand on how I could build a SQL query to do this ?
Thanks !
You can calculate the maximum sequence using group by. Then you can use join to get only the maximum in the original data.
Assuming your table is called t:
select t.*
from t join
(select id, MAX(sequence) as maxs
from t
group by id
) tmax
on t.id = tmax.id and
t.sequence = tmax.maxs

Retrieve top 48 unique records from database based on a sorted Field

I have database table that I am after some SQL for (Which is defeating me so far!)
Imagine there are 192 Athletic Clubs who all take part in 12 Track Meets per season.
So that is 2304 individual performances per season (for example in the 100Metres)
I would like to find the top 48 (unique) individual performances from the table, these 48 athletes are then going to take part in the end of season World Championships.
So imagine the 2 fastest times are both set by "John Smith", but he can only be entered once in the world champs. So i would then look for the next fastest time not set by "John Smith"... so on and so until I have 48 unique athletes..
hope that makes sense.
thanks in advance if anyone can help
PS
I did have a nice screen shot created that would explain it much better. but as a newish user i cannot post images.
I'll try a copy and paste version instead...
ID AthleteName AthleteID Time
1 Josh Lewis 3 11.99
2 Joe Dundee 4 11.31
3 Mark Danes 5 13.44
4 Josh Lewis 3 13.12
5 John Smith 1 11.12
6 John Smith 1 12.18
7 John Smith 1 11.22
8 Adam Bennett 6 11.33
9 Ronny Bower 7 12.88
10 John Smith 1 13.49
11 Adam Bennett 6 12.55
12 Mark Danes 5 12.12
13 Carl Tompkins 2 13.11
14 Joe Dundee 4 11.28
15 Ronny Bower 7 12.14
16 Carl Tompkin 2 11.88
17 Nigel Downs 8 14.14
18 Nigel Downs 8 12.19
Top 4 unique individual performances
1 John Smith 1 11.12
3 Joe Dundee 4 11.28
5 Adam Bennett 6 11.33
6 Carl Tompkins 2 11.88
Basically something like this:
select top 48 *
from (
select athleteId,min(time) as bestTime
from theRaces
where raceId = '123' -- e.g., 123=100 meters
group by athleteId
) x
order by bestTime
try this --
select x.ID, x.AthleteName , x.AthleteID , x.Time
(
select rownum tr_count,v.AthleteID AthleteID, v.AthleteName AthleteName, v.Time Time,v.id id
from
(
select
tr1.AthleteName AthleteName, tr1.Time time,min(tr1.id) id, tr1.AthleteID AthleteID
from theRaces tr1
where time =
(select min(time) from theRaces tr2 where tr2.athleteId = tr1.athleteId)
group by tr1.AthleteName, tr1.AthleteID, tr1.Time
having tr1.Time = ( select min(tr2.time) from theRaces tr2 where tr1.AthleteID =tr2.AthleteID)
order by tr1.time
) v
) x
where x.tr_count < 48