I have a list of multiple components that all have a model number. I want to group every second component based on the model it belongs to.
Model | Component | Group
1 1 1
1 2 2
1 3 1
1 4 2
1 5 1
2 1 1
2 2 2
2 3 1
Every second component belonging to a model should have an alternative group number.
I believe I have to use a windows function but haven't been able to solve.
I have assumed that your Model and Component ID numbers will not be perfectly incremental, but that they will be unique. As such, you can use the row_number windowed function along with the modulo operator % to get the remainder of the division of the row_number result by 2:
declare #t table (Model int, Component int);
insert into #t values (1,1),(1,2),(1,3),(1,4),(1,5),(2,1),(2,2),(2,2);
select Model
,Component
,case (row_number() over (partition by Model order by Component) % 2)
when 1 then 1
when 0 then 2
end as [Group]
from #t;
Output:
+-------+-----------+-------+
| Model | Component | Group |
+-------+-----------+-------+
| 1 | 1 | 1 |
| 1 | 2 | 2 |
| 1 | 3 | 1 |
| 1 | 4 | 2 |
| 1 | 5 | 1 |
| 2 | 1 | 1 |
| 2 | 2 | 2 |
| 2 | 2 | 1 |
+-------+-----------+-------+
Related
I want to flag only the first duplicate ID-VL combination in the dataset shown below. Column FirstOccurence is what I want the end result to be.
ID VL FirstOccurence
1 a 1
1 b 1
2 a 1
2 a 0
3 a 1
3 a 0
4 a 1
4 a 0
5 a 1
5 b 1
5 a 0
There is currently not a unique index available in the original table.
Is there any way to do this with for instance the LAG-functionality? I cannot find any examples online that result in the flagging of duplicates. Any suggestions are much appreciated!
Kind regards,
Igor
One method is with ROW_NUMBER() along with a CASE expression:
SELECT
ID
,VL
,CASE ROW_NUMBER() OVER(PARTITION BY ID, VL ORDER BY ID, VL) WHEN 1 THEN 1 ELSE 0 END AS FirstOccurance
FROM dbo.example
ORDER BY
ID
,VL
,FirstOccurance;
Results:
+----+----+----------------+
| ID | VL | FirstOccurance |
+----+----+----------------+
| 1 | a | 1 |
| 1 | b | 1 |
| 2 | a | 0 |
| 2 | a | 1 |
| 3 | a | 0 |
| 3 | a | 1 |
| 4 | a | 0 |
| 4 | a | 1 |
| 5 | a | 0 |
| 5 | a | 1 |
| 5 | b | 1 |
+----+----+----------------+
Note that this result order differs from your end result. If there are one or more columns present in the table that provide the same ordering as the results in you question, specify that in the ORDER BY clause instead.
I have client ids and their dates of login. i want to calculate the week number with respect to their first login date
i am fairly new to sql
Demo output
ClientID Date of login Week Number
1 2019-12-20 1
1 2019-12-21 1
1 2019-12-21 1
1 2019-12-22 1
1 2019-12-29 2
1 2019-12-29 2
2 2020-01-27 1
2 2020-01-28 1
2 2020-02-05 2
2 2020-02-06 2
2 2020-02-16 3
This is very trivial date arithmetic that just requires the min DateOfLogin for each ClientID, which you can find with a windowed function.
Calculate the datediff in days between this date and the current DateOfLogin, integer divide by 7 (to return no fractional days) and then add 1 to correctly offset the WeekNum value:
declare #l table(ClientID int, DateOfLogin date);
insert into #l values(1,'2019-12-20'),(1,'2019-12-21'),(1,'2019-12-21'),(1,'2019-12-22'),(1,'2019-12-29'),(1,'2019-12-29'),(2,'2020-01-27'),(2,'2020-01-28'),(2,'2020-02-05'),(2,'2020-02-06'),(2,'2020-02-16');
select ClientID
,DateOfLogin
,(datediff(day,min(DateOfLogin) over (partition by ClientID),DateOfLogin) / 7) + 1 as WeekNum
from #l;
Output
+----------+-------------+---------+
| ClientID | DateOfLogin | WeekNum |
+----------+-------------+---------+
| 1 | 2019-12-20 | 1 |
| 1 | 2019-12-21 | 1 |
| 1 | 2019-12-21 | 1 |
| 1 | 2019-12-22 | 1 |
| 1 | 2019-12-29 | 2 |
| 1 | 2019-12-29 | 2 |
| 2 | 2020-01-27 | 1 |
| 2 | 2020-01-28 | 1 |
| 2 | 2020-02-05 | 2 |
| 2 | 2020-02-06 | 2 |
| 2 | 2020-02-16 | 3 |
+----------+-------------+---------+
This query returns the week number.
select DATENAME(WW, '2019-12-20')
This is for MSSQL.
Here might be a solution for you, you'll maybe just have to look at the way you are going to do the insert and maybe optimize it a bit better.
select 1 AS 'ClientID', '2019-12-20' AS 'LogInDate', 1 AS 'Week'
into #test
insert into #test
select top(1) 1, '2020-02-05', case DATEDIFF(week,'2020-02-05',LogInDate) when 0 then week else Week +1 end from #test where ClientID = 1 order by LogInDate desc
I have a parent and child table like the following:
Parent Table
CourseId | CourseName
1 | MVC training
and the
Child Table
Id | StudentId | CourseId | AttnDate
1 | 33 | 1 | 6/1/2019
2 | 33 | 1 | 6/2/2019
3 | 33 | 1 | 6/3/2019
4 | 34 | 1 | 6/1/2019
5 | 34 | 1 | 6/2/2019
6 | 34 | 1 | 6/3/2019
I searched over google to use rownumber to make this but could not make it.
No idea
I want the final result like the following table. What I need is to change the 33 to 1 and 34 to 2:
Id | StudentId | CourseId | AttnDate
1 | 1 | 1 | 6/1/2019
2 | 1 | 1 | 6/2/2019
3 | 1 | 1 | 6/3/2019
4 | 2 | 1 | 6/1/2019
5 | 2 | 1 | 6/2/2019
6 | 2 | 1 | 6/3/2019
Try this using DENSE_RANK()
SELECT Id,
DENSE_RANK()OVER( ORDER BY StudentId) AS StudentId,
CourseId,
AttnDate
FROM Parent p
INNER JOIN Child c ON c.CourseId = p.CourseId
ORDER bY p.ID
Why do you need to "change the 33 to 1 and 34 to 2"? Is it for the purpose of assigning unique rank number for each distinct row within the partition (data grouped by StudentId)?
If it's true, then SQL Server DENSE_RANK ranking function is what you need
SELECT *,
DENSE_RANK() OVER(ORDER BY c.StudentId) AS RowNumberRank -- here is your rank number (StudentId in your final result)
FROM Child c
I looking for some grouping using datetime daily rows to build date range intervals
My table is something like:
id | A | B | Date
1 | 1 | 2 | 1/10/2010
2 | 1 | 2 | 2/10/2010
3 | 1 | 2 | 3/10/2010
4 | 1 | 3 | 4/10/2010
5 | 1 | 3 | 5/10/2010
6 | 1 | 2 | 6/10/2010
7 | 1 | 2 | 7/10/2010
8 | 1 | 2 | 8/10/2010
My first try was:
SELECT A, B, MIN(DATE), MAX(date)
FROM table
GROUP BY A, B
So after group by A, B and use min and max with date on my select, I get invalid results due the repetition of B = 2.
A B Date A B min(Date) max(Date)
1 | 1 | 2 | 1/10/2010 1 2 | 1/10/2010 8/10/2010
2 | 1 | 2 | 2/10/2010 Invalid
3 | 1 | 2 | 3/10/2010 ------->
6 | 1 | 2 | 6/10/2010
7 | 1 | 2 | 7/10/2010
8 | 1 | 2 | 8/10/2010
I'm looking for how to calculate the third member of the group by...
So the expected intervals results:
A B Start Date End Date
.. | 1 | 2 | 1/10/2010 | 3/10/2010
.. | 1 | 3 | 4/10/2010 | 5/10/2010
.. | 1 | 2 | 6/10/2010 | 8/10/2010
I need to support SQL Server 2008
Thank you in advance for your help
The following is an easy way to deal with "islands and gaps" where you need to find gaps in consecutive dates:
SELECT A, B, StartDate = MIN([Date]), EndDate = MAX([Date])
FROM
(
SELECT *,
RN = DATEDIFF(DAY, 0, [Date]) - ROW_NUMBER() OVER (PARTITION BY A, B ORDER BY [Date])
FROM myTable
) AS T
GROUP BY A, B, RN;
To break it down into slightly simpler-to-understand logic: you assign each date a number (DATEDIFF(DAY, 0, [Date]) here) and each date a row number (partitioned by A and B here), then any time there's a gap in the dates, the difference between those two will change.
There are a variety of resources you can use to understand different approaches to "islands and gaps" problems. Here is one that might help you with tackling other varieties of this in the future: https://www.red-gate.com/simple-talk/sql/t-sql-programming/the-sql-of-gaps-and-islands-in-sequences/
we are facing a strange behaviour in SQLite (Version 3).
We have a table for Vehicles with two columns referencing an engine and a gear.
Of course there could be more than one vehicle with the same engine gear combination.
I now want to find the distinct combination of engines and gears of the vehicles (and use it for an insert => thats why randomblob(36)).
Example:
Vehicle | EngineId | GearId
-----------------------------
1 | 1 | 1
1 | 1 | 2
1 | 2 | 1
1 | 2 | 2
1 | 1 | 2
1 | 1 | 2
The following select statement results in too many rows:
Select randomblob(36), tmp.EngineId, tmp.GearId from (Select distinct EngineId, GearId from tblVehicle order by EngineId, GearId) as tmp;
RandomId| EngineId | GearId
-----------------------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 2 | 2
5 | 1 | 2
6 | 1 | 2
But the expected result would just be:
RandomId| EngineId | GearId
-----------------------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 2 | 2
If I replace the randomblob(36) with a constant, the result is as expected (of course without a random Id).
Select 2, tmp.EngineId, tmp.GearId from (Select distinct EngineId, GearId from tblVehicle order by EngineId, GearId) as tmp;
Can someone explain me this behaviour of SQLite? Is this the expected behaviour?
This is a bug.
I can reproduce this with SQLite 3.6.23.1 but not with 3.7.15, so it has been fixed already.