SQL Server Position of an element in table with different order - sql-server

I am using a stored procedure in SQL Server 2014 to get the position of an item.
I've read about ROW_NUMBER but I am not sure how to use it (or if I can use it at all).
I have a table containing elements with IDs and dates and I would like to know the position of an element given its ID in the table sorted by date.
Let's say for instance I have these 5 items (ID. Date) :
ID DATE
1 2016-01-04
2 2016-01-05
3 2016-01-01
4 2016-01-02
5 2016-01-03
Using my stored procedure to get the position of 3., I want it to return 5 (the actual position of 3. when the table is ordered by date desc).
Thanks !

Yes, you can use ROW_NUMBER if you want only one result if there are duplicates, or RANK if you want every row that fits with your criteria (for instance, if there is more than 1 row with 2016-01-03 value):
;WITH CTE AS
(
SELECT *, RN = ROW_NUMBER() OVER(ORDER BY [Date] DESC)
FROM dbo.YourTable
)
SELECT ID, [Date]
FROM CTE
WHERE RN = 3;

Related

Create 2 table ids, the second restarts when the first increments

I have the following table:
CREATE TABLE [dbo].[CASES]
(
[CASE_ID] INT NOT NULL,
[CASE_SECTION] INT NOT NULL,
[CASE_DATA] NVARCHAR(MAX) NOT NULL,
)
I want CASE_SECTION to increment based on whether the CASE_ID has changed.
Example:
CASE_ID CASE_SECTION CASE_DATA
---------------------------------------------
1 1 'FROG ATE THE FLY'
1 2 'FROG SAT ON LOG'
2 1 'CHEETAH CHEATAXED'
3 1 'BLUE CHEESE STINKS'
Basically, I want to do something similar to using ROW_NUMBER() OVER(PARTITION BY CASE_ID) as the CASE_DATA is inserted into the table.
Is there a way I can set the table up so that CASE_SECTION increments like this by default when data is inserted?
you can use rownumber:
Select row_number() over(partition by case_id order by case_data) as case_section, * from yourtable
If you can add either an IDENTITY or InsertedDateTime column to the table, you can use that to make Case_Section a computed column that uses row_number() partitioned by case_id.
Another poster suggested this, but if you order by case_data or any other column that isn't guaranteed to be ordinal, you run the risk that the value will move around as data is inserted and changes the order of the rows.
If your computation does row_number() over(partition by case_id order by [ColumnThatIncreasesWithEachInsert]) then the values will be stable over time.

min(count(*)) over... behavior?

I'm trying to understand the behavior of
select ..... ,MIN(count(*)) over (partition by hotelid)
VS
select ..... ,count(*) over (partition by hotelid)
Ok.
I have a list of hotels (1,2,3)
Each hotel has departments.
On each departments there are workers.
My Data looks like this :
select * from data
Ok. Looking at this query :
select hotelid,departmentid , cnt= count(*) over (partition by hotelid)
from data
group by hotelid, departmentid
ORDER BY hotelid
I can perfectly understand what's going on here. On that result set, partitioning by hotelId , we are counting visible rows.
But look what happens with this query :
select hotelid,departmentid , min_cnt = min(count(*)) over (partition by hotelid)
from data
group by hotelid, departmentid
ORDER BY hotelid
Question:
Where are those numbers came from? I don't understand how adding min caused that result? min of what?
Can someone please explain how's the calculation being made?
fiddle
The 2 statements are very different. The first query is counting the rows after the grouping and then application the PARTITION. So, for example, with hotel 1 there is 1 row returned (as all rows for Hotel 1 have the same department A as well) and so the COUNT(*) OVER (PARTITION BY hotelid) returns 1. Hotel 2, however, has 2 departments 'B' and 'C', and so hence returns 2.
For your second query, you firstly have the COUNT(*), which is not within the OVER clause. That means it counts all the rows within the GROUP BY specified in your query: GROUP BY hotelid, departmentid. For Hotel 1, there are 4 rows for department A, hence 4. Then you take the minimum of 4; which is unsurprisingly 4. For all the other hotels, they have at least 1 entry with only 1 row for a hotel and department and so returns 1.

Keep record based on condition in Access or SQL Server

I have a table with many rows that is similar to the one below where each EmployeeID is repeated twice. I simply want to sum the TotalAmount column and keep one of the rows based on the content of the Adjustment column. If the content of the Adjustment cell for an employee has a 2 for one row and an 8 for the second record, then keep sum the TotalAmount and keep the row with 2. If they have 8 and 11 then keep 8. If 7 and 8 then keep 8.
The result should look as follows:
You could use:
Select EmployeeID, StartDate, Max(Adjustment), Sum(TotalAmount)
From YourTable
Group By EmployeeID, StartDate
But that will not return 8 for ID 3 and 4. There is no logic telling why 8 should be returned from these IDs.

FInding max value from TOP selection grouped by key in SQL Server

Apologies for goofy title. I am not sure how to describe the problem.
I have a table in SQL Server with this structure;
ID varchar(15)
ProdDate datetime
Value double
For each ID there can be hundreds of rows, each with its own ProdDate. ID and ProdDate form the unique key for the table.
What I need to do is find the maximum Value for each ID based upon the first 12 samples, ordered by ProdDate ascending.
Said another way. For each ID I need to find the 12 earliest dates for that ID (the sampling for each ID will start at different dates) and then find the maximum Value for those 12 samples.
Any idea of how to do this without multiple queries and temporary tables?
You can use a common table expression and ROW_NUMBER to logically define the TOP 12 per Id then MAX ... GROUP BY on that.
;WITH T
AS (SELECT *,
ROW_NUMBER() OVER (PARTITION BY Id ORDER BY ProdDate) AS RN
FROM YourTable)
SELECT Id,
MAX(Value) AS Value
FROM T
WHERE RN <= 12
GROUP BY Id

Grouping by or iterating through partitions in SQL

Two part question regarding partitioning in SQL.
In T-SQL when you use PARTITION BY is there a way to assign a unique number to each partition, in addition to something like row_number()?
E.g. row_number() would yield,
Action Timestamp RowNum
A '2013-1-10' 1
A '2013-1-11' 2
B '2013-1-12' 1
B '2013-1-13' 2
Whereas, in addition, uniquely identifying each partition could yield,
Action Timestamp RowNum PartitionNum
A '2013-1-10' 1 1
A '2013-1-11' 2 1
B '2013-1-12' 1 2
B '2013-1-13' 2 2
Then one could GROUP BY partition number.
Second part of my question is, how can you break out each partition and iterate through it, e.g.,
for each partition p
for each row r in p
do F(r)
Any way in T-SQL?
You could use dense_rank():
select *
, row_number() over (partition by Action order by Timestamp) as RowNum
, dense_rank() over (order by Action) as PartitionNum
from YourTable
Example at SQL Fiddle.
T-SQL is not good at iterating, but if you really have to, check out cursors.

Resources