I'm running a Restore Verify Only loop through a table, but I need it to UPDATE a field in that table if it's successful. Here is my code:
DECLARE #Path NVARCHAR(max)
DECLARE #DatabaseName NVARCHAR(100)
DECLARE #NSql NVARCHAR(1000)
DECLARE #Update NVARCHAR(200)
DECLARE #DB_Text NVARCHAR(50)= 'Backup has been confirmed for'
BEGIN
DECLARE
#DatabaseId INT = 1,
#NumberOfDBs INT
SELECT #NumberOfDBs= COUNT(*) FROM dbo.RestoreVerifyDatabases
WHILE #DatabaseId<= #NumberOfDBs
BEGIN
SELECT * FROM dbo.RestoreVerifyDatabases WHERE DatabaseId= #DatabaseId
SET #DatabaseId = #DatabaseId + 1
END
SET #Path = (SELECT LastBackupFileName FROM RestoreVerifyDatabases WHERE DatabaseId =
#DatabaseId)
SET #DatabaseName = (SELECT DatabaseName FROM RestoreVerifyDatabases WHERE DatabaseId =
#DatabaseId)
SET #NSql = N'SELECT LastBackupFileName
FROM RestoreVerifyDatabases
WHERE DatabaseName = #DatabaseName
AND DatabaseId = #DatabaseId'
EXEC sp_executesql #NSql
IF #DatabaseId IS NULL
BEGIN
RAISERROR(N'Verify failed. Backup information for database N''#DatabaseName'' not
found.', 16, 1)
END
RESTORE VERIFYONLY
FROM #Path
WITH FILE = #DatabaseId, checksum
SET #Update= N'UPDATE RestoreVerifyDatabases
SET Confirmed = #DB_Text + #DatabaseName
WHERE DatabaseID = #DatabaseId'
EXEC sp_executesql #Update
END
The looping and calling of Restore Verify Only works fine but the UPDATE is not getting called. Please help.
There's a few things wrong with your code as far as I can see. As my comment indicated, you run a loop over the #databaseID, and then immediately increase the id with 1 within the loop.
This means your #databaseId simply will increase until it reaches the maximum value of the id, and then exits the loop. The rest of your code will then execute once (only for that ID).
That happens here in your code:
SELECT #NumberOfDBs= COUNT(*) FROM dbo.RestoreVerifyDatabases
WHILE #DatabaseId<= #NumberOfDBs
BEGIN
SELECT * FROM dbo.RestoreVerifyDatabases WHERE DatabaseId= #DatabaseId
SET #DatabaseId = #DatabaseId + 1
END
-- Bunch of other code
So #databaseID goes from 1 to 50 (just a random number) within that loop, then exists with a value of 50. None of the underlying code ever gets to see any value other than 50.
To fix that, the code should look like this:
SELECT #NumberOfDBs= COUNT(*) FROM dbo.RestoreVerifyDatabases
WHILE #DatabaseId<= #NumberOfDBs
BEGIN
SELECT * FROM dbo.RestoreVerifyDatabases WHERE DatabaseId= #DatabaseId
-- Bunch of other code
SET #DatabaseId = #DatabaseId + 1
END
This would ensure the "bunch of other code" processes #databaseid = 1, then processes #databaseid = 2, etc. until #databaseid = 50.
You can also remove this line:
SELECT * FROM dbo.RestoreVerifyDatabases WHERE DatabaseId= #DatabaseId
I suspect you have it for debugging purposes, but it doesn't really do anything.
These lines can be simplified:
SET #Path = (SELECT LastBackupFileName FROM RestoreVerifyDatabases WHERE DatabaseId =
#DatabaseId)
SET #DatabaseName = (SELECT DatabaseName FROM RestoreVerifyDatabases WHERE DatabaseId =
#DatabaseId)
as:
SELECT #Path = LastBackupFileName, #DatabaseName = DatabaseName FROM RestoreVerifyDatabases WHERE DatabaseId = #DatabaseId
You also have a RAISEERROR. I suspect that is because you do a count(*), rather than selecting actually existing #databaseids. This works in an ideal scenario, where databases never get deleted. In the reasl world, though, you'd go from databaseid 1 to 5, because 2, 3, and 4 were removed. Your count will still be 50 databases, but you'd miss all databases with ids above the count due to these gaps. You'd be trying to process the databaseid that no longer exists, and miss the ones with an id > 50.
You could instead write your loop to do something like the following:
SELECT #DatabaseID = MIN(DatabaseID) FROM dbo.RestoreVerifyDatabases
WHILE #datbaseID IS NOT NULL
BEGIN
-- Do stuff
SELECT #DatabaseID = MIN(DatabaseID) FROM dbo.RestoreVerifyDatabases WHERE databaseID > #databaseID
END
Finally, your dynamic code isn't working. You are adding literal text rather than the value of the parameters. If I print the value of #Update at the end, it shows as:
UPDATE RestoreVerifyDatabases
SET Confirmed = #DB_Text + #DatabaseName
WHERE DatabaseID = #DatabaseId
Your code should be something like:
SET #Update= CONCAT('UPDATE RestoreVerifyDatabases SET Confirmed = ''', #DB_Text, ' ', #DatabaseName, ''' WHERE DatabaseID = ', #DatabaseId)
Which outputs:
UPDATE RestoreVerifyDatabases SET Confirmed = 'Backup has been confirmed for Last' WHERE DatabaseID = 2
Related
I have a variable which holds the database that I am working on. How can I add this variable in a static query?
This is what I want to achieve:
if exists(select * from #DestinationDB.[RaPa] where tid = #dyid)
begin
RAISERROR('Rapa exist',16,1)
end
I'm not sure if you meant without Dynamic SQL... but here is how you can accomplish this with dynamic SQL
declare #DestinationDB varchar(64)
declare #dyid int
declare #sql varchar(max)
set #DestinationDB = 'SomeDB'
set #dyid = 14
set #sql =
'if exists(select * from ' + quotename(#DestinationDB) + '.[RaPa] where tid = ' + cast(#dyid as varchar(16)) + ')
begin
RAISERROR(''Rapa exist'',16,1)
end'
print #sql
--exec(#sql)
Just uncomment the exec part when you are satisfied with the command.
I have a stored procedure that is called to establish sequence numbers for a specific client account. A simple table stores the last issued value for all clients and the SP will just take a parameter of SupplyChainID and how many numbers are required.
GetItemIDs
So SupplyChainID 12345 might have 5 as its last issued number, so running
GetItemIDs 12345,200
would return 5 and then set the value to 205 for next time
So the current SP does something like this as it has to check it does not go beyond 99,999,999. (goes back to 0 if it would go over)
IF (SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID) + #DocumentCount > 99999999
BEGIN
SELECT 0
UPDATE dbo.ItemIDGeneration SET EIBItemID = #DocumentCount,
LastIssuedDate = getdate() WHERE SupplyChainID = #SCID
END
ELSE
BEGIN
SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
UPDATE dbo.ItemIDGeneration SET EIBItemID = EIBItemID + #DocumentCount,
LastIssuedDate = getdate() WHERE SupplyChainID = #SCID
END
What I need to add is a check of another table to see if that has a higher value and in which case use that one instead of the last issued number from the ItemGeneration table
Something like this:
SELECT #HI_ID = MAX(EIBItemID) from
(SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
UNION ALL
SELECT ISNULL(MAX(EIBItemID),0) AS EIBItemID FROM dbo.SupplyChainID_'+ #tablename) as bigint
IF (#HI_ID) + #DocumentCount > 99999999
BEGIN
SELECT 0
UPDATE dbo.ItemIDGeneration SET EIBItemID=#DocumentCount,LastIssuedDate = getdate() WHERE SupplyChainID = #SCID END
ELSE
BEGIN
SELECT #HI_ID--EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
UPDATE dbo.ItemIDGeneration SET EIBItemID = #HI_ID +#DocumentCount,LastIssuedDate = getdate() WHERE SupplyChainID = #SCID
END
As you can see the table has the same SupplyChainID as part of the table name so I know I need to pass it in as part of a query and exec it but I can't get the following to work
SET #tablename = 'dbo.SupplyChain_'+#SCID
SET #tablequery = N'SELECT ISNULL(MAX(EIBItemID),0) AS EIBItemID FROM ' + #tablename
execute #tableID = sp_executesql #tablequery
SELECT #HI_ID = MAX(EIBItemID) from
(SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
union all
SELECT #tableID) as bigint
IF (#HI_ID) + #DocumentCount > 99999999
The process doesn't error but I think I have something wrong in my syntax as when I run the following
declare #return int
exec #return = GetItemIDs 8001377,20
select #return as result
I see EIBItemID returned as the correct result from the dbo.SupplyChain_xxxxx table but the return value from the end of the sp is the reply based on the ItemIDGeneration table (returns 200).
I think it's visibly returning the correct result when the exec is called but storing 0 in #tableid
You can try this to get the value:
DECLARE #SCID INT = 1
DECLARE #TableName NVARCHAR(100) = N'dbo.SupplyChain_' + CAST(#SCID AS NVARCHAR(10))
DECLARE #TableID BIGINT
DECLARE #TableQuery NVARCHAR(1000) = N'SELECT #TableID = ISNULL(MAX(EIBItemID), 0) FROM ' + #TableName
EXEC sp_ExecuteSql #TableQuery, N'#TableID BIGINT OUTPUT', #TableID OUTPUT
PRINT #TableID
Thanks to all that answered, I used Alex's suggestion with a small tweak
DECLARE #HI_ID as bigint
DECLARE #TableName NVARCHAR(100) = N'dbo.SupplyChain_' + CAST(#SCID AS NVARCHAR(10))
DECLARE #TableID BIGINT
DECLARE #TableQuery NVARCHAR(1000) = N'SELECT #TableID = ISNULL(MAX(EIBItemID),0) FROM ' + #TableName
EXEC sp_ExecuteSql #TableQuery, N'#TableID BIGINT OUTPUT', #TableID OUTPUT
SELECT #TableID As EIBItemID
How to create an insert with select query in a variables using SQL Server?
Here for example:
DECLARE #sqlCommand nvarchar(MAX)
DECLARE #odbname varchar(30)
DECLARE #m VARCHAR(20)
DECLARE #id VARCHAR(20)
DECLARE #br VARCHAR(30)
DECLARE #ndbname VARCHAR(30)
SET #ndbname='databasename'
SET #id = 2
SET #odbname = 'olddatabasename'
SET #br = 2
SET #m = 9
DECLARE #insert VARCHAR(MAX)
SET #insert = 'INSERT INTO'+ #ndbname+'.[pm]([pmId],[pmCode],[pmName])'
EXEC (#insert)
SET #sqlCommand = 'SELECT #id AS spID,[spCode],[spName] `enter code here`FROM' + #0dbname+'.[sp] where spbID = #br and spID = #m'
EXECUTE sp_executesql #sqlCommand, N'#br nvarchar(75),#m nvarchar(75),#id VARCHAR(20)',#br = #br,#m=#m,#id=#id
Actually I needed a select query executed in insert query ie, selected data inserted in to another database table
SET #insert='INSERT INTO'+ #ndbname+'.[pm]([pmId],[pmCode],[pmName])'
SET #sqlCommand = #insert + ' ' +'SELECT #id AS spID,[spCode],[spName] `enter code here`FROM' + #0dbname+'.[sp] where spbID = #br and spID = #m'
EXECUTE sp_executesql #sqlCommand, N'#br nvarchar(75),#m nvarchar(75),#id VARCHAR(20)',#br = #br,#m=#m,#id=#id
There are quite a few flaws:
You try to execute the INSERT alone
If you state a dbName, you must specify the schema (is it "dbo"?)
You're letting out spaces
If you change to this
SET #insert='INSERT INTO'+ #ndbname+'.[pm]([pmId],[pmCode],[pmName])'
SET #sqlCommand = #insert + ' SELECT #id AS spID,[spCode],[spName] `enter code here`FROM' + #odbname+'.[sp] where spbID = #br and spID = #m'
PRINT #sqlCommand
You'll get this:
INSERT INTOdatabasename.[pm]([pmId],[pmCode],[pmName]) SELECT #id AS spID,[spCode],[spName] `enter code here`FROMolddatabasename.[sp] where spbID = #br and spID = #m
But it should be something like this
INSERT INTO databasename.[schema].[pm]([pmId],[pmCode],[pmName])
SELECT #id,[spCode],[spName]
FROM olddatabasename.[schema].[sp]
where spbID = #br and spID = #m
General hints:
Don't use dynamic SQL if you don't need it
If you build dynamic sql don't try to execute it. Rather print it, copy it to a query window and analyze if it is OK
I have the following T-SQL pseudo-code query
SET #Loop = 1
WHILE #Loop > 0
BEGIN
IF (#Table_name = 'abcdef')
BEGIN
SET #SqlCmd = 'update top 1000 #Table_name
set columnA = ''haha'''
END
ELSE
BEGIN
SET #SqlCmd = 'update top 1000 #Table_name
set columnA = ''hehe'''
END
EXEC dbo.sp_executesql #SqlCmd
SET #Loop = ##RowCount
END
Now, assume the both #Table_name (abcdef and the other one) has 5000 records, the update statement inside the "ELSE" clause would just run 5 times and get out of the loop. But, the update statement inside the "IF" clause is falling into an infinite loop. I believe the cause is ##RowCount being interrupted by the IF (#Table_name = 'abcdef'). because ##RowCount always return 1 when running inside that block.
I have a quick (but really ugly) solution for this as follow:
SET #Loop = 1
WHILE #Loop > 0
IF (#Table_name = 'abcdef')
BEGIN
SET #SqlCmd = 'update top 1000 #Table_name
set columnA = ''haha'''
SELECT #Loop = COUNT(1) FROM #Table_name WHERE columnA != 'haha'
END
ELSE
BEGIN
SET #SqlCmd = 'update top 1000 #Table_name
set columnA = ''hehe'''
SET #Loop = ##RowCount
END
EXEC dbo.sp_executesql #SqlCmd
END
Although the above solution would work, is there a better way to solve the problem? Eager to learn more, thanks!
Your problem isn't ##ROWCOUNT. It is:
update top 1000 #Table_name
set columnA = 'haha';
If you run this in a loop, it is going to set the same rows over and over. Perhaps you should use:
update top 1000 #Table_name
set columnA = 'haha'
where columnA <> 'haha';
This is in SQL server 2012. I'm on Sever Management studio.
I have multiple servers that have multiple databases that I need to feed it a varying list of Database names to pull back a sum of a size field. At the moment #sql2 updates the BR_ProductionSize to the actual select statement instead of the answer to that statement.
DECLARE #TempCaseArtifactID NVARCHAR(60)
DECLARE #sql2 NVARCHAR(200)
DECLARE #answer NVARCHAR(200)
set #TempCaseArtifactID = (select '[EDDS'+BR_CaseArtifactid+'].[EDDSDBO].[File]' from #BRFindSizes where UpdateCompleted = '2')
set #sql2 = '(select SUM(size) FROM '+#TempCaseArtifactID + ' where TYPE = 3 and InRepository = 1)'
IF (select BR_sqlServerID from #BRFindSizes where UpdateCompleted = '2') = 1015083
Begin
update #BRFindSizes
set BR_ProductionSize = #sql2
where UpdateCompleted = '2'
end
This answer is untested and might have some syntax errors, but it represents the gist of what you want to do.
You have this (actually, I put in the SumOfSizes alias):
set #sql2 = '(select SUM(size) SumOfSizes
FROM '+#TempCaseArtifactID + '
where TYPE = 3 and InRepository = 1)'
Which is a string. To the the value, you have to execute that query and put the result into a variable. This is the general idea.
set #valueIWant = SumOfSizes from
sp_executesql #SQLString #sql2
Then you use the #valueIWant variable in your update query.
For the correct syntax, read this.
You have to Execute the dynamic statement that you have created, to use the value generated.
What you should do is
DECLARE #sql2 VARCHAR(50) = EXEC '(select CONVERT(VARCHAR, SUM(size)) FROM '
+ #TempCaseArtifactID
+ ' where TYPE = 3 and InRepository = 1)'
And then
IF (select BR_sqlServerID from #BRFindSizes where UpdateCompleted = '2') = 1015083
BEGIN
UPDATE #BRFindSizes
SET BR_ProductionSize = #sql2
WHERE UpdateCompleted = '2'
END
The same thing goes for #TempCaseArtifactID.