SQL: While loop in While Loop - sql

I am trying to insert 10K names in Parent table, Using 10 described names while adding number in the back. But managing to write only first thousand. I need your eyes to see where I am failing. I do understand that #i is not increesing but dont know why.
DECLARE #TempNameTable table (ID int , Name varchar (50))
DECLARE #i int = 1,
#tempNameValue varchar(50),
#randNumber int = 1
INSERT INTO #TempNameTable VALUES
(1,'Jonas'), (2,'Petras'),(3,'Antanas')
, (4,'Stasys'), (5,'Dainius'), (6,'Giedrius')
, (7,'Mindaugas'), (8,'Povilas'), (9,'Kestutis')
, (10,'Darius')
WHILE ((SELECT COUNT(Name) FROM Parent) < 10000)
BEGIN
WHILE #i < 11
BEGIN
SET #tempNameValue = CASE
WHEN #i = 1 THEN
(SELECT Name from #TempNameTable WHERE ID = #i)
WHEN #i = 2 THEN
(SELECT Name from #TempNameTable WHERE ID = #i)
WHEN #i = 3 THEN
(SELECT Name from #TempNameTable WHERE ID = #i)
WHEN #i = 4 THEN
(SELECT Name from #TempNameTable WHERE ID = #i)
WHEN #i = 5 THEN
(SELECT Name from #TempNameTable WHERE ID = #i)
WHEN #i = 6 THEN
(SELECT Name from #TempNameTable WHERE ID = #i)
WHEN #i = 7 THEN
(SELECT Name from #TempNameTable WHERE ID = #i)
END
WHILE #randNumber < 1000
BEGIN
INSERT INTO Parent VALUES
(#tempNameValue + CAST(#randNumber as varchar(1000)))
SET #randNumber = #randNumber + 1
END
SET #i = #i + 1
END
END

I suppose your query becomes:
DECLARE #TempNameTable table (ID int , Name varchar (50))
DECLARE #tempNameValue varchar(50),
#randNumber int = 1
INSERT INTO #TempNameTable VALUES
(1,'Jonas'), (2,'Petras'), (3,'Antanas'),
(4,'Stasys'), (5,'Dainius'), (6,'Giedrius'),
(7,'Mindaugas'), (8,'Povilas'), (9,'Kestutis'), (10,'Darius')
WHILE ((SELECT COUNT(Name) FROM Parent) < 10000)
BEGIN
SET #randNumber = 1
WHILE #randNumber <= 1000
BEGIN
INSERT INTO Parent
SELECT Name + CAST(#randNumber as varchar(1000))
FROM #TempNameTable
SET #randNumber = #randNumber + 1
END
END

I'd do it like the below. Just tested and it outputs each name * 1,000 rows. It's more verbose but its obvious what it's doing and it works.
Declare #Jonas varchar(20) = 'Jonas'
Declare #Petras varchar(20) = 'Petras'
Declare #Antanas varchar(20) = 'Antanas'
Declare #Stasys varchar(20) = 'Stasys'
Declare #Dainius varchar(20) = 'Dainius'
Declare #Giedrius varchar(20) = 'Giedrius'
Declare #Mindaugas varchar(20) = 'Mindaugas'
Declare #Povilas varchar(20) = 'Povilas'
Declare #Kestutis varchar(20) = 'Kestutis'
Declare #Darius varchar(20) = 'Darius'
Declare #TempJonas varchar(20)
Declare #TempPetras varchar(20)
Declare #TempAntanas varchar(20)
Declare #TempStasys varchar(20)
Declare #TempDainius varchar(20)
Declare #TempGiedrius varchar(20)
Declare #TempMindaugas varchar(20)
Declare #TempPovilas varchar(20)
Declare #TempKestutis varchar(20)
Declare #TempDarius varchar(20)
Declare #NameIncrement int = 0
WHILE #NameIncrement <= 1000
BEGIN
Set #TempJonas = #Jonas + CONVERT(varchar(6),#NameIncrement)
Set #TempPetras = #Petras + CONVERT(varchar(6),#NameIncrement)
Set #TempAntanas = #Antanas + CONVERT(varchar(6),#NameIncrement)
Set #TempStasys = #Stasys + CONVERT(varchar(6),#NameIncrement)
Set #TempDainius = #Dainius + CONVERT(varchar(6),#NameIncrement)
Set #TempGiedrius = #Giedrius + CONVERT(varchar(6),#NameIncrement)
Set #TempMindaugas = #Mindaugas + CONVERT(varchar(6),#NameIncrement)
Set #TempPovilas = #Povilas + CONVERT(varchar(6),#NameIncrement)
Set #TempKestutis = #Kestutis + CONVERT(varchar(6),#NameIncrement)
Set #TempDarius = #Darius + CONVERT(varchar(6),#NameIncrement)
Insert Into Parent
Select #TempJonas
Insert Into Parent
Select #TempPetras
Insert Into Parent
Select #TempAntanas
Insert Into Parent
Select #TempStasys
Insert Into Parent
Select #TempDainius
Insert Into Parent
Select #TempGiedrius
Insert Into Parent
Select #TempMindaugas
Insert Into Parent
Select #TempPovilas
Insert Into Parent
Select #TempKestutis
Insert Into Parent
Select #TempDainius
Set #NameIncrement = #NameIncrement + 1
END

Set based answer without loops:
rextester: http://rextester.com/EBM78452
declare #TempNameTable table (id int , Name varchar (50))
insert into #TempNameTable values
(1,'Jonas'), (2,'Petras'), (3,'Antanas')
, (4,'Stasys'), (5,'Dainius'), (6,'Giedrius')
, (7,'Mindaugas'), (8,'Povilas'), (9,'Kestutis')
, (10,'Darius');
if object_id('tempdb..#r') is not null drop table #r;
create table #r (n int not null primary key, r int not null);
with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, d as (
select n=row_number() over (order by (select 1))
, r=convert(int,((rand(checksum(newid())) * 10)+1))
from n as deka
cross join n as hecto
cross join n as kilo
cross join n as tenK
)
insert into #r (n, r)
select n, r from d;
--insert into Parent
select Name=Name+convert(varchar(13),n)
from #r as r
inner join #TempNameTable t on r.r=t.id
This uses convert(int,((rand(checksum(newid())) * 10)+1)) to generate a random number from 1 to 10, and uses that to join the temp table #r to #TempNameTable

Related

Implement the stored procedure iterative approach in a SQL manner

I am trying to implement convolution between two vectors v1 and v2. As part of that I have written a stored procedure with an iterative approach using while loops. Here is the below code as below. I am not able to think through how to do it using SQL as the stored procedure is inefficient w.r.t performance. Can somebody share your thoughts on this? Any inputs would be appreciated.
Idea behind writing the stored procedure:
https://software.intel.com/en-us/ipp-dev-reference-convolve
Table schema and sample input data:
CREATE TABLE AIRWork..TableA (idx INT, val INT);
CREATE TABLE AIRWork..TableB (idx INT, val INT);
INSERT INTO AIRWork..TableA
VALUES (0, -2), (1, 0), (2, 1), (3, -1), (4, 3);
INSERT INTO AIRWork..TableB
VALUES (0, 0), (1, 1);
Stored procedure:
ALTER PROCEDURE Calc_Convolved_Values_Test
AS
BEGIN
DECLARE #srclen1 INT
DECLARE #srclen2 INT
DECLARE #n INT = 0
DECLARE #k INT
DECLARE #m INT
DECLARE #SQL NVARCHAR(1000)
DECLARE #x int
DECLARE #xx int = 0
DECLARE #sum INT = 0
DECLARE #y int
DECLARE #yy int = 0
DECLARE #a INT = 0
DECLARE #b INT = 0
SELECT #srclen1 = COUNT(*) FROM AIRWork..TableA;
SELECT #srclen2 = COUNT(*) FROM AIRWork..TableB;
SET #m = #srclen1 + #srclen2 -1
WHILE #n < #m
BEGIN
SET #k = 0
SET #sum = 0
WHILE #k <= #n
BEGIN
SET #SQL = 'SELECT #x=val FROM AIRWork..TableA WHERE idx ='+CONVERT(VARCHAR(5),#k)
EXEC sp_executesql #SQL, N'#x int out', #xx out
SET #a = #xx
IF #n-#k < #srclen2
BEGIN
SET #SQL = 'SELECT #y=val FROM AIRWork..TableB WHERE idx ='+CONVERT(VARCHAR(5),#n-#k)
EXEC sp_executesql #SQL, N'#y int out', #yy out
SET #b = #yy
END
ELSE
BEGIN
SET #b = 0
END
SET #sum = #sum + #a*#b
SET #k = #k + 1
END
PRINT #sum
SET #n = #n + 1
END
END
GO
Sample output:
pDst[n] --> Please check the formula in the beginning of the question.
0
-2
0
1
-1
3
This procedure should do it:
ALTER PROCEDURE Calc_Convolved_Values_Test
AS
;WITH AllRows AS
(
SELECT idx, val, 0 as tbl FROM AIRWork..TableA
UNION ALL SELECT idx, val, 1 as tbl FROM AIRWork..TableB
)
, CombinedRows As
(
SELECT *,
ROW_NUMBER() OVER(ORDER BY tbl, idx)-1 As k,
COUNT(*) OVER(PARTITION BY 1) - 1 As n
FROM AllRows
)
SELECT ABDest.k As idx, SUM(A.val * B.val) As val
FROM CombinedRows AS ABDest
JOIN CombinedRows AS AB ON AB.k <= ABDest.k
LEFT JOIN AIRWork..TableA As A ON A.idx = AB.k
LEFT JOIN AIRWork..TableB As B ON B.idx = ABDest.k - AB.k
WHERE ABDest.k < ABDest.n
GROUP BY ABDest.k
ORDER BY ABDest.k
GO
FYI, I would not recommend using a whole table to store a single vector. You would be much better off storing all of your vectors in the same table and using a name or ID key column to separate them.

Sql Query To Find Relevant Match

I am trying to write a query that should return the following output:
val1 = 'GREAT'
val2 = 'TAGER'
See above have the same characters and it should return 'Exist' if the match is found. Otherwise, if there is a character missing, then 'Not exist'. I am using CASE to get the required output and was wondering if it could be done using SUBSTRING, CHARINDEX etc. Hoping to get a solution or idea to do so. Thanks.
You can make it as a function / procedure according to your needs.
DECLARE #S1 VARCHAR(100)
DECLARE #S2 VARCHAR(100)
SELECT #S1 = val1
,#S2 = val2
FROM <TABLE_NAME>
DECLARE #c CHAR(1)
DECLARE #i TINYINT
DECLARE #o1 VARCHAR(100) = ''
DECLARE #o2 VARCHAR(100) = ''
WHILE DataLength(#s1) > 0
BEGIN
SET #c = Left(#s1, 1)
SET #s1 = Substring(#s1, 2, len(#s1))
SET #i = 1
WHILE #i <= Len(#o1)
AND #c > substring(#o1, #i, 1)
SET #i += 1
SET #o1 = left(#o1, #i - 1) + #c + substring(#o1, #i, len(#o1))
END
WHILE DataLength(#s2) > 0
BEGIN
SET #c = Left(#s2, 1)
SET #s2 = Substring(#s2, 2, len(#s2))
SET #i = 1
WHILE #i <= Len(#o2)
AND #c > substring(#o2, #i, 1)
SET #i += 1
SET #o2 = left(#o2, #i - 1) + #c + substring(#o2, #i, len(#o2))
END
SELECT CASE
WHEN #o1 = #o2
THEN 'Exist'
ELSE 'Not Exist'
END
This is a custom script for you
Run this SP first
IF(OBJECT_ID('CharSplit')) IS NOT NULL
DROP PROCEDURE CharSplit;
GO
CREATE PROC CharSplit
#Words VARCHAR(MAX)
AS
BEGIN
IF OBJECT_ID('tempdb..#temp1') IS NOT NULL
DROP TABLE #temp1;
CREATE TABLE #temp1
(
letter CHAR(1), freq INT
);
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL
DROP TABLE #temp2;
CREATE TABLE #temp2
(
letter CHAR(1), freq INT
);
DECLARE #t VARCHAR(MAX);
DECLARE #I INT;
--SET #Words = 'sanuantony';
SELECT #I = 0;
WHILE(#I < LEN(#Words) + 1)
BEGIN
SELECT #t = SUBSTRING(#words, #I, 1);
INSERT INTO #temp1
(letter, freq
)
VALUES
(#t, 0
);
SET #I = #I + 1;
END;
TRUNCATE TABLE #temp2;
INSERT INTO #temp2
(letter, freq
)
SELECT letter, COUNT(freq)
FROM #temp1
GROUP BY letter;
SELECT *
FROM #temp2
ORDER BY letter;
END;
Now Just try your business logic
DECLARE #t1 AS TABLE
(
letter CHAR(1), freq INT
);
DECLARE #t2 AS TABLE
(
letter CHAR(1), freq INT
);
INSERT INTO #t1
EXEC charSplit 'alammalay';
INSERT INTO #t2
EXEC charSplit 'malayalam';
IF(
(
SELECT COUNT(1)
FROM #t1
) =
(
SELECT COUNT(1)
FROM #t2
)
AND
(
SELECT COUNT(1)
FROM #t2
) =
(
(
SELECT COUNT(1)
FROM #t1
)
UNION
(
SELECT COUNT(1)
FROM #t2
)
)
)
SELECT 'Both are matching' AS result;
ELSE
SELECT 'Both are not matching' AS result;

Replacing string values in SQL

I'm trying to change some string values in SQL using while loops and replace function.
I have two tables from where I get the values and formulas that I gotta change. The main problem is that when I execute the code, I can change the first matching pattern of the very first formula but the other patterns don't change.
I don't know if the problem is the way that I set the counters or the "Selects" used for searching values.
My code:
IF OBJECT_ID('tempdb..#TABLA_TEMP') IS NOT NULL BEGIN
DROP TABLE #TABLA_TEMP
END
IF OBJECT_ID('tempdb..#TABLE_VALUES') IS NOT NULL BEGIN
DROP TABLE #TABLE_VALUES
END
CREATE TABLE #TABLA_TEMP (
ID INT IDENTITY NOT NULL PRIMARY KEY,
NUMERO VARCHAR(max)
)
INSERT INTO #TABLA_TEMP(NUMERO)VALUES('X=''A01TGR.420.JHNB''+''A02TGR.421.ZASD''')
INSERT INTO #TABLA_TEMP(NUMERO)VALUES('X=''A08TGR.427.YUJK''+''A03TGR.422.CVBN''')
INSERT INTO #TABLA_TEMP(NUMERO)VALUES('X=''A04TGR.423.TYUI''+''A05TGR.424.QWER''')
CREATE TABLE #TABLE_VALUES (
ID INT IDENTITY NOT NULL PRIMARY KEY,
ID_INDICADOR INT,
CODIGO VARCHAR(max),
MtoValor DECIMAL(18,2)
)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19520, 'A01TGR.420.JHNB', 50.00)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19521, 'A02TGR.421.ZASD', 25.00)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19522, 'A03TGR.422.CVBN', 15.00)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19523, 'A04TGR.423.TYUI', 65.00)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19524, 'A05TGR.424.QWER', 30.00)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19527, 'A08TGR.427.YUJK', 45.00)
select * from #TABLA_TEMP
--select * from #TABLE_VALUES
DECLARE #counter int
SET #counter = 1
DECLARE #counterInterno int
SET #counterInterno = 1
WHILE(#counter <= (SELECT MAX(ID) FROM #TABLA_TEMP)) BEGIN
DECLARE #MatchExpression VARCHAR(max)
SET #MatchExpression = (''+ CAST(((SELECT CODIGO FROM #TABLE_VALUES
WHERE ID = #counter)) AS VARCHAR) +'')
--WHILE 1 = 1
WHILE(#counterInterno <= (SELECT MAX(ID) FROM #TABLE_VALUES)) BEGIN
DECLARE #valorInterno VARCHAR(MAX)
SET #valorInterno = (''+ CAST(((SELECT MtoValor FROM #TABLE_VALUES V
WHERE V.ID = #counterInterno)) AS VARCHAR) +'')
DECLARE #RetVal varchar(max)
SET #RetVal = (SELECT REPLACE(NUMERO, #MatchExpression, #valorInterno)
FROM #TABLA_TEMP T WHERE T.ID = #counterInterno)
IF(#RetVal IS NOT NULL)
UPDATE #TABLA_TEMP
SET NUMERO = #RetVal
WHERE ID = #counter
ELSE
break
SET #counterInterno = #counterInterno + 1
SET #counter = #counter + 1
END
END
SELECT * FROM #TABLA_TEMP
At the end, the idea is to get something like this:
X='65'+'15'+'25'
Any help would be appreciated.
Try this:
SELECT ROW_NUMBER() OVER (ORDER BY t1.ID, t2.ID) As RowNo, t1.ID, t1.NUMERO, t2.CODIGO, t2.MtoValor
INTO #NewTemp
FROM #TABLA_TEMP t1 JOIN #TABLE_VALUES t2 ON t1.NUMERO LIKE '%' + t2.CODIGO + '%'
DECLARE #Counter int = 1, #ID as int, #Codigo varchar(max), #MtoValor decimal(18, 2)
WHILE (EXISTS (SELECT 1 FROM #NewTemp WHERE RowNo = #Counter))
BEGIN
SELECT #ID = nt.ID, #Codigo = nt.CODIGO, #MtoValor = nt.MtoValor
FROM #NewTemp nt
WHERE nt.RowNo = #Counter
UPDATE #TABLA_TEMP
SET NUMERO = REPLACE(NUMERO, #Codigo, CAST(#MtoValor AS varchar(25)))
WHERE ID = #ID
SET #Counter = #Counter + 1
END
SELECT *
FROM #TABLA_TEMP
For this:
ID | NUMERO
----+-----------------------
1 | X='50.00'+'25.00'
2 | X='45.00'+'15.00'
3 | X='65.00'+'30.00'

Can't understand why i'm getting an incorrect syntax error in my script?

Can anyone tell me why I'm getting an incorrect syntax error for the line
SELECT * INTO #pre_and_post_op FROM NBOCAP(#StartDate,#EndDate,#OrgCode)
Code:
DECLARE #StartDate datetime
DECLARE #EndDate datetime
DECLARE #OrgCodeString varchar (8000)
SET #StartDate = '01-JAN-11'
SET #EndDate = '31-MAR-14'
SET #OrgCodeString = 'RA720|RQ801|RVJ20|RN325|8AAAA|RBA11'
DECLARE #i int
DECLARE #OrgCode varchar(10)
DECLARE #OrgCount int
DECLARE #TrustTable TABLE
(idx int IDENTITY(1,1), org varchar(10))
DECLARE #pre_and_post_op TABLE
(CARE_ID int,ERR_NumberOfNodesPositive int,ERR_FinalPathologyTCategory int,
ERR_FinalPathologyNCategory int,ERR_FinalMCategory int)
INSERT INTO #TrustTable
SELECT * FROM SplitString(#OrgCodeString, '|')
SET #i = 1
SET #OrgCount = (SELECT COUNT(*) FROM #TrustTable)
IF #OrgCount > 0
WHILE (#i <= #OrgCount)
BEGIN
SET #OrgCode = (SELECT org FROM #TrustTable WHERE idx = #i)
SELECT * INTO #pre_and_post_op FROM NBOCAP(#StartDate,#EndDate,#OrgCode)
SET #i = #i + 1
END
You cannot SELECT INTO a table variable. To quote MSDN:
You cannot specify a table variable or table-valued parameter as the new table.
Use INSERT INTO ... SELECT instead
INSERT INTO #pre_and_post_op SELECT * FROM NBOCAP(#StartDate,#EndDate,#OrgCode)

return separate character from a string

How to return all the characters from a string and count it in sql.
if the string is "how are you"
it should return
char count
2
h 1
o 2
w 1
a 1
r 1
e 1
y 1
u 1
You can use this script. It will give you exactly what you need.
This one counts just the letters in the string.
declare #c int
declare #ch varchar(10)
declare #str varchar(max)
set #str = 'how are you'
declare #letter int
declare #i int
set #i = 1
create table #tbl(ch varchar(10), cnt int)
while (#i <= len(#str))
begin
set #letter = 0
set #ch = substring(#str, #i, 1)
select #c = count(*) from #tbl
where ch = #ch
if ( (#ch >= 'a' and #ch <= 'z') or (#ch >= 'A' and #ch <= 'Z') )
begin
set #letter = 1
end
if (#c = 0)
begin
if (#letter = 1)
begin
insert into #tbl (ch, cnt) values (#ch, 1)
end
end
else
begin
update #tbl set cnt = cnt + 1 where ch = #ch
end
set #i = #i + 1
end
select * from #tbl
drop table #tbl
And if you want to count all chars (not just letters),
this makes it even easier. Use this script.
declare #c int
declare #ch varchar(10)
declare #str varchar(max)
set #str = 'how are you'
declare #i int
set #i = 1
create table #tbl(ch varchar(10), cnt int)
while (#i <= len(#str))
begin
set #ch = substring(#str, #i, 1)
select #c = count(*) from #tbl
where ch = #ch
if (#c = 0)
begin
insert into #tbl (ch, cnt) values (#ch, 1)
end
else
begin
update #tbl set cnt = cnt + 1 where ch = #ch
end
set #i = #i + 1
end
select * from #tbl
drop table #tbl
You can use a customer tsql function, see http://gallery.technet.microsoft.com/scriptcenter/T-SQL-Script-to-Split-a-308206f3.
And you can make a query solve your issue using group by and count statements ?
This will return the result set you have requested. It does this by taking each letter and adding it to a new row within a temporary table and then querying the results to return the counts for each occurrence of the character.
DECLARE #individual CHAR(1);
DECLARE #text NVARCHAR(200)
SET #text = 'how are you';
IF OBJECT_ID('tempdb..#tmpTable') IS NOT NULL
DROP TABLE #tmpTable
CREATE TABLE #tmpTable (letter char(1));
WHILE LEN(#text) > 0
BEGIN
SET #individual = SUBSTRING(#text, 1, 2)
INSERT INTO #tmpTable (letter) VALUES (#individual);
SET #text = SUBSTRING(#text, 2, LEN(#text))
END
SELECT letter, COUNT(*) AS [count]
FROM #tmpTable
GROUP BY letter;