Partition data into subgroups based on bit fields - sql-server
I have the first 4 columns of data, and I wan't to use the Ranking functions in the SQL 2008 R2 to derive the fifth column. What's the best way to partition the data into subgroups based on the nextiteminsubgroup and previousiteminsubgroup fields?
Group OrderInGroup NextItemInSubGroup PreviousItemInSubGroup SubGroup
1 1 1 0 1
1 2 1 1 1
1 3 1 1 1
1 4 0 1 1
1 5 0 0 2
1 6 0 0 3
1 7 1 0 4
1 8 1 1 4
1 9 0 1 4
2 1 0 0 1
2 2 0 0 2
2 3 0 0 3
2 4 1 0 4
2 5 0 1 4
3 1 0 0 1
4 1 0 0 1
4 2 0 0 2
4 3 0 0 3
A recursive CTE solution:
DECLARE #t TABLE
([Group] INT
,OrderInGroup INT
,NextItemInSubGroup INT
,PreviousItemInSubGroup INT
,SubGroup INT
)
INSERT #t
VALUES
(1,1,1,0,1),(1,2,1,1,1),(1,3,1,1,1),(1,4,0,1,1),(1,5,0,0,2),(1,6,0,0,3),
(1,7,1,0,4),(1,8,1,1,4),(1,9,0,1,4),(2,1,0,0,1),(2,2,0,0,2),(2,3,0,0,3),
(2,4,1,0,4),(2,5,0,1,4),(3,1,0,0,1),(4,1,0,0,1),(4,2,0,0,2),(4,3,0,0,3)
;WITH recCTE
AS
(
SELECT [Group], OrderInGroup,NextItemInSubGroup , PreviousItemInSubGroup, 1 AS subgroup
FROM #t
WHERE OrderInGroup = 1
UNION ALL
SELECT r.[Group], t.OrderInGroup,t.NextItemInSubGroup , t.PreviousItemInSubGroup,
CASE WHEN r.NextItemInSubGroup = 1 THEN r.subgroup ELSE r.subgroup + 1 END
FROM recCTE AS r
JOIN #t AS t
ON t.[Group] = r.[Group]
AND t.OrderInGroup = r.OrderInGroup + 1
)
SELECT * FROM recCTE
ORDER BY [Group],OrderInGroup ;
P.S. it's best practice to avoid using SQL keywords (e.g. GROUP) as table/column names
Seems like 0 and 0 restart the ranking.
Select
Rank() Over (
Partition By
[Group]
, Case When [NextItemInSubGroup] + [PreviousItemInSubGroup] = 0
Then 0
Else 1
End
Order By [OrderInGroup]
) as [SubGroup]
From Your_Table;
Related
Formulating Code and SQL Query
I have a Table in DB named 'Retail' CustomerID Itemset 1 1 1 3 1 7 2 6 2 7 3 4 ... ... I want to write this table in Datatable 'Matrix' where the Rows are Itemset={1,2,3,4,5,6....,k} and Columns are CustomerID={1,2,3,4,...,x} and the rows are 1 if the 'Itemset' belongs to the CustomerID. The output I want is like.. 1 2 3 4 5 6 7 ............. x 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 2 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 3 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 4 5 6 /And so on! 7 8 9 ` I tried to code it but the problem is in VS Parameters for SQL Query don't work with Loops. This is my code- objConnection.Open() Dim matrix As DataTable = New DataTable("Retail") intcount = 0 For intcount = 1 To noofCustomerID_col matrix.Columns.Add(intcount, GetType(Integer)) Next Dim i As Integer Dim workRow As DataRow Dim Boolin As Boolean For i = 1 To 9 ObjCommand.CommandText = "Select count(*) from Retail Where CustomerID=#in and Itemset=#in" ObjCommand.Parameters.AddWithValue("#in", i) {{I Get Error here as I can't Loop Parameters}} Boolin = ObjCommand.ExecuteScalar() workRow = matrix.NewRow() workRow(0) = i workRow(1) = Boolin matrix.Rows.Add(workRow) Next Kindly Help. I know this code can completely be wrong and it's okay if you can suggest totally different way of doing it. I've been stuck for quite some time now! Thanks. If any clarification is needed I shall explain as many times needed in the comments.
Like Tab Alleman suggested, SQL PIVOT can come handy here. Dynamic SQL is also needed. DECLARE #DynamicColumn NVARCHAR(MAX), #DynamicQuery NVARCHAR(MAX) SELECT #DynamicColumn = SELECT '[' + CONVERT(NVARCHAR, CustomerID) + '],' FROM Retail AS Customer ORDER BY CustomerID FOR XML PATH('') SELECT #DynamicColumn = SUBSTRING(#DynamicColumn, 0, DATALENGTH(#DynamicColumn) / 2)--REMOVE EXTRA "," SELECT #DynamicQuery = 'SELECT * FROM ( SELECT CustomerID, ItemSet FROM Retail) AS D PIVOT ( COUNT([CustomerID]) FOR Itemset IN (' + #DynamicQuery + ') ) AS P' EXECUTE(#DynamicQuery)
Get Min and Max Dates from SQL Server SQL
Data in my table looks like this PAY_END_DT Sal 10/27/2013 0 11/10/2013 0 11/24/2013 2473.14 12/08/2013 0 01/19/2014 0 02/02/2014 0 02/16/2014 0 My desired result should be like as below 10/27/2013 11/10/2013 12/08/2013 02/16/2014 I need a SQL to generate this result set.. please help
SELECT employee_id, MIN(pay_end_dt) AS island_min_pay_end_dt, MAX(pay_end_dt) AS island_max_pay_end_dt FROM ( SELECT pay_end_dt, ROW_NUMBER() OVER (PARTITION BY employee_id, ORDER BY pay_end_dt ) AS full_set_ordinal, ROW_NUMBER() OVER (PARTITION BY employee_id, sal ORDER BY pay_end_dt ) AS zero_set_ordinal FROM yourTable ) AS sorted_set WHERE sal = 0 GROUP BY employee_id, full_set_ordinal - zero_set_ordinal ; Using your data as an example: PAY_END_DT Sal FULL_SET_ORIDINAL ZERO_SET_ORDINAL "FULL - ZERO" 10/27/2013 0 1 1 0 11/10/2013 0 2 2 0 11/24/2013 2473.14 3 1 2 12/08/2013 0 4 3 1 01/19/2014 0 5 4 1 02/02/2014 0 6 5 1 02/16/2014 0 7 6 1 Which then allows us to include only the rows WHERE sal = 0 and then GROUP BY "FULL - ZERO" to get our two sets, and then finally apply the MIN() and MAX() functions. As stated in a comment, this is known as "Gaps and Islands". 1 1 1 1 0 0 0 0 0 1 2 3 4 5 6 7 8 9 - ordinal from the whole set 1 2 3 4 - ordinal from just the "islands" 1 2 3 4 5 - ordinal from just the "gaps" 2 2 2 3 - ordinal of the "islands" (whole_set_id - islands_id) 0 0 3 4 4 - ordinal of the "gaps" (whole_set_id - gaps_id)
;) SELECT "10/27/2013 11/10/2013" UNION SELECT "12/08/2013 02/16/2014"
A group by challenge
Let's say I have this table MyTbl Record Id_try Id Type IsOk DateOk 1 1 MYDB00125 A 0 NULL 2 1 MYDB00125 B 1 2012-07-19 20:10:05.000 3 1 MYDB00125 A 0 2012-07-25 14:10:05.000 4 2 MYDB00125 A 0 2012-07-19 22:10:05.000 5 1 MYDB00254 B 0 2012-07-19 22:10:05.000 6 1 MYDB00254 A 0 NULL 7 3 MYDB00125 A 1 2012-07-19 22:15:05.000 8 3 MYDB00125 B 1 2012-07-19 22:42:53.000 9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0 10 1 MYDB00323 C 0 NULL And I want a group by that brings me for each Id and Type my last "Id_Try Record". SELECT Id, MAX(Id_Try), MyTbl.Type, IsOK, MAX(DateOk) from MyTbl GROUP BY Id, MyTbl.Type, IsOK Won't do, because It'll bring me the last Id_Try AND the last date (Date of record 3 in the example). And I don't care if its the last date or not, I need the date of the last Id_Try. Is this only solved by a subselect? or a having clause could do? This is the result expected: Record Id_try Id Type IsOk DateOk 5 1 MYDB00254 B 0 2012-07-19 22:10:05.000 6 1 MYDB00254 A 0 NULL 7 3 MYDB00125 A 1 2012-07-19 22:15:05.000 8 3 MYDB00125 B 1 2012-07-19 22:42:53.000 9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0 10 1 MYDB00323 B 0 NULL
I think you will need to break this into two pieces: with maxIDTry as ( SELECT MAX(Id_try) as maxId, ID FROM MyTable GROUP BY ID ) SELECT * FROM MyTable as mt INNER JOIN maxIDTry as max ON mt.id_try = max.maxId AND mt.id = max.id
I think you want this: select * FROM ( select *, row_number() over (partition by id,type order by Id_try desc) as position from mytbl ) foo where position = 1 order by record http://www.sqlfiddle.com/#!3/95742/5 Your sample result set lists 9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0 10 1 MYDB00323 A 0 NULL But that doesn't make sense since you're saying the ID and the Id_try have the same value. I assume you meant for Id_try to be 2 maybe? Otherwise I think my results match up.
Hope this helps. SELECT A.Record, A.Id_try, A.Id, A.Type, A.IsOk, A.DateOk FROM MyTbl A INNER JOIN ( SELECT MAX(Id_Try) Id_Try, Id, B1.Type from MyTbl B1 GROUP BY Id, B1.Type) AS B ON A.Id_Try = B.Id_Try AND A.Id = B.Id AND A.Type = B.Type ORDER BY A.RECORD
how to acomplish a full series in sql
I want to achieve a full numeric scale from 0 to the max number in the table. Let's say we have a table T with two fields named x and y select x,y from t would show us lets say the results X Y 3 11 5 23 7 45 9 1 10 34 I found this query to build sequential numbers: With T_Misparim As (Select 1 N Union All Select N+1 N From T_Misparim Where N<1000) Select N From T_Misparim Option (MaxRecursion 0); from this source : http://www.sqlserver.co.il/?p=3296 My bottom line is, how do i integrate the two queries into a single query to give right outer join : N X Y 0 null 0 1 null 0 2 null 0 3 3 11 4 null 0 5 5 23 6 null 0 7 7 45 8 null 0 9 9 1 10 10 34
You can just LEFT JOIN with the ordinal number CTE; select 3 as X, 11 as Y into #TEST insert #TEST values (5,23),(7,45),(9,1),(10,34) ;with NUMS(n) as ( select 0 union all select 1 + n from NUMS where n < 50 ) select NUMS.n N, T.X, isnull(T.Y, 0) Y from NUMS left join #TEST T on (T.X = NUMS.n) option (maxrecursion 50) For N X Y 0 NULL 0 1 NULL 0 2 NULL 0 3 3 11 4 NULL 0 5 5 23 6 NULL 0 7 7 45 8 NULL 0 9 9 1 10 10 34
SQL Server 2008 problem
I have table in following structure... ReturnID SumbitID Status 1 1 1 1 NULL 2 2 2 3 3 3 1 3 3 1 I want this output..... RetunrID TotalAttempt Success 1 2 1 2 1 0 3 2 2 Count Of ReturnID is TotalAttempt, when ReturnID = sumbitID and status =1 Then it count as success... Thanks in Advance!
Something like this SELECT T.ReturnID , COUNT(T.ReturnID) AS TotalAttempt , SUM(CASE WHEN T.ReturnID = T.sumbitID AND T.Status = 1 THEN 1 ELSE 0 END) AS Status FROM dbo.MyTable T group by T.ReturnID
Check this: SELECT T.ReturnID , COUNT(T.ReturnID) AS TotalAttempt , SUM(CASE WHEN T.ReturnID = T.sumbitID AND T.Statusa = 1 THEN 1 ELSE 0 END) AS Status FROM #table T GROUP BY T.ReturnID