Must declare the table variable SQL server 2008 - sql

I am writing to make it easier for other techs to fix a database issue.
The goal of this query is so the techs only have to copy paste and provided 3 values but I'm running into a error
Must declare the table variable "#fromArchives".
DECLARE #maxIdentityValue INT
DECLARE #selectId varchar(60)
DECLARE #fromArchives varchar(60)
DECLARE #tableDBCC varchar(60)
SET #selectId = someColumn --This is a column in the #fromArchives
SET #fromArchives = OrderArchives --This is a table
SET #tableDBCC = Orders --This is the table to fix
SET #maxIdentityValue =
(SELECT MAX(#selectId)
FROM #fromArchives) + 1
DBCC CHECKIDENT
(#tableDBCC, RESEED, #maxIdentityValue)
GO
any ideas?

All tablename should be static in sql query.
If you want to use dynamic table or column names, you should generate the full SQL dynamically, and use sp_executesql or EXEC(sql) to execute it.
DECLARE #fromArchives varchar(60)
SET #fromArchives = OrderArchives --This is a table
EXEC('SELECT * FROM ' + #fromArchives)
Refer This Dynamic SQL Article

Related

How to set 1 database name containing a specific table to variable?

So, a little backstory on this one:
I have a lengthy query that I use frequently for my jobs that utilizes the sp_MSForEachDB stored proc. The query creates a temporary table, and then goes through and searches sys.tables, and if a database has a table called T_Study, it will run the query and pull these results into the temporary table.
What I am now trying to do is join in another table from another database, and this database is of a different type. These database are all distinguished by the existence T_BatchStores. All databases that have a T_BatchStores table will also have a table dbo.T_TSyntax, and this is the table on which I will need to join.
Essentially, I am trying to build a universal query that I can run on any server containing this software, and I have these few universal tables, but the names of the databases themselves will vary.
So what I want to do is, in my query that populates my temporary table, add the following:
JOIN '+#MEDDB+'.dbo.T_TSyntax and then my ON clause, etc. Keep in mind that this join occurs within my begin and end clauses and that sp_MSforEachDb will be run on this.
I want #MEDDB to be just a randomly selected name of ANY database on their SQL instance that contains a T_BatchStores table - it does not matter what the name is - I just don't want to modify the query every time I run it.
How can I use my DECLARE #MEDDB and SET/SELECT #MEDDB to work with these requirements?
Also, in some reading, I read that I should use SYSNAME as the data type, but I also know NVARCHAR would work - but I'd just like a tip on which would be ideal.
I have tried the following:
DECLARE #MEDDB SYSNAME
SET #MEDDB = (SELECT TOP 1 name FROM sys.databases WHERE EXISTS (SELECT name FROM sys.tables WHERE name = '''T_BATCHSTORES'''))
SELECT #MEDDB
But this returns 1 row with a NULL value. I'm very much a beginner to SQL, so any assistance would be greatly appreciated!
Note: I am only using Microsoft SQL Server 2008 and 2012 at the present time.
Thanks!
Okay, after heavily modifying the query so that the names aren't actually exactly the same as our actual table structure, here is a slimmed-down version of the query I'm using so that you'll see what I'm going for:
/* Add or change variables as needed and comment back in WHERE statements in Insert section as needed.
You do not need to delete any variables in this section, even if you do not need them.
Simply comment in or out relevant data in the WHERE clause in Section 4. */
/* Section 1: Declaring variables. */
DECLARE #STUID NVARCHAR (65)
DECLARE #IMUID NVARCHAR (200)
DECLARE #ACCN NVARCHAR (100)
DECLARE #MEDDB NVARCHAR (255)
/* Section 2: Assigning values to variables such as an Image file's UID. */
SET #STUID = 'enterSTUID'
SET #IMUID = 'enterIMUIDhere'
SET #ACCN = 'enterACCNhere'
SET #MEDDB = (SELECT TOP 1 name FROM sys.databases WHERE [name] LIKE '%med%'
AND [name] NOT LIKE '%audit%')
/* Section 3: Creating our temporary table to dump our results. */
IF OBJECT_ID('tempdb.dbo.#tempBatchResultsD6') IS NULL
BEGIN
CREATE TABLE #tempBatchResultsD6
(
Database_Name VARCHAR (200),
THING1 VARCHAR(100) NOT NULL,
THING2 VARCHAR(200) NOT NULL,
THING3 DATETIME NOT NULL,
TSyntaxUID VARCHAR (66) NOT NULL,
TSyntaxDesc VARCHAR (128) NOT NULL
)
END
TRUNCATE TABLE #tempBatchResultsD6
/* Section 4: Query that will be used to populate the contents of the temporary table created above.
Utilizing the stored procedure "sp_MSForEachDb," this will search every database on the SQL instance.
Here, we are limiting our results to only searching specific databases by only returning results from databases that have a "T_Studies" table. */
DECLARE #Command NVARCHAR(MAX)
SET #Command = N'USE [?];
IF EXISTS (SELECT * FROM sys.tables WHERE [name] = ''T_Studies'')
BEGIN
INSERT #tempBatchResultsD6
SELECT
DB_Name () as Database_Name,
THING1,
THING2,
THING3,
TS.TSyntaxUID,
TS.TSyntaxDesc
FROM T_Studies ST WITH (nolock)
JOIN T_Patients PT WITH (nolock) ON ST.ST_PT_FOLDERID = PT.PT_FOLDERID
JOIN T_Series SE WITH (nolock) ON ST.ST_FOLDERID = SE.SE_ST_FOLDERID
JOIN T_Images IM WITH (nolock) ON SE.SE_FOLDERID = IM.IM_SE_FOLDERID
JOIN '+#MEDDB+'.dbo.T_TSyntaxes TS WITH (nolock) on IM.IM_TSyntaxID = TS.TSyntaxUID
WHERE ST.STUID = '''+#STUID+'''
--WHERE IM.IM_UID = '''+#IMUID+'''
--WHERE ST.ST_ACCNNO = '''+#ACCN+'''
END'
EXEC sp_MSForEachDb #Command
/* Section 5: Querying our temporary table to get our results. */
SELECT
Database_Name,
THING1,
THING2,
THING3,
TSyntaxUID,
TSyntaxDesc
FROM #tempBatchResultsD6
ORDER BY Database_Name
So as you can see, this is a massive temp table that will pull from all databases that have a T_Studies table in them. It's huge in its actual form, but this is trimmed down significantly.
The problem comes in section 2, where I am using #MEDDB to choose a random database name if the name contains the word "Med" but not the word "audit." This is problematic because it assumes consistent naming across all sites - and while these names are suggested, they are never a guarantee.
To guarantee consistency, I am trying to populate the #MEDDB variable with the name of ANY database on their system that contains a T_BatchStores table instead of the WHERE [name] like portion.
Any advice with this new info would be greatly appreciated!
I am not sure whether I understand your question completely.
But if you wanna loop through all databases, you can use something like the following code. "SELECT XXX" would then be your query, by using "use ' + #DB_Name + ';" you switch to the desired database to execute the your query.
DECLARE #DB_Name varchar(100)
DECLARE #Command nvarchar(max)
DECLARE database_cursor CURSOR FOR
SELECT name
FROM MASTER.sys.sysdatabases
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
set #Command =
'
use ' + #DB_Name + ';
SELECT XXX
'
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
DECLARE #MEDDB NVARCHAR(500)
SET #MEDDB = 'SELECT TOP 1 name FROM sys.databases WHERE EXISTS (SELECT name FROM sys.tables WHERE name = ''T_BATCHSTORES'')'
EXEC (#MEDDB)
This is Dynamic SQL. Of course, I'm not getting any results, either, but I'm not in your database. Still, this allows you to be 'dynamic', and use a variable to modify things:
DECLARE #MEDDB NVARCHAR(500)
DECLARE #MEDDB2 NVARCHAR(100) = 'T_BATCHSTORES'
SET #MEDDB = 'SELECT TOP 1 name FROM sys.databases WHERE EXISTS (SELECT name FROM sys.tables WHERE name = ''' + #MEDDB2 + ''')'
EXEC (#MEDDB)
My recommendation is that you run simpler queries that show what you want, and then you build them into the dynamic method.
For instance, I'm in AdventureWorks right now, so I can do:
SELECT * FROM sys.databases
This gives me a list of all the databases that are available in here.
So maybe I expand that to
SELECT * FROM sys.databases WHERE name = 'AdventureWorks'
This gives me just one line of results. So if that's what I want, I build it into the dynamic portion:
DECLARE #MEDDB NVARCHAR(500)
DECLARE #MEDDB2 NVARCHAR(100) = 'AdventureWorks'
SET #MEDDB = 'SELECT * FROM sys.databases WHERE name =''' + #MEDDB2 + ''''
EXEC (#MEDDB)
It just all depends what you're looking for. I always find the data I want first, and then figure out how to make my query look for it.

How can I declare a table variable with a decimal variable as the identity seed? [duplicate]

This question already has answers here:
Programmatically set identity seed in a table variable
(3 answers)
Closed 9 years ago.
I'm using this, but I can't figure out why this doesn't work. SSMS won't give me a useful message other than syntax incorrect:
DECLARE #columnSeed DECIMAL
SELECT #columnSeed = MAX([seeded_column]) + 1 FROM [table] (nolock) WHERE [conditions]
DECLARE #Temp_Table TABLE ([seeded_column] varchar(35) IDENTITY(#columnSeed, 1), [more columns])
I want to take the maximum value from a column in one table and create a temporary table variable with an identity column seeded with that previous maximum value.
Edit: OK, after digging around for into about dynamic SQL I think I've got what should work, but it still isn't:
DECLARE #columnSeed DECIMAL
[#columnSeed set properly]
EXECUTE sp_executesql
N'DECLARE #Temp TABLE (seeded_column decimal IDENTITY(#seed, 1) NOT NULL [more columns])',
N'#seed decimal',
#seed = #columnSeed;
All the info I get now is that I've incorrect syntax near '#seed'
You can't use a variable as a seed. It is invalid syntax. The table variable is already implicitly created before the batch is executed and the variable assigned anyway.
The only way of doing this would be to concatenate the desired query and execute it. All usages of the table variable would need to be in the child scope.
DECLARE #columnSeed DECIMAL(18,0) = 10
DECLARE #sql NVARCHAR(MAX) = N'DECLARE #Temp TABLE (seeded_column decimal IDENTITY(' + CAST(#columnSeed AS NVARCHAR(19)) +', 1) NOT NULL)
INSERT INTO #Temp DEFAULT VALUES;
SELECT * FROM #Temp;'
EXECUTE sp_executesql
#sql,
N'#seed decimal',
#seed = #columnSeed;
I'm sure there is a better way of doing whatever it is you are doing anyway though.
You could just declare the table variable in the outer scope with a seed of 0 and add the desired offset to your SELECT queries from it for example.
DECLARE #columnSeed DECIMAL(18,0) = 10
DECLARE #Temp TABLE (seeded_column decimal(18,0) IDENTITY(0, 1) NOT NULL)
INSERT INTO #Temp DEFAULT VALUES;
INSERT INTO #Temp DEFAULT VALUES;
SELECT #columnSeed + seeded_column AS psuedo_seeded_column
FROM #Temp;
Though the whole need for this seems suspect. You shouldn't normally care what the IDENTITY values are. If this is to prepare data that later is inserted into the table you are calculating #columnSeed from maybe just inserting it and using the OUTPUT clause to get the ID values inserted might be more appropriate and less at risk of concurrency issues.
I think you can't use parameters in DDL. In other words, you won't be able to use #seed in the IDENTITY clause. Convert the seed to a string and shove it into your DDL manually. Something like this should work. (I don't have a SQL Server instance handy, so my apologies if there are any additional errors. The point is: Don't use parameters in DDL statements.)
DECLARE #columnSeed DECIMAL
DECLARE #sql NVARCHAR(1024)
[#columnSeed set properly]
SET #sql = N'DECLARE #Temp TABLE (seeded_column decimal IDENTITY(' || CONVERT(NVARCHAR, #seed) || N', 1) NOT NULL [more columns])';
EXECUTE sp_executesql #sql

How can I spot in what database is a stored procedure with name 'myStoredProcedure'?

There are bunch of databases to the SQL server I am connected.
How should I query the sysobjects in order to spot in what database a stored procedure with name 'myStoredProcedure' is located ?
The query should return the database name.
Thanks
I know you are not asking for this, but I'd really download RedGate's Sql Search add-in for SSMS and use that. It allows you to find any object (proc, table, view, column, etc) on any database easily.
And it's free!
I'd give this a try:
CREATE TABLE ##DatabaseList
(
DatabaseName varchar(50)
)
EXECUTE SP_MSForEachDB 'USE [?]; INSERT INTO ##DatabaseList SELECT DB_NAME() FROM [sys].[objects] WHERE name = "MyStoredProcedure" AND type_desc = "SQL_STORED_PROCEDURE"'
SELECT * FROM ##DatabaseList
DROP TABLE ##DatabaseList
That's using the undocumented/ unsupported system stored procedure SP_MSForEachDb and writing any hits to a global temp table, then outputting the contents to the Results window before dropping the table. If you just need to know which database (or databases - there may of course be more than one) has an appropriately named SP, this should do it. If you want to use the output elsewhere as a parameter, it may take a little more work.
By the way, I'm only learning this stuff myself over the last few months so if anyone can critique the above and suggest a better way to go at it I'm happy to receive feedback. Equally, I can answer any further questions posted here to the best of my ability.
Cheers
So out of curiosity I decided to try write this myself, especially since ADG mentioned his solution was using an unsupported, undocumented procedure. This could also be expanded to take a 2nd parameter so where it checks the type = P (stored Proc) you could probably change it to look for other things like views / tables etc.
My solution is a bit long but here goes:
CREATE PROCEDURE spFindProceduresInDatabases
(
#ProcedureName NVARCHAR(99)
)
AS
BEGIN
-- Get all the database names and put them into a table
DECLARE #Db TABLE (DatabaseName Varchar(99))
INSERT INTO #Db SELECT name FROM Sys.databases
-- Declare a table to hold our results
DECLARE #results TABLE (DatabaseName VARCHAR(99))
-- Make a Loop
-- Declare a variable to be incremented
DECLARE #count INT
SET #count = 0
-- Declare the end condition
DECLARE #endCount INT
SELECT #endCount = COUNT(*) FROM #Db
-- Loop through the databases
WHILE (#count < #endCount )
BEGIN
-- Get the database we are going to look into
DECLARE #dbWeAreChecking VARCHAR(99)
SELECT TOP 1 #dbWeAreChecking = DatabaseName FROM #Db
DELETE FROM #Db WHERE DatabaseName = #dbWeAreChecking
-- Create and execute our query
DECLARE #Query NVARCHAR(3000)
SET #Query = N'SELECT #outParam = COUNT(*) FROM '+#dbWeAreChecking+'.sys.sysobjects WHERE type = ''P'' and name = #ProcedureName'
Declare #outParam INT
print (#Query)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #IntVariable INT
SET #ParmDefinition = N'#ProcedureName VARCHAR(99),#outParam INT OUTPUT'
SET #IntVariable = 35
EXECUTE sp_executesql
#Query ,
#ParmDefinition,
#ProcedureName,
#outParam = #outParam OUTPUT
-- If we have a result insert it into the results table
If (#outParam > 0)
BEGIN
INSERT INTO #results(DatabaseName) VALUES(#dbWeAreChecking)
END
-- Increment the counter
SET #count = (#count + 1)
END
-- SELECT ALL OF THE THINGS!!!
SELECT * FROM #results
END

T-SQL to modify a field in any database where it exists

So I have about 150 SQL Server 2005 databases all mostly copies of each other. Each one has a table called bvc_User that has a field called PasswordChanged. For now, PasswordChanged is a nullable bit field.
I want to change all instances of it to a non-nullable bit field with a default value of 0 and set any NULL values currently in the table data to 1 (yes, I don't want them set to the default of 0).
I can probably do the update of the NULL setting and the corresponding update of the already existing database values separately, but my primary question is, how can I loop through all the databases on a server, look for the bvc_User table (not all DB's on the server have it) and if it exists, alter the PasswordChanged field?
You can use sp_msforeachdb to run a command on all database. Notice that I check for the existence of the table prior to actually using it.
sp_msforeachdb '
If Exists(Select 1
From [?].Information_Schema.Tables
Where Table_Name = ''bvc_User'')
Update [?].dbo.bvc_User
Set PasswordChanged = 1
Where PasswordChanged Is NULL'
Three pieces: get the db names, loop through them, execute dynamic sql:
DECLARE #dbNames TABLE (Id int IDENTITY, name nvarchar(50))
INSERT INTO #dbNames
SELECT name FROM sysdatabases
DECLARE #statement nvarchar(540)
DECLARE #dbName nvarchar(50)
DECLARE #maxId int
SELECT #maxId = MAX(Id) FROM #dbNames
DECLARE #i int
SET #i = 1
WHILE #i < #maxId
BEGIN
SEt #dbName = 'dbName'
SET #statement = 'USE ' + #dbName + CHAR(13) + '--execute table specific alter table logic here'
EXEC sp_ExecuteSql #statement
SET #i = #i + 1
END
HTH.

Execute query stored in variable in a very specific way

Greetings, I have a problem as follows:
I have an SQL variable declared:
DECLARE #myVariable nvarchar(max)
a third party library set a value for this variable. To simplify, lets say that the value is as follows:
SET #myVariable = 'Select ROWGUID from MySampleTable'
Now, I want to execute the following query:
SELECT ROWGUID FROM myTable WHERE ROWGUID in (exec sp_executesql #myVariable )
However, the above statement does not work because it returns an error telling me that I can't execute stored procedure in that way. I made a workaround and this is what I wrote:
create table #temptable (ID uniqueidentifier null)
if(#myVariable is not null AND #myVariable !='') insert into #temptable exec sp_executesql #myVariable
SELECT ROWGUID FROM myTable WHERE ROWGUID in (select * from #temptable)
DROP TABLE #temptable
This works fine.However I don't think it is a good idea to use temporary table. How can I achieve the same result without necessity of creating temporary tables?
I am using SQL SERVER 2005
UPDATE
Please read what I've written where is the problem:
However, the above statement does not work because it returns an error telling me that I can't execute stored procedure in that way. I made a workaround and this is what I wrote:
Keep it simple
-- Your original declaration
declare #myVariable nvarchar(max)
set #myVariable = 'Select ROWGUID from MySampleTable'
-- Additional code
declare #myQuery nvarchar(max) = 'SELECT ROWGUID FROM myTable WHERE ROWGUID in (' + #myVariable + ')'
exec (#myQuery)
Maybe you could use User Defined Functions instead of stored procedures?
If you are using SQL Server 2005 or 2008, you could use a Common Table Expression instead of creating a temporary table.
Common Table Expressions
Your CTE should look like:
WITH Records (ROWGUID) AS (
SELECT ROWGUID
FROM MySimpleTable
)
Then you can simply use:
SELECT ROWGUID
FROM myTable
WHERE ROWGUID IN (SELECT ROWGUID
FROM Records);
Which potentially means you can drop your Variable.
EDIT
Ok, so CTE is out of the question. But, what about using a Table variable instead of creating a Temporary Table.
DECLARE #myVar nvarchar(max);
DECLARE #table TABLE
(
ROWGUID uniqueidentifier
)
SET #myVar = 'SELECT ROWGUID FROM MySampleTable';
INSERT INTO #table
EXEC sp_executesql #myVar;
SELECT ClientID
FROM myTable
WHERE EXISTS (SELECT ClientID FROM #table);