Fill up column with random values from different table - sql

I have 2 tables. Table Table_View has 5 columns and 200 rows
and Table_Random has 3 columns with 10 rows
I need to poulate column Table_View.A_random with values from
Table_Random.FixValues. If the query reaches the end of row in Table_Random i.e row 10, it should start again with
values from the top row i.e row 1. until it fills up the 200 rows.
Given that all tables has primary keys.
Any Ideas?
Thanks in advance

This will work for any count of rows in destination and source tables.
The idea is to calculate count of rows in random table and then assign number rn % #c to each row in destination table. And then update based on join:
DECLARE #count INT = 21
DECLARE #i INT = 1
DECLARE #c INT = 0
DECLARE #t TABLE ( ID INT, Random INT )
DECLARE #r TABLE ( ID INT, Random INT )
INSERT INTO #r
VALUES ( 1, 10 ),
( 3, 20 ),
( 4, 30 ),
( 6, 40 ),
( 8, 50 ),
( 11, 60 ),
( 14, 70 ),
( 17, 80 ),
( 19, 90 ),
( 21, 100 )
WHILE #i <= #count
BEGIN
INSERT INTO #t
VALUES ( #i, NULL )
SET #i = #i + 1
END;
SELECT #c = COUNT(*)
FROM #r;
WITH ctet1
AS ( SELECT * , ROW_NUMBER() OVER ( ORDER BY ID ) AS rn
FROM #t
),
ctet2
AS ( SELECT * ,
CASE WHEN rn % #c = 0 THEN #c
ELSE rn % #c
END AS rnn
FROM ctet1
),
cter
AS ( SELECT * , ROW_NUMBER() OVER ( ORDER BY ID ) AS rn
FROM #r
)
UPDATE ct
SET Random = cr.Random
FROM ctet2 ct
JOIN cter cr ON cr.rn = ct.rnn
SELECT * FROM #t
Output:
ID Random
1 10
2 20
3 30
4 40
5 50
6 60
7 70
8 80
9 90
10 100
11 10
12 20
13 30
14 40
15 50
16 60
17 70
18 80
19 90
20 100
21 10
If you didn't want cycle update then no need for views, functions and needless stuff. Just update:
UPDATE #t SET Random = (SELECT TOP 1 Random FROM #r ORDER BY NEWID())

yes you can make this out.
First of all you need to create and view which'll return a single value from Random Table(Table_Random) for every call.
Create View vMyRand as
Select top 1 val from myRand order by NewID();
then create a function to return value from created view.
CREATE FUNCTION GetMyRand ()
RETURNS varchar(5)
--WITH EXECUTE AS CALLER
AS
BEGIN
Declare #RetValue varchar(5)
--#configVar =
Select #RetValue = val from vmyRand
RETURN(#retValue)
END;
Fiddle Demo Here
Full Code:
create table tab_1
(
id bigint identity(1,1),
name varchar(50),
email varchar(50)
)
insert into tab_1(name,email) values
('a','a#mail.com'), ('b','c#mail.com'),
('a1','a1#mail.com'), ('a2','a2#mail.com'),
('a3','a3#mail.com'), ('a4','a4#mail.com'),
('b1','b1#mail.com'),('b2','b2#mail.com')
create table myRand(val varchar(50))
insert into myRand values('Q1654'),('F2597'),
('Y9405'),('B6735'),('D8732'),('C4893'),('I9732'),
('L1060'),('H6720');
Create View vMyRand as
Select top 1 val from myRand order by NewID();
CREATE FUNCTION GetMyRand ()
RETURNS varchar(5)
--WITH EXECUTE AS CALLER
AS
BEGIN
Declare #RetValue varchar(5)
--#configVar =
Select #RetValue = val from vmyRand
RETURN(#retValue)
END;
Update Code:
update tab_1 set name=(select dbo.getMyRand())
Hope This'll Help You.
Thanks. :)

Related

Best combination to satisfy a quantity

I have a list of items with the same article but different quantities, and I want to find different subgroups of items that could satisfy a specific quantity.
UNIT
ITEM
Quantity
1
1
40
2
1
50
3
1
60
4
1
60
5
1
60
The quantity to satisfy is between 110 and 120
I want to find all the combinations of units that can reach the sum between 110 and 120.
My solution, for now, is to use sql programming, but don't know if can be done with a query.
declare #units table ( id int,Item int,Quantity int)
insert into #units
values
(1 ,1 ,40),
(2 ,1 ,50),
(3 ,1 ,60),
(4 ,1 ,60),
(5 ,1 ,60)
DECLARE #TEMP TABLE ( ID INT, QUANTITY INT , RANKc INT)
DECLARE #TEMP2 TABLE ( Rmin INT, Rmax INT , sumQ INT)
INSERT INTO #TEMP
SELECT
Id,
Quantity,
row_number() over (order by Quantity asc) as rank_c
FROM #units
where Item=1
select * from #TEMP
DECLARE #RMIN INT =1
DECLARE #RMax INT =2
DECLARE #MaxQ int=120
DECLARE #MinQ int=110
--DECLARE #Count int=1
DECLARE #SumQuantity int
WHILE (#RMax<=(SELECT MAX(RANKc) FROM #TEMP))
BEGIN
select #SumQuantity=sum(QUANTITY) from #TEMP where RANKc between #RMIN and #RMax
if (#SumQuantity between #MinQ and #MaxQ)
begin
insert into #TEMP2 values
(#RMIN,#RMax,#SumQuantity)
set #RMIN=#RMIN+1
set #RMax=#RMIN+1
--break;
end
IF (#SumQuantity < #MinQ)
begin
set #RMax=#RMax+1
end
if (#SumQuantity>#MaxQ)
begin
set #RMIN=#RMIN+1
set #RMax=#RMIN+1
end
END
select * from #TEMP2
Rmin
Rmax
sumQ
2
3
110
3
4
120
4
5
120

"Array" usage in T-SQL

Trying to create a temp table where the AlphaSeq column would go through an "array" of alphanumeric characters that do not repeat and follow a flow as shown in the example below.
Example:
AlphaSeq
NumericSeq
A
1
A1
2
B
3
B1
4
AA
5
AB
6
BA
7
BB
8
[ETC]
[ETC]
Here's what I have so far (Obviously the "IG" is static as it is written now, so Im trying to make that field more fluid)
CREATE TABLE #Index
(
AlphaSeq VARCHAR(2),
NumericSeq TINYINT
)
DECLARE #ArrayNum AS TINYINT;
DECLARE #ReceiptSeq AS VARCHAR(2);
SET #ArrayNum = 0
SET #ReceiptSeq = 'IG'
WHILE #ArrayNum < 100
BEGIN
SET #ArrayNum = #ArrayNum + 1
INSERT INTO #Index (AlphaSeq, NumericSeq)
VALUES (#ReceiptSeq, #ArrayNum)
END
SELECT *
FROM #Index
You can simply cross-join the list of characters
CREATE TABLE #Index
(
AlphaSeq VARCHAR(2) NOT NULL,
NumericSeq SMALLINT NOT NULL IDENTITY
);
WITH Chars AS (
SELECT *
FROM (VALUES
('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M'),('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z')
) v(chr)
),
CharsWithNums AS (
SELECT *
FROM (VALUES
('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('0')
) v(chr)
UNION ALL
SELECT *
FROM Chars
)
INSERT #Index (AlphaSeq)
SELECT chr AS AlphaSeq
FROM Chars
UNION ALL
SELECT a.chr + b.chr
FROM Chars a
CROSS JOIN CharsWithNums b
ORDER BY AlphaSeq;

In SQL , how to build a loop that copies a row number of times

could someone please help? My starting table looks like this with 2 fields:
Name Counter
dave 2
Joe 3
I want my result to look like this:
Name Counter
dave 1
dave 2
joe 1
joe 2
joe 3
Essentially creating n number of records base on the counter and starts at 1. I tried to do a loop using counter as a variable, but the code just runs nonstop.. could someone help?
A procedural SQL Server solution:
declare #input table
(
name nvarchar(100)
,wantedrows int
,processed bit
,id uniqueidentifier
);
declare #output table
(
name nvarchar(100)
,rownum int
);
insert into #input
select 'Dave',3,0,newid()
union
select 'Joe',2,0,newid();
while exists(select * from #input where processed = 0)
begin
declare #currentid uniqueidentifier = (select top 1 id from #input where processed = 0);
declare #currentwantedrows int = (select wantedrows from #input where id = #currentid);
declare #i int = 0;
while #i < #currentwantedrows
begin
insert into #output
select name,#i+1
from #input
where id = #currentid;
set #i = #i + 1;
end;
update #input set processed = 1 where id = #currentid;
end
select name,wantedrows from #input;
select * from #output;
You can use a number-table or following trick using a system view to build a sequence:
WITH Nums AS
(
SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_objects
)
SELECT Name, Counter = n
FROM Nums n CROSS JOIN Table1 t1
WHERE n BETWEEN 1 AND Counter
ORDER BY Name, Counter;
Demo
This view has only about 2000 rows, so if you need more you could use a number-table.
http://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1
( presuming SQL-Server )
Is a hundred copies enough?
create table #c (num)
insert into #c (num)
select 0 union
select 1 union
select 2 union
select 3 union
select 4 union
select 5 union
select 6 union
select 7 union
select 8 union
select 9
select T.Name, c1.num * 10 + c0.num + 1
from T, #c c1, #c c0
where c1.num * 10 + c0.num < T.Counter
drop table #c
You didn't say which version of Sybase. The old ones I've worked on didn't allow derived tables so I had to throw the values into a temp table. But you can see how to extend the idea. This may not be the best approach if this is something you need to do more than once though.

Sequential numbers randomly selected and added to table

The SO Question has lead me to the following question.
If a table has 16 rows I'd like to add a field to the table with the numbers 1,2,3,4,5,...,16 arranged randomly i.e in the 'RndVal' field for row 1 this could be 2, then for row 2 it could be 5 i.e each of the 16 integers needs to appear once without repetition.
Why doesn't the following work? Ideally I'd like to see this working then to see alternative solutions.
This creates the table ok:
IF OBJECT_ID('tempdb..#A') IS NOT NULL BEGIN DROP TABLE #A END
IF OBJECT_ID('tempdb..#B') IS NOT NULL BEGIN DROP TABLE #B END
IF OBJECT_ID('tempdb..#C') IS NOT NULL BEGIN DROP TABLE #C END
IF OBJECT_ID('tempdb..#myTable') IS NOT NULL BEGIN DROP TABLE #myTable END
CREATE TABLE #B (B_ID INT)
CREATE TABLE #C (C_ID INT)
INSERT INTO #B(B_ID) VALUES
(10),
(20),
(30),
(40)
INSERT INTO #C(C_ID)VALUES
(1),
(2),
(3),
(4)
CREATE TABLE #A
(
B_ID INT
, C_ID INT
, RndVal INT
)
INSERT INTO #A(B_ID, C_ID, RndVal)
SELECT
#B.B_ID
, #C.C_ID
, 0
FROM #B CROSS JOIN #C;
Then I'm attempting to add the random column using the following. The logic is to add random numbers between 1 and 16 > then to effectively overwrite any that are duplicated with other numbers > in a loop ...
SELECT
ROW_NUMBER() OVER(ORDER BY B_ID) AS Row
, B_ID
, C_ID
, RndVal
INTO #myTable
FROM #A
DECLARE #rowsRequired INT = (SELECT COUNT(*) CNT FROM #myTable)
DECLARE #i INT = (SELECT #rowsRequired - SUM(CASE WHEN RndVal > 0 THEN 1 ELSE 0 END) FROM #myTable)--0
DECLARE #end INT = 1
WHILE #end > 0
BEGIN
SELECT #i = #rowsRequired - SUM(CASE WHEN RndVal > 0 THEN 1 ELSE 0 END) FROM #myTable
WHILE #i>0
BEGIN
UPDATE x
SET x.RndVal = FLOOR(RAND()*#rowsRequired)
FROM #myTable x
WHERE x.RndVal = 0
SET #i = #i-1
END
--this is to remove possible duplicates
UPDATE c
SET c.RndVal = 0
FROM
#myTable c
INNER JOIN
(
SELECT RndVal
FROM #myTable
GROUP BY RndVal
HAVING COUNT(RndVal)>1
) t
ON
c.RndVal = t.RndVal
SET #end = ##ROWCOUNT
END
TRUNCATE TABLE #A
INSERT INTO #A
SELECT
B_ID
, C_ID
, RndVal
FROM #myTable
If the original table has 6 rows then the result should end up something like this
B_ID|C_ID|RndVal
----------------
| | 5
| | 4
| | 1
| | 6
| | 3
| | 2
I don't understand your code, frankly
This will update each row with a random number, non-repeated number between 1 and the number of rows in the table
UPDATE T
SET SomeCol = T2.X
FROM
MyTable T
JOIN
(
SELECT
KeyCol, ROW_NUMBER() OVER (ORDER BY NEWID()) AS X
FROM
MyTable
) T2 ON T.KeyCol = T2.KeyCol
This is more concise but can't test to see if it works as expected
UPDATE T
SET SomeCol = X
FROM
(
SELECT
SomeCol, ROW_NUMBER() OVER (ORDER BY NEWID()) AS X
FROM
MyTable
) T
When you add TOP (1) (because you need to update first RndVal=0 record) and +1 (because otherwise your zero mark means nothing) to your update, things will start to move. But extremely slowly (around 40 seconds on my rather outdated laptop). This is because, as #myTable gets filled with generated random numbers, it becomes less and less probable to get missing numbers - you usually get duplicate, and have to start again.
UPDATE top (1) x
SET x.RndVal = FLOOR(RAND()*#rowsRequired) + 1
FROM #myTable x
WHERE x.RndVal = 0
Of course, #gbn has perfectly valid solution.
This is basically the same as the previous answer, but specific to your code:
;WITH CTE As
(
SELECT B_ID, C_ID, RndVal,
ROW_NUMBER() OVER(ORDER BY NewID()) As NewOrder
FROM #A
)
UPDATE CTE
SET RndVal = NewOrder
SELECT * FROM #A ORDER BY RndVal

get specific rows of table given a rule SQL Server 2008

I have a table like:
ID NAME VAL
----------------------
1 a1*a1 90052
2 a1*a2 236
3 a1*a3 56
4 a1*a4 6072
5 a1*a5 1004
6 a2*a2 4576
7 a2*a3 724
8 a2*a4 230
9 a2*a5 679
10 a3*a3 5
11 a3*a4 644
12 a3*a5 23423
13 a4*a4 42354
14 a4*a5 10199
15 a5*a5 10279
Given a number given S = 5, I want to query
the rows wth id: 1,6,10,13,15
they are a1*a1,a2*a2,a3*a3,a4*a4 and a5*a5
I would like something like:
INSERT #NEW_TABLE (ID,NAME,Value) (
SELECT ordinal, NAME, VAL FROM myTable where id = 1,6,10,13,15)
to get
ID NAME VAL
----------------------
1 a1*a1 90052
2 a2*a2 4576
3 a3*a3 5
4 a4*a4 42354
5 a5*a5 10279
Is there a way to do this for any given S, Maybe wth dynamic sql?
I was getting the formula and I got this:
S=5
ID formula
1 1
6 1+S
10 1+S+ (S-1)
13 1+S+ (S-1) + (S-2)
15 1+S+ (S-1) + (S-2) + (S-3)
Is there a way to do this inside a case or a while loop?
This worked in testing.
You can just inner join on #Tab to limit your results. You probably also want to add some traps for values below 3, which I haven't done.
The basic process is
Declare your #s value
Insert the first two rows since they will always be the same
In a loop, insert one row at a time with an incrementing difference
Loop exits once it has run #s-2 times
Try:
DECLARE #Tab Table (id INT)
DECLARE #S int = 5,
#ct int
DECLARE #cur int = (1 + #S)
INSERT INTO #Tab SELECT 1
INSERT INTO #Tab SELECT (1 + #S)
SET #ct = 1
WHILE #ct <= #S - 2
BEGIN
SET #cur = #cur + (#S - #ct)
INSERT INTO #Tab SELECT #cur
SET #ct = #ct + 1
END
SELECT * FROM #Tab
ORDER BY id
To use this in your query, you can do either:
SELECT ordinal, NAME, VAL
FROM myTable
WHERE id IN (SELECT id FROM #Tab)
-- OR
SELECT ordinal, NAME, VAL
FROM myTable t
INNER JOIN #tab t2
ON t2.id = t.id