I have a SQL question. Below is my data and query
select ID from table
ID
4
4
5
3
5
3
3
What query should I add to my select list so that it gives me the occurrence of a value for each specfic row(I do not want the total count, I want something like a rank of occurrence).
4 1--this is the first time we got a 4 in the list, so 1
4 2--this is the second time we got a 4 in the list, so 2
5 1--this is the first time we got a 5 in the list, so 1
3 1--this is the first time we got a 3 in the list, so 1
5 2--this is the second time we got a 5 in the list, so 2
3 2--this is the second time we got a 3 in the list, so 2
3 3--this is the third time we got a 3 in the list, so 3
You want ROW_NUMBER():
SELECT
[Id],
ROW_NUMBER() OVER (PARTITION BY [Id] ORDER BY [Id])
FROM ...
You'll probably need to change the Order By clause to get the right output.
To generate a numbering from an order of rows, use row_number() or rank(). The problem is, row_number() does not guarantee the original order will be preserved. You could try this:
select
[id],
row_number() over (partition by id, order by (select 1)) as [rank]
from #t
However, you will find the results are not in the original order and somewhat confusing:
id rank
3 1
3 2
3 3
4 1
4 2
5 1
5 2
To preserve the original row order, you could build a temporary table or table variable with an identity column. Select a row_number() partitioned by id from there:
declare #t table ([tkey] int identity(1,1) primary key clustered, [id] int)
insert into #t (id) values (4), (4), (5), (3), (5), (3), (3)
select
[id],
row_number() over (partition by [Id] order by [tkey]) as [rank]
from #t
order by [tkey]
Note that the final order by [tkey] really is necessary. The query has the desired results:
id rank
4 1
4 2
5 1
3 1
5 2
3 2
3 3
Here is a Common Table Expression (CTE) approach. The CTE adds a row_number() to maintain the rows in the original order. (This is the equivalent of the identity column in the previous example.) The actual ranking comes with the second row_number() when it does a partition by id. This causes the 1st 4 gets 1, the 2nd 4 gets 2, etc.
The second row_number() must be ordered by the original order to rank correctly, but this is still not enough to preserve the order in the output. A final order by ensures the ending order is the same.
declare #t table (id int)
insert into #t (id) values (4), (4), (5), (3), (5), (3), (3)
;with [tRows] (rownum, id) as
(
select
row_number() over (order by (select 1)) as [rownum],
[id]
from #t
)
select
[id],
row_number() over (partition by id order by [rownum]) as [rank]
from [tRows]
order by [rownum]
This query also has the desired results:
id rank
4 1
4 2
5 1
3 1
5 2
3 2
3 3
In this example, you could use rank() instead of the second row_number(). The difference between the functions is explained well in this question. rank() would not work the same if, somehow, there were duplicate row numbers generated by the first row_number(), but that cannot happen.
Related
Have a table like this
FileID Value Version
-------------------------
1 Welle 2
1 Achse 3
2 Box 5
2 Enclosure 7
I need to "sum" up the lines with same FileID -> take highest value from column VERSION and get back the related value.
Desired result would be:
FileID Value Version
-------------------------
1 Achse 3
2 Enclosure 7
However using GROUP By sums up, but brings wrong result for Value:
SELECT
[FileID],
MAX([Value]),
MAX([Version])
FROM [ValueMist]
GROUP BY FileID
This returns:
FileID Value Version
------------------------
1 Welle 3
2 Enclosure 7
One option is WITH TIES in concert with row_number()
Example
Select top 1 with ties *
From YourTable
Order By row_number() over (partition by FileId Order By version desc)
You can achieve this by using ROW NUMBER
;WITH CTE AS (SELECT ROW_NUMBER() OVER ( PARTITION BY
ID ORDER BY VERSION DESC) AS RW
FROM TABLE)
SELECT * FROM CTE
WHERE RW=1
I have query returning few rows. There is column with consecutive numbers and nulls in it.
For example, it has values from 1-10 then 5 nulls, then from 16-30 and then 10 nulls, then from 41-45 and so on.
I need to update that column or create another column to create groupId for consecutive columns.
Meaning as per above example, for rows 1-10, groupID can be 1. Then for 5 nulls nothing and then from 16-30 groupId can be 2. Then for 10 nulls nothing. Then from 41-45 groupId can be 3 and so on.
Please let me know
This was a fun one. Here is the solution with a simple table that contains just integers, but with gaps.
create table n(v int)
insert n values (1),(2),(3),(5),(6),(7),(9),(10)
select n.*, g.group_no
from n
join (
select row_number() over (order by low.v) group_no, low.v as low, min(high.v) as high
from n as low
join n as high on high.v>low.v
and not exists(select * from n h2 where h2.v=high.v+1)
where not exists(select * from n l2 where l2.v=low.v-1)
group by low.v
) g on g.low<=n.v and g.high>=n.v
Result:
v group_no
1 1
2 1
3 1
5 2
6 2
7 2
9 3
10 3
Typical island & gap solution
select col, grp = dense_rank() over (order by grp)
from
(
select col, grp = col - dense_rank() over (order by col)
from yourtable
) d
I'm trying to select randomly few rows for each Id stored in one table where these Ids have multiple rows on this table. It's difficult to explain with words, so let me show you with an example :
Example from the table :
Id Review
1 Text11
1 Text12
1 Text13
2 Text21
3 Text31
3 Text32
4 Text41
5 Text51
6 Text61
6 Text62
6 Text63
Result expected :
Id Review
1 Text11
1 Text13
2 Text21
3 Text32
4 Text41
5 Text51
6 Text62
In fact, the table contains thousands of rows. Some Ids contain only one Review but others can contain hundreds of reviews. I would like to select 10% of these, and select at least once, all rows wich have 1-9 reviews (I saw the SELECT TOP 10 percent FROM table ORDER BY NEWID() includes the row even if it's alone)
I read some Stack topics, I think I have to use a subquery but I don't find the correct solution.
Thanks by advance.
Regards.
Try this:
DECLARE #t table(Id int, Review char(6))
INSERT #t values
(1,'Text11'),
(1,'Text12'),
(1,'Text13'),
(2,'Text21'),
(3,'Text31'),
(3,'Text32'),
(4,'Text41'),
(5,'Text51'),
(6,'Text61'),
(6,'Text62'),
(6,'Text63')
;WITH CTE AS
(
SELECT
id, Review,
row_number() over (partition by id order by newid()) rn,
count(*) over (partition by id) cnt
FROM #t
)
SELECT id, Review
FROM CTE
WHERE rn <= (cnt / 10) + 1
Result(random):
id Review
1 Text12
2 Text21
3 Text31
4 Text41
5 Text51
6 Text63
So I have a table that has two records that need to be one. I can identify them but I want to update them in groups (sort of like a scan update =1, then proceed, then some other field changes, increment the number by 1 and proceed.)
Example table:
IDEvent 1 2 3 4 5
Col1 1 1 0 1 0
Col2 a a b a b
So essentially, my outcome would look like this afterwards so that I can write a select and group by col1 to then group the two first records into one but leave non consecutive record alone. I tried while loops but I couldn't figure it out.
IDEvent 1 2 3 4 5
Col1 1 1 0 2 0
Col2 A A B A B
alter view PtypeGroup as
WITH q AS
(
SELECT *,
ROW_Number() OVER (PARTITION BY idsession, comment ORDER BY ideventrecord) AS rnd,
ROW_NUMBER() OVER (PARTITION BY idsession ORDER BY ideventrecord) AS rn
FROM [ratedeventssorted]
)
SELECT min(ideventrecord) as IDEventRecord, idsession, min(distancestamp) as distancestamp, sum(length) as length, min(comment) as comment2, min(eventscorename) as firstptype, min(eventscoredescription) as Ptype2,
MIN(ideventrecord) AS first_number,
MAX(ideventrecord) AS last_number,
comment
,COUNT(ideventrecord) AS numbers_count
--into test
FROM q
where eventscorename IN ('Flex', 'Chpsl')
GROUP BY idsession,
rnd - rn,
comment
I'm banging my head here. I feel pretty stupid because I'm sure I've done something like this before, but can't for the life of me remember how. One of those days I guess >.<
Say I have the following data: ---> and a query which returns this: ---> But I want this:
ID FirstID ID FirstID ID FirstID
-- ------- -- ------- -- -------
1 1 1 1 7 1
2 1 3 3 3 3
3 3 4 4 6 4
4 4 5 5 5 5
5 5
6 4
7 1
Notice that my query returns the records where ID = FirstID, but I want it to return the Max(ID) for each subset of unique FirstID. Sounds simple enough right? That's what I thought, but I keep getting back just record #7. Here's my query (the one that returns the second block of figures above) with some test code to make your life easier. I need this to give me the results in the far right block. It should be noted that this is a self-joining table where FirstID is a foreign key to ID. Thanks :)
declare #MyTable table (ID int, FirstID int)
insert into #MyTable values (1,1),(2,1),(3,3),(4,4),(5,5),(6,4),(7,1)
select ID, FirstID
from #MyTable
where ID = FirstID
Does this work
declare #MyTable table (ID int, FirstID int)
insert into #MyTable values (1,1),(2,1),(3,3),(4,4),(5,5),(6,4),(7,1)
Select FirstID, Max (Id) ID
From #MyTable
Group BY FirstID
Results in
FirstID ID
----------- -----------
1 7
3 3
4 6
5 5
With SQL2005 and later SQL2008 versions the Aggregate functions in SQL Server have been improved
You can use PARTITION BY clause for example with MAX,MIN,SUM,COUNT functions
Please try the following example
select
Distinct FirstID, Max(ID) OVER (PARTITION BY FirstID) MaxID
from #MyTable
You can find an example at http://www.kodyaz.com/t-sql/sql-count-function-with-partition-by-clause.aspx
Upon your comment, I modified the same query just to provide the exact output in order of rows and columns as follows
select Distinct
Max(ID) OVER (PARTITION BY FirstID) ID,
FirstID
from #MyTable
order by FirstID