SQL Server nested cursor problem - sql-server

I have a strange problem with my nested cursors and I have no idea what it's all about.
Here's my T-SQL code:
declare #dbname varchar(50)
declare #servername varchar(50)
declare srv cursor for select servername from test.dbo.servers
declare #str varchar(200)
truncate table test.dbo.temp
open srv
fetch next from srv into #servername
while ##fetch_status = 0
begin
set #str = 'Data Source='+#servername+';Integrated Security=SSPI'
declare db cursor for select name from opendatasource('SQLNCLI', #str).master.dbo.sysdatabases
open db
fetch next from db into #dbname
while ##fetch_status = 0
begin
insert test.dbo.temp (dbname, servername) values (#dbname, #servername)
fetch next from db into #dbname
end
fetch next from srv into #servername
close db
deallocate db
end
close srv
deallocate srv
It gives me next error message:
Incorrect syntax near '#str'.
[SQLSTATE 42000] (Error 102)
Looks like the problem is in giving the variable as a parameter to opendatasource function. But why? And how to avoid this problem?

You are correct that variables cannot be passed to OPENDATASOURCE. Instead You must use a literal instead. As much as we discourage using dynamic SQL, there are some cases that it is unavoidable. Try something like this:
declare #dbname varchar(50)
declare #servername varchar(50)
declare srv cursor for select servername from test.dbo.servers
declare #str varchar(200)
declare #sql nvarchar(MAX)
truncate table test.dbo.temp
open srv
fetch next from srv into #servername
while ##fetch_status = 0
begin
SET #sql = N'
declare db cursor for select name from opendatasource(''SQLNCLI'', ''Data Source='+#servername+';Integrated Security=SSPI'').master.dbo.sysdatabases
open db
fetch next from db into #dbname
while ##fetch_status = 0
begin
insert test.dbo.temp (dbname, servername) values (#dbname, #servername)
fetch next from db into #dbname
end
close db
deallocate db
'
EXEC sp_executesql
#sql,
N'#dbname varchar(50),
#servername varchar(50)',
#dbname,
#servername
fetch next from srv into #servername
end
close srv
deallocate srv

If you need to use nested cursors, you are doing something wrong. There are very few reasons to use a cursor instead of some other set-based operation, and using a cursor within a cursor is like the ultimate SQL Server anti-pattern.
For your inner cursor, you could change it to use the undocumented sp_msforeachdb function (which apparently creates a cursor behind the scenes):
open srv
fetch next from srv into #servername
while ##fetch_status = 0
begin
EXEC sp_msforeachdb '
Data Source='+#servername+';Integrated Security=SSPI
insert test.dbo.temp (dbname, servername) values (?, #Servername)'
fetch next from srv into #servername
end
close srv
deallocate srv
You may need to enclose the ? in single quotes and escape them, like:
EXEC sp_msforeachdb 'insert test.dbo.temp (dbname, servername) values (''?'', #Servername)

Related

SQL Server logins are locked out but not really locked out

I create Logins for a lot of people. They work mostly but a few now and then behave like this:
Logins are authenticated through SQL Server Authentication. The person gets this message:
When I look at the Login I see this:
So it tells me they are not locked out. I have to edit their pw and the login starts working again. I don't even have to change the PW, I just re-enter the current one. Am I missing something?
Here is the script that creates the Login:
ALTER PROCEDURE [dbo].[spCreateLogins]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #newdb sysname
DECLARE #studentID AS varchar(20)
begin try
close student_cursor
DEALLOCATE student_cursor
end try
begin catch
end catch
DECLARE student_cursor CURSOR FOR SELECT UserName FROM tStudent where studentid>35
DECLARE #SQL NVARCHAR(4000)
OPEN student_cursor
FETCH NEXT FROM student_cursor
INTO #studentID
WHILE ##FETCH_STATUS = 0
BEGIN
-- Create the user name
SET #SQL = 'CREATE LOGIN ' + ltrim(rtrim(#StudentID)) + ' WITH PASSWORD = ''P#ssword1'', DEFAULT_DATABASE=' + ltrim(rtrim(#StudentID)) + ', CHECK_EXPIRATION=OFF, CHECK_POLICY=ON';
print #SQL
EXECUTE(#SQL);
FETCH NEXT FROM student_cursor
INTO #studentID
END
END
I looked in Security Settings-->Account Policies-->AccountLockout policy in secpol.msc as suggested by #SEarle1986. I had no idea a lockout could be temporary. :)

Not displaying select results from dynamic SQL within Cursor

I'm currently learning SQL and trying to think of exercises for myself and I can't seem to make this one work even though it seems simple:
I'm trying to run a cursor through all the filtered tables within my db so that then I could pass that table name to a variable which will be used within a DynamicSQL inside the cursor. The end result should be all values from every column that has the column 'empid' in them.
However, the message returns as "Commands completed successfully" but I get to see no results despite my select statement.
I'm trying to run something like this:
declare #tablename nvarchar(200);
declare #empid int;
declare #sql nvarchar(200) = N'select * from ' + #tablename + N' where empid = ' +#empid;
declare tablecursor cursor for select table_name from information_schema.tables where col_length(table_name, 'empid') is not null;
open tablecursor;
fetch next from tablecursor into #tablename;
while ##fetch_status = 0
begin
execute sp_executesql #sql, 825
fetch next from tablecursor into #tablename;
end
close tablecursor;
deallocate tablecursor;
I've been searching everywhere for answers to make this work but can't find anything. I've tried putting into a stored procedure and then executing it from there but that didn't work either.
Help would be highly appreciated.
DECLARE #SQL Should be outside but assigning the Variable inside the while loop
SET #SQL = N'SELECT * FROM ' + #tableName
Should be in while loop.
The other thing is to increase the length of #SQL Variable.
Thank you kindly for the help. After I listened to your advice I've encountered more errors but at least for these I was able to find answers online. What I also learnt is that you can't have your sql string in quotes when you execute it as that will make SSMS treat #SQL as an actual string and not a variable. I've managed to get it working and my code now looks something like this:
create proc cdr #empid nvarchar(5) as
declare #tablename nvarchar(200);
declare tablecursor cursor for select table_name from information_schema.tables where col_length(table_name, 'empid') is not null;
open tablecursor;
fetch next from tablecursor into #tablename;
declare #sql nvarchar(max)
while ##fetch_status = 0
begin
set #sql = N'select * from ' + #tablename + N' where empid = ' + #empid;
execute sp_executesql #sql
fetch next from tablecursor into #tablename;
end
close tablecursor;
deallocate tablecursor;

update statement value in multi table at once

I have over 100 tables in SQL Server 2000 with the same column name in each table. Now I want to update a value in 100 tables at once using a SQL update statement.
How do I do that? I try to google and stackoverflow but not really help.
Thanks so much
Create a cursor for all table in your database and using dynamic query to execute.
This script will be help you do this.
--USE [Your DB]
--GO
DECLARE #tableName VARCHAR(100)
DECLARE #sqlQuery VARCHAR(MAX)
DECLARE curTable CURSOR FOR SELECT name FROM sys.objects WHERE type_desc = 'USER_TABLE' AND name NOT IN ('sysdiagrams')
OPEN curTable
FETCH NEXT FROM curTable INTO #tableName
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #sqlQuery = 'UPDATE ' + #tableName + 'SET [YourCol1] = [YourVal1], [YourCol2] = [YourVal2] ...'
PRINT #sqlQuery
EXECUTE sp_executesql #sqlQuery
FETCH NEXT FROM curTable INTO #tableName
END
CLOSE curTable
DEALLOCATE curTable

Query number of records across all databases

I have multiple databases in my SQL Server. All databases are the same in structure but have different data. These databases are used to store sensor data so each sensor has it's own seperate DB in the SQL Server.
I want a query to Select the Database name and number of records in a specific table of each DB.
I tried with a cursor. I get error saying the name {query} is not a valid identifier. My Cursor is as follows:
Declare #dbname Varchar (50), #sql Varchar(1000)
Declare db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name LIKE 'EP505-%' -- All sensors of EP505
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql= 'SELECT Count(*) FROM [' + #dbname + '].dbo.TimeLine'
EXEC #sql
FETCH NEXT FROM db_cursor INTO #dbname
END
CLOSE db_cursor
DEALLOCATE db_cursor
In the output I require the db name and the number of records for the TimeLine table.
What's the best way to achieve what I am trying.
Use parentheses when executing a SQL query string like so:
EXEC (#sql). Without parentheses, SQL Server will interpret #sql as a stored procedure or user-defined function.
your attempt looks quite good so far.
Please try adding a fetch next below the exec-line and try putting the #SQL variable after the exec brackets. That worked in my SQL Server environment.
hope this helps
br
Patrik
You can use sp_executeSQL to execute your dynamic query instead of exec statement which will help you to solve your issue
Here is the modified version
Declare #dbname Varchar (50), #sql nVarchar(1000)
Declare db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name LIKE 'kodyaz' -- All sensors of EP505
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql= N'SELECT Count(*) FROM [' + #dbname + '].dbo.Kontaktpersonen'
exec sp_executesql #sql
FETCH NEXT FROM db_cursor INTO #dbname
END
CLOSE db_cursor
DEALLOCATE db_cursor
I change #sql data type to nvarchar() and use
exec sp_executesql #sql

Dynamic SQL parameter error, Incorrect syntax near '#myparametername'

I'm building a fun stored procedure that will use dynamic SQL, sp_executesql with parameters, to allow some alter statements for a column in all database tables if the column name exists ( As you can see I used a cursor for loop all the tables on DB)
I built a test but the parameter doesn't work, I get the next error on each alter table statement that runs
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '#parTablename'.
The next is the code
SET NOCOUNT ON;
GO
DECLARE #tablename varchar(100);
DECLARE #alteredColumn varchar(100)='[mycolumn] [datetimeoffset](0) NOT NULL;';
DECLARE #column varchar(100)='mycolumn';
DECLARE #parDefinition nvarchar(500) = N'#parTablename nvarchar(100)';
DECLARE #sqlCommand nvarchar(1000)= N'ALTER TABLE #parTablename ALTER COLUMN '+#alteredColumn;
DECLARE ALTERCURSOR CURSOR LOCAL FAST_FORWARD FOR
SELECT name AS tablename
FROM sys.Tables
OPEN ALTERCURSOR;
FETCH NEXT FROM ALTERCURSOR INTO #tablename
WHILE ##FETCH_STATUS = 0
BEGIN
--print #tablename
IF EXISTS(SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tablename AND COLUMN_NAME = #column)
BEGIN
EXECUTE sp_executesql #sqlCommand, #parDefinition,#parTablename = #tablename
END
FETCH NEXT FROM ALTERCURSOR INTO #tablename
END
CLOSE ALTERCURSOR;
DEALLOCATE ALTERCURSOR;
SET NOCOUNT OFF;
GO
SOLUTION
Apparently is not possible to send a table name as a parameter, instead of that I used the #SeanLange option for degub with a little modification
SET #sqlCommand =Replace(#sqlCommand, '#parTablename',QUOTENAME(#tablename))
EXECUTE sp_executesql #sqlCommand
You can't stick a parameter in the middle of your dynamic sql like this. You need to use PRINT instead of EXECUTE to debug this. I wouldn't use a cursor for this myself but if you go that path you will have to do something like this before the EXECUTE statement.
Set #sqlCommand = Replace(sqlCommand, '#parTablename', #parTablename)

Resources