How does the while loop work? - sql

declare #t INT = 1
declare #i INT = 1
while #t <= 5
BEGIN
while #i <= 40
BEGIN
set #i = #i + 1
END
set #t = #t + 1
select #t
END
The result I get is #t=2. If I replace it with #i I get #i=41. Why does the #variable in the first while loop show 2, does it brake? Should it not show#t=6?
If I put the select #t at the end it will show 6, but what if you need every result from the iteration, you would not get the others results if you put the #t after the end, you would only get the last result. I would like the results 1,2,3,4,5,6 all go through #t ,and the end result should show only 6.
This is simplified example of a procedure that i have written, for every #t iteration the #i makes a full iteration, and then #t should go for the second iteration. #i works as planned, but the #t breaks after the first itteration.
(if #t = 1 , #i gets 40 rows from column 1 from some table, #t = 2 it gets 40 rows from column 2 from some table..ect) and writes it in #sql string, when she gets to 40 while loop breaks and goes into the #t loop, the #t should execute the #sql string(example it creates a view, so at the end i should have 6 views, but after the first execute the #t loop breaks.)

You can store your result in a table variable.
DECLARE #t INT = 1
DECLARE #i INT = 1
DECLARE #Result table(Id int)
while #t <= 5
BEGIN
while #i <= 40
BEGIN
set #i = #i + 1
END
INSERT INTO #Result(Id) values(#t)
set #t = #t + 1
END
select Id FROM #Result

As I understand, you should have:
DECLARE #t INT = 1
DECLARE #i INT = 1
while #t <= 5
BEGIN
while #i <= 40
BEGIN
set #i = #i + 1
END
set #t = #t + 1
--select #t <-- this is breaking the loop before it ends
END
select #t

Related

SQL Loop based calculation

I have following data:
Calculation is the column consists of following formula:
For Exmaple H12 = =(C12-D12+C12-E12+C12-F12+C12-G12)
+(D12-C12+D12-E12+D12-F12+D12-G12)
+(E12-C12+E12-D12+E12-F12+E12-G12)
+(F12-C12+F12-D12+F12-E12+F12-G12)
+(G12-C12+G12-D12+G12-E12+G12-F12)
In short for category 1, (col1 value i.e. 2 minus col1 value) into (col1 value minus value for rest columns) by keeping col1 as fix then Plus same for col2.
Additional conditions are there can be any number of columns (cols) and any number of categories.
So I have attempted to write a code. But how to write a calculation part?:
DECLARE #i int = 0
DECLARE #j int = 0
DECLARE #k int = 1
DECLARE #Category_Count int = (select count(distinct Category) from Table) --This I am getting some other table
DECLARE #columns int = (select count(distinct columns) from Table) --This I am getting some other table
WHILE #i < #Category_Count
BEGIN
WHILE #j < #columns
BEGIN
WHILE #k < #Category_Count
BEGIN
/* Calculation=
How to write this part */
SET #k = #k + 1
END
SET #j = #j + 1
END
SET #i = #i + 1
END
create table #tab1
(
Category varchar(1),
col1 int,
col2 int,
col3 int,
col4 int,
col5 int,
Calculation int
)
insert into #tab1 values('a',2,3,1,1,3,0),('b',1,3,3,3,2,0),('c',12,5,4,2,6,0),('d',2,3,4,3,2,0),('e',2,1,2,1,1,0),('f',2,3,1,2,2,0),('g',2,3,1,1,3,0),('h',2,3,1,1,3,0),('i',2,3,1,1,3,0),
('j',2,3,1,1,3,0)
DECLARE #count int = 0
DECLARE #j int = 0
DECLARE #k int = 1
select row_number() over(order by category) as RN,* into #tab2 from #tab1
select #count=count(*) from #tab1
WHILE (#k <= #count)
BEGIN
update #tab2 set Calculation=
((col1-col2+col1-col3+col1-col4+col1-col5)
+(col2-col2+col2-col3+col2-col4+col2-col5)
+(col3-col2+col3-col2+col3-col4+col3-col5)
+(col4-col2+col4-col2+col4-col3+col4-col5)
+(col5-col2+col5-col2+col5-col3+col5-col4))
from #tab2 where RN= #k
set #k=#k+1
END

sql use while loop to fetch values and run query on them

I have long query which is ran based on two value parameters (contcode, datime).
I am using this while loop to fetch these values in order from another table, run the query and insert the result into a final table:
DECLARE #r TABLE (id int IDENTITY (1,1),lnr char (9), pday datetime)
INSERT INTO #r (lnr, pday)
SELECT TOP 1 lnr, pday FROM memrepay
DECLARE #counter int SET #counter = 1
DECLARE #contcode char (9)
DECLARE #datime datetime
WHILE #counter <= (SELECT COUNT(*) FROM #r)
BEGIN
--long query
END
SET #counter = #counter + 1
END
SELECT * FROM #finaltable
However long query only works when I fetch 1 row:
SELECT TOP 1 contcode, datime FROM #tbl
And if I don't use TOP 1, I get the error message of:
"Subquery returned more than 1 value...."
How can I fetch those two or more values in order, run the long query based each , not getting this error?
I think you just need to move the SET #counter = #counter + 1 up between the BEGIN...END block under your WHILE loop. That's probably why it only works for TOP 1, since 1 is <= COUNT(*).
DECLARE #r TABLE (id int IDENTITY (1,1),lnr char (9), pday datetime)
INSERT INTO #r (lnr, pday)
SELECT TOP 1 lnr, pday FROM memrepay
DECLARE #counter int SET #counter = 1
DECLARE #contcode char (9)
DECLARE #datime datetime
WHILE #counter <= (SELECT COUNT(*) FROM #r)
BEGIN
--long query
SET #counter = #counter + 1
END
END
SELECT * FROM #finaltable

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;

Storing phone nos with only numbers and with "x" for extension?

I have a test function which would sanitize phone nos and allow only nos and characters "x" or "X" to be stored. I have it to where it does most of it other than it allows multiple x's which I don't want. Can anybody help me add it to the regular expression also let me know if you spot potential issues ?
CREATE Function [dbo].[RemoveAlphaCharacters](#Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin
While PatIndex('%[^0-9,x,X]%', #Temp) > 0
Set #Temp = Stuff(#Temp, PatIndex('%[^0-9,x,X]%', #Temp), 1, '')
Return #TEmp
End
The problem with PATINDEX here is that it can't really determine that the pattern should change after it hits a string for the first time. So maybe this approach will be simpler:
CREATE FUNCTION [dbo].[RemoveAlphaCharacters]
(
#Temp VARCHAR(1000)
)
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE #i INT, #hitX BIT, #t VARCHAR(1000), #c CHAR(1);
SELECT #i = 1, #hitX = 0, #t = '';
WHILE #i <= LEN(#Temp)
BEGIN
SET #c = SUBSTRING(#Temp, #i, 1);
IF LOWER(#c) = 'x' AND #hitX = 0
BEGIN
SET #t = #t + #c;
SET #hitX = 1;
END
IF #c LIKE '[0-9]'
BEGIN
SET #t = #t + #c;
END
SET #i = #i + 1;
END
RETURN(#t);
END
GO
SELECT dbo.RemoveAlphaCharacters('401-867-9092');
SELECT dbo.RemoveAlphaCharacters('401-867-9092x32');
SELECT dbo.RemoveAlphaCharacters('401-867-9092x32x54');
Results:
4018679092
4018679092x32
4018679092x3254

Sql query checking condition before insert row

I have a table called dbo.Tbl_ActivityInformations and the data look like
Activityid activitymaxcount Activityusedcount
1 10 9
2 10 7
3 15 15
And another table called Tbl_AttendeeInformations and the data look like
AttendedID AssID ActivityID
13 123456 1,2
14 123457 1,3
In the Tbl_AttendeeInformations table data will be inserted as new row from page and in the ActivityInformations table Activityusedcount column incremented by one for appropriate activityID.
Now I want to check before inserting a row into AttendeeInformations that Activityusedcount < activitymaxcount using ActivityID. If the condition is satisfied then only it will allow to insert otherwise it should rollback. I have function named SplitString to split ActivityID in Tbl_AttendeeInformations.
This is the code for SplitString
create FUNCTION dbo.SplitString(#FormattedString varchar(8000),#Delimitter char(1))
returns #retResults TABLE(Value varchar(8000),Rownumber int)
as
BEGIN
DECLARE #SearchString as varchar(8000)
DECLARE #AssignString as varchar(8000)
DECLARE #Index int
DECLARE #Count int
set #SearchString = #FormattedString
set #AssignString= ''
set #Count = 0
while(len(#SearchString) > 0 )
begin
SET #Index = CHARINDEX(#Delimitter,#SearchString, 0)
set #Count = #Count + 1
if #Index = 0
begin
INSERT INTO #retResults
values( #SearchString,#Count)
set #SearchString = ''
continue
end
set #AssignString = SUBSTRING(#SearchString,1, #Index - 1 )
INSERT INTO #retResults values
(#AssignString,#Count)
SET #SearchString = (select SUBSTRING(#SearchString, #Index + 1, LEN(#SearchString) - #Index ))
end
return
END
Please do help.
Pseudocode to show an idea:
INSERT INTO AttendeeInformations
SELECT act.*
FROM ActivityInformations act
INNER JOIN AttendeeInformations at ON act.ActivityID = at.ActivityID
WHERE act.Activityusedcount < act.activitymaxcount