Update a table column with shuffled numbers within a range - sql-server

I want to update a table column -Code- with shuffled numbers within its range, with no duplicates and without missing a number from the range.
for example the range is 1-9 and the following is the table:
Id|Name|Code
1 | AC | 2
2 | AB | 1
3 | CB | 5
4 | DE | 9
5 | FE | 3
6 | AE | 4
7 | FD | 6
8 | BD | 7
9 | DC | 8
I want result like in the above example. I am using SQL Server 2008.

Try this:
DECLARE #t TABLE ( ID INT, Code INT )
INSERT INTO #t
( ID )
VALUES ( 1 ),
( 2 ),
( 3 ),
( 4 ),
( 5 ),
( 6 ),
( 7 ),
( 8 ),
( 9 );
WITH cte
AS ( SELECT * ,
ROW_NUMBER() OVER ( ORDER BY NEWID() ) AS rn
FROM #t
)
UPDATE cte
SET code = rn
SELECT *
FROM #t
Output:
ID Code
1 2
2 7
3 4
4 1
5 6
6 8
7 5
8 9
9 3
If you want to manually set the range then you can set starting number of range and do something like:
DECLARE #start INT = 101
DECLARE #t TABLE ( ID INT, Code INT )
INSERT INTO #t
( ID )
VALUES ( 1 ),
( 2 ),
( 3 ),
( 4 ),
( 5 ),
( 6 ),
( 7 ),
( 8 ),
( 9 );
WITH cte
AS ( SELECT * ,
ROW_NUMBER() OVER ( ORDER BY NEWID() ) AS rn
FROM #t
)
UPDATE cte
SET code = rn + #start - 1
SELECT *
FROM #t
Output:
ID Code
1 104
2 108
3 107
4 105
5 102
6 103
7 106
8 101
9 109

NEWID() will give us a type of random id that you can use it for shuffling
As Giorgu Nakeuri answer you can use ROW_NUMBER() for a range of continuous and always start from 1
So I suggest you to use a query like this for shuffling a non-continues Range with different start point of 1:
;With t as (
SELECT *, ROW_NUMBER() OVER (ORDER BY NEWID()) As rndrn
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY Id) As rn
FROM yourTable ) t1)
SELECT Id, Name, (SELECT ti.Id FROM t ti WHERE ti.rn = t.rndrn) As Code
FROM t
ORDER BY Id
Sample Result is:
ID Name Code
2 AB 2
3 CB 8
4 DE 7
5 FE 5
6 AE 6
7 FD 9
8 BD 3
9 DC 11
11 AC 4

Related

Find Query in SQL Server for the below Results

I have table look like the following
Col1
Col2(nvarchar)
Col3
1
2/4
100
1 ​
2/4
200
2 ​
1/3
140
3 ​
2/3
120
4
3/4
200
Result would be:
The sum of column 3 group by column 1 + column 3 of 2 and column 3 of 4
(excluding the / from col 2)
For example, 1st row will be 100 + 200 + 140 + 200 = 640.
Result would be like the following:
Col1
Sum
1
640
2
560
3
380
4
520
How can I make or what would be the query in sql server to get such resultant one?
Try something like this:
DECLARE #data table ( Col1 int, Col2 nvarchar(3), Col3 int );
INSERT INTO #data VALUES
( 1, '2/4', 100 ),
( 1, '2/4', 200 ),
( 2, '1/3', 140 ),
( 3, '2/3', 120 ),
( 4, '3/4', 200 );
;WITH cte AS (
SELECT
Col1, Col2, SUM ( Col3 ) AS Col3Sum
FROM #data AS d
GROUP BY
Col1, Col2
)
SELECT
Col1, ( Col3Sum + Col2MatchesSum ) AS [Sum]
FROM cte
OUTER APPLY (
-- get the sum of rows matching Col2 delimited values.
SELECT SUM ( Col3 ) AS Col2MatchesSum FROM #data WHERE Col1 IN (
SELECT CAST ( [value] AS int ) FROM STRING_SPLIT ( cte.Col2, '/' )
)
) AS n
ORDER BY
Col1;
RETURNS
+------+-----+
| Col1 | Sum |
+------+-----+
| 1 | 640 |
| 2 | 560 |
| 3 | 380 |
| 4 | 520 |
+------+-----+

Find next record where status field is different from current

I have a table that is used to log events. Two types specifically : ON and OFF.
There are sometimes overlapping log entries as there can be 2 simultaneous devices logging. This is not crucial, as the end report should give a [mostly] correct overview of ON -> OFF periods.
Below is a sample, with the 3rd column just for illustration: It does not exist.
ActionTaken ID ID_of_next_OFF
Switched ON 1 3
Switched ON 2 6
Switched OFF 3
Switched ON 4 7
Switched ON 5 8
Switched OFF 6
Switched OFF 7
Switched OFF 8
Switched On 9 10
Switched OFF 10
Switched On 11 12
Switched OFF 12
Given the first two columns, how can I calculate the third?
This does not work:
SELECT actionTaken, Id, LEAD(Id)
OVER (PARTITION BY ActionTaken ORDER BY ID) nextConn
FROM dbo.Events
as it bases the ID_of_Next on the next matching actionTaken value, instead of the next alternate.
You are on the right way. All you need is the LEFT JOIN of the 'Switched ON' part with the 'Switched OFF' part on equal row numbers.
with Events as (
select 'Switched ON' as ActionTaken, 1 as ID union all -- 3
select 'Switched ON', 2 union all -- 6
select 'Switched OFF', 3 union all
select 'Switched ON', 4 union all -- 7
select 'Switched ON', 5 union all -- 8
select 'Switched OFF', 6 union all
select 'Switched OFF', 7 union all
select 'Switched OFF', 8 union all
select 'Switched On', 9 union all -- 10
select 'Switched OFF', 10 union all
select 'Switched On', 11 union all -- 12
select 'Switched OFF', 12
), E as (
select
*, row_number() over(partition by ActionTaken order by ID) as rn
from Events
)
select
a.ActionTaken, a.ID, b.ID
from E as a
left join E as b
on a.ActionTaken = 'Switched ON' and
b.ActionTaken = 'Switched OFF' and
a.rn = b.rn
order by a.ID, a.ActionTaken;
Output:
+--------------+----+------+
| ActionTaken | ID | ID |
+--------------+----+------+
| Switched ON | 1 | 3 |
| Switched ON | 2 | 6 |
| Switched OFF | 3 | NULL |
| Switched ON | 4 | 7 |
| Switched ON | 5 | 8 |
| Switched OFF | 6 | NULL |
| Switched OFF | 7 | NULL |
| Switched OFF | 8 | NULL |
| Switched On | 9 | 10 |
| Switched OFF | 10 | NULL |
| Switched On | 11 | 12 |
| Switched OFF | 12 | NULL |
+--------------+----+------+
Test it online with SQL Fiddle.
something like this should get you there.
Below I've used 2 CTE's to split the off and on data and then provide a ranking item for first switch on first switch off then I've used a union query to match those up
declare #Events table (
ActionTaken nvarchar(25),
ID int
);
insert #Events
values
--ActionTaken ID ID_of_next_OFF
('Switched ON' , 1), -- 3
('Switched ON' , 2),-- 6
('Switched OFF', 3),
('Switched ON' , 4),-- 7
('Switched ON' , 5),-- 8
('Switched OFF', 6),
('Switched OFF', 7),
('Switched OFF', 8),
('Switched On' , 9),-- 10
('Switched OFF', 10),
('Switched On' , 11),-- 12
('Switched OFF', 12);
with onrank as (
select row_number()over(order by id) ranking, * from #Events where ActionTaken like '%ON')
, offrank as (
select row_number()over(order by id) ranking, * from #Events where ActionTaken like '%OFF')
select o.ActionTaken, o.ID, case when o.ranking=f.ranking then cast(f.id as nvarchar(3)) end as Id_next_off
from onrank o inner join offrank f on o.ranking=f.ranking
union
select ActionTaken, ID, '' from offrank
order by o.ID;

SQL Server : query for DENSE_RANK() grouped by 2 column?

Need help in construct SQL, over an orders table, that holds the Date, SalesID, ItemID and other misc. columns.
Table looks like:
Date SalesID ItemID
13-9-15 6:15:00 56 6
13-9-15 6:00:00 56 6
13-9-15 6:26:00 56 4
13-9-15 6:38:00 34 4
13-9-15 7:05:00 34 2
13-9-15 6:42:00 12 2
13-9-15 7:20:00 12 5
13-9-15 7:34:00 78 5
13-9-15 7:41:00 78 6
What I'd like to have as an additional column is, one counter which is increments each time when new SalesID begins order by date.And the counter column will count until max no is 3.I'm using DENSE_RANK()for the increment column.
Finally what I need:
Date SalesID ItemID Counter
13-9-15 6:00:00 56 6 1
13-9-15 6:15:00 56 6 1
13-9-15 6:26:00 56 4 1
13-9-15 6:38:00 34 4 2
13-9-15 6:42:00 34 2 2
13-9-15 7:05:00 12 2 3
13-9-15 7:20:00 12 5 3
13-9-15 7:34:00 78 5 1
13-9-15 7:41:00 78 6 1
This solution works for sqlserver 2012+. I had to correct invalid data in your example in order to get the correct output
DECLARE #t table(Date datetime, SalesID int, ItemID int)
INSERT #t values
('2015-09-13 6:15:00',56,6),
('2015-09-13 6:00:00',56,6),
('2015-09-13 6:26:00',56,4),
('2015-09-13 6:38:00',34,4),
('2015-09-13 6:42:00',34,2),
('2015-09-13 7:05:00',12,2),
('2015-09-13 7:10:00',12,5),
('2015-09-13 7:34:00',78,5),
('2015-09-13 7:41:00',78,6)
;WITH CTE as
(
SELECT
[Date], [SalesID], [ItemID],
CASE WHEN lag(SalesID) over (order by Date) = SalesID
THEN 0 ELSE 1 END x
FROM #t
)
SELECT
[Date], [SalesID], [ItemID],
(sum(x) over (ORDER BY Date) - 1) % 3 + 1 [Counter]
FROM CTE
Result:
Date SalesID ItemID Counter
2015-09-13 06:00 56 6 1
2015-09-13 06:15 56 6 1
2015-09-13 06:26 56 4 1
2015-09-13 06:38 34 4 2
2015-09-13 06:42 34 2 2
2015-09-13 07:05 12 2 3
2015-09-13 07:10 12 5 3
2015-09-13 07:34 78 5 1
2015-09-13 07:41 78 6 1
This will work for sqlserver 2008:
;WITH CTE as
(
SELECT
[Date],
SalesID,
ItemID,
row_number() over (order by Date)-
row_number() over (partition by SalesID order by Date) x
FROM #t
)
SELECT
[Date],
SalesID,
ItemID,
(dense_rank() over (order by x) - 1) % 3 + 1 [Counter]
FROM CTE

SQL Server 2008 R2: Recursive query

This is the follow up question of : Prepare a recursive query
I have the table with the two columns namely cola and colb as shown below:
Table : Test
create table Test
(
cola int,
colb int
);
Records I have entered are:
Cola Colb
------------
1 2
1 3
1 4
2 5
2 6
2 3
3 2
3 4
3 7
3 10
10 11
11 12
11 13
11 14
12 15
13 16
14 99
15 88
16 77
Note: Now I want to show the only records who are connected with value I have pass. For example If I pass the value as 1 then it should display me the connected number to it and form connect like a tree.
For the above requirement I have got the script from Dark Knight as shown below which works fine.
;WITH CTE AS
(
SELECT COLA,COLB,','+CAST(COLA AS VARCHAR(MAX))+',' AS CHCK FROM test WHERE COLA=1
UNION ALL
SELECT C1.COLA,C1.COLB,C.CHCK+CAST(C1.cola AS VARCHAR(MAX))+','
FROM CTE C INNER JOIN test C1 ON C.colb = C1.cola
WHERE CHARINDEX(','+CAST(C.colb AS VARCHAR(MAX))+',',C.CHCK)=0
),
OUTERCTE AS
(
SELECT DISTINCT COLA,COLB,ROW_NUMBER() OVER(PARTITION BY Colb ORDER BY Cola) rn FROM CTE --ORDER BY COLA
)
SELECT Cola,Colb FROM OUTERCTE
WHERE rn<=1
ORDER BY CASE WHEN Cola = 1 THEN 1 ELSE 2 END;
Which gives me this:
----------------
Cola Colb
----------------
1 2
1 3
1 4
2 5
2 6
3 7
3 10
10 11
11 12
11 13
11 14
12 15
13 16
16 77
15 88
14 99
Requirement: Now I want to show the levels of records.
Expected Result:
------------------------------
Cola Colb Level
------------------------------
1 2 1
1 3 1
1 4 1
2 5 2
2 6 2
3 7 2
3 10 2
10 11 3
11 12 4
11 13 4
11 14 4
12 15 5
13 16 5
16 77 6
15 88 6
14 99 5
;WITH CTE AS
(
SELECT COLA,COLB
,','+CAST(COLA AS VARCHAR(MAX))+',' AS CHCK
, 1 as lvl FROM #Test WHERE COLA=1
UNION ALL
SELECT C1.COLA,C1.COLB ,C.CHCK+CAST(C1.cola AS VARCHAR(MAX))+','
, c.lvl+1
FROM CTE C INNER JOIN #Test C1 ON C.colb = C1.cola
WHERE CHARINDEX(','+CAST(C.colb AS VARCHAR(MAX))+',',C.CHCK)=0
),
cte2 as (
select * , ROW_NUMBER() over (partition by colb order by lvl)as rn From CTE
)
select cola,colb,lvl from cte2 where rn = 1

Modifying a column in a table

I have the following table test
iD Name ParentId GroupID
-----------------------------
1 1 Null
2 1 Null
3 1 Null
4 7 Null
5 7 Null
6 7 Null
7 9 Null
How can I modify it to get the column GroupID like this:
iD Name ParentId GroupID
------------------------------
1 1 1
2 1 1
3 1 1
4 7 2
5 7 2
6 7 2
7 9 3
; WITH CTE
AS
(
SELECT iDName, ParentId, GroupID,
DENSE_RANK() OVER (ORDER BY ParentId ASC) RN
FROM Test
)
UPDATE CTE
SET GroupID = RN
Working SQL FIDDLE
UPDATE test SET GroupID = 1 WHERE ParentId = 1
UPDATE test SET GroupID = 2 WHERE ParentId = 7
UPDATE test SET GroupID = 3 WHERE ParentId = 9

Resources