I need to use a select expression in a while loop and I use the below sample code:
declare #i integer
set #i=1
while (#i<10)
begin
select #i as m;
set #i=#i+1
END
this code returns 10 separate table! I want it to return all select results in one table... is that possible? if yes... how?
You can use a temp table or table variable for this.
Here's how to do it using a temp table.
CREATE TABLE #t (m INT)
DECLARE #i INT
SET #i=1
WHILE (#i<10)
BEGIN
INSERT INTO #t SELECT #i
SET #i=#i+1
END
SELECT m FROM #t
Very similar with a table variable
DECLARE #t TABLE (m INT)
DECLARE #i INT
SET #i=1
WHILE (#i<10)
BEGIN
INSERT INTO #t SELECT #i
SET #i=#i+1
END
SELECT m FROM #t
It is not possible. Each SELECT statement generates its own result set. You can use temp table to add results of each iteration and then get all in one table. To generate sequence of integers you can use this (for SQL SERVER 2005 + )
;WITH CTE
AS
(
SELECT 1 N
UNION ALL
SELECT N + 1 FROM CTE
WHERE N<10
)
SELECT N FROM CTE
squillman got it...with #t (create table # - table persisted at top-level scope while session is open - if you have several batch statements, you can reference this table in any after declaration until you drop the table)
Cris also got it with #test (declare # table - variable - only persisted in the current scope - single execution batch block...note that there are several performance issues that can be introduced if you use this)
the last type of temp table you can use is a global temp table (create table ## - lasts as long as the session that created it stays open or until it is dropped)
with #t, you may want to add this to the beginning of your script if you don't close the session:
IF OBJECT_ID('tempdb..#t') IS NOT NULL
DROP TABLE #t
Enjoy the temp tables!
declare #i integer
DECLARE #test TABLE(
m /*your data type*/
)
set #i=1
while (#i<10)
begin
insert into #test select #i;
set #i=#i+1
END
select * from #test
Related
Consider this script to illustrate what I want:
SET NOCOUNT OFF
DECLARE #table TABLE(col1 INT IDENTITY(1,1), col2 INT)
INSERT INTO #table(col2) VALUES (1),(2),(3),(4)
This will show (4 row(s) affected)
Now what I want:
SET NOCOUNT ON
DECLARE #table TABLE(col1 INT IDENTITY(1,1), col2 INT)
INSERT INTO #table(col2) VALUES (1),(2),(3),(4)
-- do other stuff...
SET NOCOUNT OFF
SELECT ##ROWCOUNT = 666 -- return this value to client with ExecuteNonQuery()
Obviously SELECT ##ROWCOUNT = 666 is incorrect syntax.
I need to set ##ROWCOUNT manually, and return that value to a c# client with rowsAffected = ExecuteNonQuery(...)
Can this be done?
(Note: I use a stored procedure, and do not want to use an OUT parameter or return a recordset)
The obvious way to create an artificial (rows affected) message is to perform an action that affects that number of rows whilst having as few side effects as possible:
declare #t table (n int not null)
;With Numbers (n) as (
select ROW_NUMBER() OVER (ORDER BY so1.object_id)
from sys.objects so1,sys.objects so2
)
insert into #t(n) select n from Numbers where n<=666
Whether it will be sufficient to trick ExecuteNonQuery I couldn't say. (If you have an actual Numbers table you can use that in place of the CTE, though you may have to adjust the filtering if it contains 0 or negative numbers)
Another way to achieve this is:
SET NOCOUNT ON
-- Do stuff
SET NOCOUNT OFF
-- Run the actual query that will affect the specified number of rows
SET NOCOUNT ON
-- Do more stuff
Example:
CREATE PROCEDURE Example1
AS
SET NOCOUNT ON
DECLARE #table TABLE(col1 INT IDENTITY(1,1), col2 INT)
INSERT INTO #table(col2) VALUES (1),(2),(3),(4)
SET NOCOUNT OFF
SELECT a.*
INTO #NoWhere
FROM #table AS a
CROSS JOIN #table AS b
SET NOCOUNT ON
SELECT COUNT(*)
FROM #table AS a
CROSS JOIN #table AS b
GO;
EXEC Example1
-- (16 row(s) affected)
I have this code. Can I insert values into a temp table multiple times? I have list of ids (i.e. 1000 ids). I want to insert this by loop.
DECLARE #tempTable TABLE(col1 INT)
FOR (#ids IS NOT NULL) {
INSERT INTO #tempTable VALUES(#ids)
}
SELECT * FROM #tempTable
Even though it is possible using WHILE loop I will suggest you to go with SET Based approach
Why cant you just do this
INSERT INTO #tempTable (ID)
select Id from yourlist
SQL Server is not support FOR loop. You need to use WHILE loop instead.
SQL Server Looping
You can use a while statement as said Jitendra Tiwari:
DECLARE #tempTable TABLE(col1 INT)
DECLARE #num int
SET #num = 1
WHILE #num <= 1000
BEGIN
INSERT INTO #tempTable VALUES (#num) --(#ids)
SET #num = #num + 1
END
SELECT * FROM #tempTable
My teacher asks an algorithm that find all combinations. I have a set of data and the length can be variable. So combinations should be like this:
a
b
c
aa
ab
ac
...
ccbc
ccca
cccb
cccc
They will be stored in the "word" table that contains a single varchar field.
I did it with loop because I don't like recursivity and jt has better performance:
DROP PROCEDURE combi;
CREATE PROCEDURE combi
AS
BEGIN
DELETE FROM word
DECLARE #i BIGINT
DECLARE #j INT
DECLARE #word NVARCHAR(24)
DECLARE #str NVARCHAR(62)
DECLARE #combinations BIGINT
DECLARE #currentlength TINYINT
DECLARE #maxcurrentlength TINYINT
SET #maxcurrentlength=4
SET #str='azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN0123456789' -- length=62
SET #currentlength=1
-- loop on the length of the text
WHILE #currentlength<=#maxcurrentlength BEGIN
SET #combinations=POWER(62,#currentlength)
SET #i=0
-- get all combinations
WHILE i<#combinations BEGIN
SET #word=''
SET #j=0
-- generate word
WHILE #j<#currentlength BEGIN
SET #word=#word+SUBSTRING(#str, (FLOOR(#i / POWER(62,#currentlength-#j-1) ) % 62) +1, 1)
SET #j=#j+1
END
INSERT INTO word VALUES (#word)
SET #i=#i+1
END
SET #currentlength=#currentlength+1
END
END;
EXEC combi;
The problem is when I use a length of 8, my server crashes: it seems that POWER(62,#currentlength-#j-1) is the problem.
I'm slightly confused about how you ask the question. You ask to "find all combinations" which could very easily be done with CROSS JOIN. If you need to get a length of 4 then you join the table with available values to itself 4 times and you are pretty much done. If you need to get the strings in 1 field you could concatenate them in the select. Like this:
declare #values table (
value nvarchar(100))
insert #values values ('a'),('b'),('c')
select v1.value+v2.value+v3.value+v4.value
from #values v1 cross join
#values v2 cross join
#values v3 cross join
#values v4
order by v1.value+v2.value+v3.value+v4.value
Here is a generic solution using a recursive CTE:
CREATE TABLE t (i nchar(1))
INSERT INTO t VALUES ('a'),('b'),('c')
;WITH cte AS (
SELECT cast(i AS nvarchar(4000)) AS combo, 1 AS ct
FROM t
UNION ALL
SELECT cte.combo + t.i, ct + 1
FROM cte
CROSS JOIN t
WHERE ct <= 4 -- your maximum length
)
SELECT combo
FROM cte
ORDER BY ct, combo
SQL Fiddle.
You must be aware that the number of results grows exponentially with the maximum length, so performance deteriorates rapidly with growing maximum length.
You are likely overflowing the int type you are passing to POWER() as the documentation for power suggests POWER() returns the same type you feed it.
Try using:
SET #word=#word+SUBSTRING(#str, (FLOOR(#i / POWER(CAST(62 AS BIGINT),#currentlength-#j-1) ) % 62) +1, 1)
If you need to parameterise it so that you can set the required length then this algorithm would do it and it's more relational database orientated.
declare #characters table (character nchar(1))
declare #words table (word nvarchar(100))
insert #characters values ('a'),('b'),('c')
INSERT #words (word ) VALUEs ('')
DECLARE #Required_length int
DECLARE #length int
SET #Required_length = 4
SET #length = 0
WHILE #length <= #Required_length
BEGIN
SET #length = #length+1
INSERT #words (word )
SELECT w.word + c.character
FROM #words w JOIN #characters c ON LEN(w.word) = #length-1
END
SELECT word from #words where len(word) = #Required_length
Start with a zero length word
Add all the possible characters to the zero length word to get all
the one character words
Add all the possible characters to the end of all the one character
words to get all the two character words
Add all the possible characters to the end of all the two character words
to get all the three character words
etc....
You can make it run more efficiently by including the length as a column in the word table so that you don't need to calculate the lengths when you're filtering by them but as this has been set by your teacher I'm not going to do all your work for you
First insert of all characters
SET NOCOUNT ON;
create table ##chars (col char(1))
declare #i int
set #i=65
while #i<=90 /* A-Z */
begin
insert into ##chars values( CHAR(#i))
set #i=#i+1
end
set #i=97
while #i<=122 /* a-z */
begin
insert into ##chars values( CHAR(#i))
set #i=#i+1
end
set #i=48
while #i<=57 /* 0-9 */
begin
insert into ##chars values( CHAR(#i))
set #i=#i+1
end
Now, set number for combinations
create table ##result(word varchar(10))
declare #wide int
set #wide=4 /* set how many combinations are calculated */
insert into ##result select * from ##chars
while #wide>1
begin
begin tran w
insert into ##result select a.word+b.col from ##result a, ##chars b
commit tran w
set #wide=#wide-1
end
select * from ##result
/*
drop table ##chars
drop table ##result
*/
I have a simple while loop and in the loop I am declaring a DECLARE #TABLE with one column and its data type is id. While the loop loops the records I am just inserting the values into the table variable. Whenever the loop is looping it the Declare #TABLE should get recreated and the old values should not exist. But its not happening. Below is the code
Declare #V int
Set #V = 1
While (#V <= 3)
begin
DECLARE #Changes table
(
Id int
)
Insert into #Changes
Values (#V)
select * from #Changes
SET #V=#V+1
END
In normal we should get the output as
1
2
3
But the output i am getting is
1
1
2
1
2
3
Which is wrong.
Is this the normal behavior or a bug in SQL
That's normal. T-SQL is a very odd language. Variable declarations affect when a variable can be referenced, but they don't actually participate in control flow.
Consider:
IF 1 = 0
BEGIN
DECLARE #a int
END
SET #a = 1
PRINT #a
Actually prints 1. It doesn't complain about an undeclared variable.
As Allan notes in the comments, if you want #Changes to be empty at the start of each loop, make it so:
Declare #V int
DECLARE #Changes table
(
Id int
)
Set #V = 1
While (#V <= 3)
begin
delete from #Changes
Insert into #Changes
Values (#V)
select * from #Changes
SET #V=#V+1
END
Want to change this piece of SQL query into a loop version which
Could Select-Insert records by 1000 items per iteration.
On each iteration want to get a print to see what was the last inserted item.
The Code :
INSERT INTO [tData2]
(
[Key],
Info1,
Info2
)
SELECT
[Key], --the Id
Info1,
Info2
FROM
[tData]
Edit :
(There were other conditions to limit the insertion, which aren't related to the question)
The Bulk-Insertion logic will not be changed, just we shrink the database pieces to be inserted.
Instead of inserting the whole table we Bulk-Insert 10000 items per iteration and could get a simple report on it also.
your help is really appreciated.
Here's some sample code I quickly put together for you to experiment with. This doesn't use a cursor (uses while instead) but you could build it that way as well. There are some performance optimizations that you could make but only you can judge that. YMMV
set nocount on
/* mock up source/dest tables */
declare #src table (id int, value varchar(max));
declare #dest table (id int, value varchar(max));
/* fill source with some data */
declare #rownum int;
set #rownum=0;
while (#rownum<5000) begin
insert into #src select #rownum,'test value ' + CONVERT(varchar(25),#rownum);
select #rownum=#rownum+1;
end
/* laod batched data */
declare #pagesize int;set #pagesize=1000;
declare #rowlow int;set #rowlow=0;
declare #rowmax int;set #rowmax=#pagesize;
declare #ct int;select #ct = COUNT(*) from #src;
declare #id int;
declare #value varchar(max);
while (#rowmax<=#ct) begin
WITH result_set AS (
SELECT ROW_NUMBER() OVER (ORDER BY id) AS [row_number], id,value
FROM #src
) insert into #dest
SELECT id,value FROM result_set
WHERE [row_number] BETWEEN #rowlow AND #rowmax
-- Output
print 'Copied rows ' + convert(varchar(25),#rowlow) + ' to ' + convert(varchar(25),#rowmax)
-- Increment batch counters
select #rowlow=#rowmax+1,#rowmax+=#pagesize;
end
select * from #dest