SQL Looping temp table and reading data - sql

I have following script to create temp data
DECLARE #Name NVARCHAR(100), #Marks INT
DECLARE #MYTABLE TABLE
(
[Name][nvarchar](100) NULL,
[Marks][INT] NULL
)
INSERT INTO #MYTABLE ([Name],[Marks]) VALUES ('Mark',50);
INSERT INTO #MYTABLE ([Name],[Marks]) VALUES ('Steve',50);
INSERT INTO #MYTABLE ([Name],[Marks]) VALUES ('Don',50);
Now I want loop it, as shown in below script
SELECT #MaxPK = MAX(PK) from #MYTABLE
WHILE #PK <= #MaxPK
BEGIN
SET #Name = SELECT Name from #MYTABLE
SET #Marks = SELECT Marks from #MYTABLE
print #Name
print #Marks
SET #PK = #PK + 1
END
But I get error near SELECT statement.
"Incorrect syntax near the keyword SELECT"!

The two rows where you set the variables can be put together like this. That way you will only scan the table once.
SELECT #Name = Name, #Marks = Marks FROM #MYTABLE
Just know that the row chosen to be put in your variables is completely arbitary (and will probably be the same row every time) unless you add a whereclause.

Please try below while loop:
WHILE #PK <= #MaxPK
BEGIN
SELECT #Name = Name, #Marks = Marks from #MYTABLE
print #Name
print #Marks
END
Note: I guess, a where condition is required in select statement in order to print all data.

Related

Get value depending of current iteration on while loop

Currently I'm using SQL Server Management Studio v18, and I want to iterate a Table Type using a while loop, so I do:
CREATE TYPE [VarcharIdTableType] AS TABLE
(
[FileName] VARCHAR(MAX)
)
Then I use a while loop as:
DECLARE #FileTableType [VarcharIdTableType]
INSERT INTO #FileTableType
VALUES ('test1'),('test2'),('test3')
DECLARE #FileCount INT = (SELECT COUNT(*) FROM #FileTableType), #RowCount INT = 0
WHILE #RowCount <= #FileCount
BEGIN
DECLARE #Content VARCHAR(555)= CONCAT('File name ', #filename)
SET #RowCount = #RowCount + 1;
END
So I want to get each FileName depending of iteration number, how can I achieve that?
IMPORTANT: Do you actually need a loop? As you haven't shown us what your desired final outcome is we are unable to comment. But in many cases a set based approach will accomplish what you need and if so it should be used.
Making a few assumptions, such as no ID column in your table, and being able to delete rows from your table variable, I would do the following using exists rather than counting rows.
DECLARE #FileTableType TABLE ([Name] VARCHAR(MAX));
INSERT INTO #FileTableType([Name]) VALUES ('test1'), ('test2'), ('test3');
DECLARE #Content VARCHAR(MAX) = '', #Filename VARCHAR(MAX);
WHILE EXISTS (SELECT 1 FROM #FileTableType)
BEGIN
SELECT TOP 1 #Filename = [Name] FROM #FileTableType;
SET #Content = CONCAT('File number ', #Filename);
DELETE FROM #FileTableType WHERE [Name] = #Filename;
END;
However having a known unique identifier on the values in the table variable would be better because if you have duplicate filenames the first code will have issues.
DECLARE #FileTableType TABLE (id INT IDENTITY(1,1), [Name] VARCHAR(MAX));
INSERT INTO #FileTableType([Name]) VALUES ('test1'), ('test2'), ('test3');
DECLARE #Content VARCHAR(MAX) = '', #Filename VARCHAR(555), #FileId INT;
WHILE EXISTS (SELECT 1 FROM #FileTableType)
BEGIN
SELECT TOP 1 #FileId = id, #Filename = [Name] FROM #FileTableType;
SET #Content = CONCAT('File number ', #Filename);
DELETE FROM #FileTableType WHERE id = #FileId;
END;
Note the best practices:
Terminating all statements with a semi-colon
Listing all columns when inserting
Using VARCHAR(MAX) for #Content since the filename is.

Using while exists in triggers sends the query in infinite loop

I created a trigger for insert and it works fine. This creates the trigger just fine:
While (exists(Select Id from #temp))
But the insert query is going into an infinite loop. I am using while exists to accommodate multiple insertions at a time. Can anyone tell me what is causing the infinite loop?
Create Table sqltutorial.Employee
(
Id int,
Name nvarchar(50),
Salary int,
Gender nvarchar(50),
DepartmentId int
)
Alter Trigger sqltutorial.trg_forinsert_Employee
on sqltutorial.Employee
For Insert
As
Begin
print 'Audit Begins'
Declare #Id int, #Name nvarchar(50), #Salary int,
#Gender nvarchar(50), #DepartmentId nvarchar(50)
Declare #AuditText nvarchar(500)
Select *
into #temp
from inserted
While (exists(Select Id from #temp))
Select #Id = Id from #temp
Select
#Id = Id, #Name = Name, #Salary = Salary,
#Gender = Gender, #DepartmentId = DepartmentID
from
#temp
Set #AuditText = 'New Record Inserted With Id='+Cast(#Id As nvarchar(50))+',Name='+#Name+' ,Salary='+CAST(#Salary as nvarchar(50))+' Gender'+#Gender
+' ,Department Id='+#DepartmentId+' on '+CAST((Select GETDATE()) AS nvarchar(50))+' by '+(Select system_user)
Insert into sqltutorial.AuditTrial
values (#AuditText)
Delete from #temp
where Id = #Id
print 'Audit Ends'
End
The reason for the infinite loop is that you did not specify a BEGIN and END to your WHILE loop code block like this:
WHILE SomeCondition = true
BEGIN
Do stuff
END
When you use WHILE and don't specify BEGIN..END, the WHILE loop repeats the next statement only, over and over until the WHILE condition is no longer met. And in your code, that would never happen, since the next statement doesn't delete anything from #temp.
In other words, in your code, this is what you are looping:
While (exists(Select Id from #temp))
Select #Id = Id from #temp
The rest of the code after this never even executes because the WHILE loop never exits.
You don't need to use all the variables and temp tables in your trigger simply do the following:
ALTER TRIGGER sqltutorial.trg_forinsert_Employee
ON sqltutorial.Employee
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO sqltutorial.AuditTrial
SELECT
' New Record Inserted With Id=' + CAST([Id] AS NVARCHAR(50)) +
',Name=' + [Name] +
',Salary=' + CAST(Salary AS NVARCHAR(50)) +
',Gender' + Gender +
',Department Id=' + DepartmentId +
' on ' + CAST((SELECT GETDATE()) AS NVARCHAR(50)) +
' by ' + CAST(system_user AS NVARCHAR(256))
FROM
inserted
END

How to insert values into table from stored procedure inputs as well as temp table

I have a stored procedure like this:
create procedure spname
#ID varchar,
#name varchar,
#R xml
AS
BEGIN
-- Getting values XML
create table #Table
(
country varchar,
status varchar
)
I have to insert the values into a table based on the condition that if ID, Name which are from stored procedure input and country (from temp table) doesn't exists, then insert. I don't know exact syntax os how to join all these. However I tried below, but I reckon its wrong, I think I must some some looping technique like cursor?
DECLARE #Country VARCHAR;
SELECT #Country = C.Country
FROM #Table C
INSERT INTO MyTable(Id, Name, Country)
VALUES (#Id, #Name, #Country)
FROM
WHERE NOT EXISTS (SELECT 1 FROM MyTable mT
WHERE ID = #Id
AND Name = #Name
AND mt.country = C.country)
I am thinking there is wrong syntax in values as well as it will not serve my purpose as temp table contains a lot of values
I came up with a solution this way using cursor:
DECLARE #country VARCHAR
DECLARE CountryCur CURSOR FOR
SELECT Country FROM #Temp
OPEN CountryCur
FETCH NEXT FROM CountryCur INTO #Country
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO MyTable(Id, Name, Country)
VALUES (#id, #name, #Country)
WHERE NOT IN (SELECT 1 FROM MyTable mT
WHERE mT.Id = #Id
AND mT.name = #name
AND mT.country = #Country)
FETCH NEXT FROM CountryCur INTO #Country
CLOSE CountryCur
DEALLOCATE CountryCur
However, it shows syntax error near where. Don't know whats wrong.
well as you have mentioned you have the data in the #temp table coming from xml then it should be as simple as
INSERT INTO MyTable(Id,Name,Country)
SELECT #Id, #Name, t.Country
FROM #Table t
WHERE NOT EXISTS (SELECT 1
FROM MyTable mT
WHERE mt.ID = #Id
AND mt.Name = #Name
AND mt.country= t.country)
No Cursor needed
You need to use SELECT...INTO instead of VALUES() as below:
INSERT INTO MyTable(
Id,
Name,
Country
)
select #ID, #Name, #Country
WHERE not exists(select 1 from MyTable
WHERE ID = #Id
AND Name = #Name
AND country in (Select country from #Temp))

Determine all columns from a table and write them separated by commas in a variable

--Dummy table
create table table1 (
column_order varchar (100)
)
insert into table1 values ('column1')
insert into table1 values ('column2')
insert into table1 values ('column3')
insert into table1 values ('column4')
insert into table1 values ('column5')
insert into table1 values ('column6')
--Start of select
declare #rowsCount INT
declare #i INT = 1
declare #column varchar(1000) = ''
set #rowsCount = (select COUNT(*) from table1)
while #i <= #rowsCount
begin
set #column = #column + (select column_order from table1 where rowid(table1) = #i) + ', '
set #i = #i + 1
end
select #column
This code has the function ROWID thats an IQ-Sybase funktion, and im not sure what other DBMS can use it. And above you have a example what i want my select to look like.
My problem is, you cant use the ROWID function with sys.column or any other systables. Has anyone an idea how to get the same select as mine without using the ROWID function.
If you are using IQ, i constructed the code so you can just type f5 and see the select statement, after that just drop the dummy table.
Use list(). It works in both the ASA system and IQ catalogs.
drop table if exists table1
go
create local temporary table table1 (
column_order varchar (100)
) in system --create table in system
insert into table1 values ('column1')
insert into table1 values ('column2')
insert into table1 values ('column3')
insert into table1 values ('column4')
insert into table1 values ('column5')
insert into table1 values ('column6')
declare #columns varchar(100)
select #columns = list(column_order) from table1
select #columns
go
I may be not understand your need, because I can't see why you need rowdid.
Usually, in TSQL, I do as follow:
declare #someVar as nvarchar(max)
set #someVar = (select
'[' + c.name + '],' as 'data()'
from
sys.columns c
join sys.tables t on c.object_id = t.object_id
where
t.name = 'SomeTableName'
for xml path(''))
print Left(#someVar, Len(#someVar) - 1)
Maybe you will need to use a cursor:
-- #MyTableID has to be definded somewhere or replace
DECLARE #columns varchar(32000)
DECLARE my_cursor CURSOR FOR
SELECT syscolumn.column_name FROM syscolumn WHERE syscolumn.table_id = #MyTableID
OPEN my_cursor
FETCH NEXT my_cursor into #column
WHILE ##FETCH_STATUS = 0
BEGIN
-- put your magic here
-- e.g.
-- SET #columns = #columns + column
FETCH NEXT my_cursor_pkey into #column
END
CLOSE my_cursor
DEALLOCATE my_cursor
Not tested yet, but something like that should work.

Suppress result from insert trigger

A MS SQL insert trigger causes some grief as it returns a result. Is there a way to disable any result from being sent? I've used 'set nocount on', but that doesn't seem to do much...
create trigger tr_insert_raw_data
on raw_data
instead of insert
as
begin
set nocount on
declare #query varchar(max);
declare #rev int;
declare #id int;
declare #oldrev int;
declare #contextinfo VARBINARY(128)
select #contextinfo = context_info()
if #contextinfo = 0x00001
begin
insert into raw_data select * from inserted
return
end
select * into #query from inserted
set #id = (select count(distinct id) from raw_data);
set #id += 1;
insert into revisions (username, hostname, ts) values (SYSTEM_USER, HOST_NAME(), GETDATE())
set #rev = (select max(id) from revisions);
select #oldrev = revision_id from inserted;
if #oldrev is null set #oldrev=#rev-1;
select * into #inserted from inserted
update #inserted set revision_id = #rev, id = #id
select * from #inserted
insert into raw_data select * from #inserted
insert into edges (a, b) values (#oldrev, #rev)
end
what kind of a result are you getting?
After a quick review of your query my first thought is that you're getting results due to the
select * from #inserted
line you have (third line from bottom). This line tells me that you are requesting results which is probably why you're getting some?
If you do need values selected from a table to modify or custom select out of, perhaps CTE's will help you out? (Common Table Expressions)