Trying to find a way to use a declared variable's result from one database to be used in a different database:
For example:
USE DB1
GO
DECLARE #d DATETIME
SELECT TOP 1 #d = Date
FROM DateDB
USE DB2
GO
PRINT #d
Error:
Must declare the scalar variable "#d"
Not sure if it is possible, so figured Id ask S.O. after Googling (Perhaps incorrectly) for the last 45 minutes.
Local variables only exist for the lifetime of a single batch.
In SSMS, the GO keyword (assuming it hasn't been altered in the settings) separates batches.
The statements following GO are a new separate batch; to persist data you will need to store it - you can create a table in TempDB for such a purpose.
The go keyword is treated as a batch separator by SQL Server Management Studio and sqlcmd. It indicates the start of a new batch, and each new batch has its own variables.
However, there is a convenient storage for variables between databases in a single session: session storage. These context variables persist for the life of the session and can be referenced in multiple batches.
Use the sp_set_session_context system procedure to set a session context variable. Use the SESSION_CONTEXT() function to retrieve the session context variables.
For example:
USE DB1
GO
DECLARE #d DATETIME
SELECT #d = '1/1/2022'
PRINT #d
EXEC sp_set_session_context #key = N'MyDate', #value = #d
USE DB2
GO
DECLARE #d DATETIME
SELECT #d = CAST(SESSION_CONTEXT(N'MyDate') AS DATETIME)
PRINT #d
Output:
Jan 1 2022 12:00AM
Jan 1 2022 12:00AM
If you need to remember a variable across multiple sessions, then you must save the variable to a persistent storage like a tempdb table or global temporary ##Table.
For example, an initialization batch could save a date value in a tempdb table called tempdb..MyVariables column MyDate. Later sessions processing this information could refer to the value in this table column. A final cleanup session could remove the table completely.
You Should specify the whole name with schema
for example
SELECT * FROM DB1.dbo.MyTable
Related
I'm trying to use SQL Notebooks similar to how I'm used to using Jupyter Notebooks for documenting some standard queries I use. However when I declare a table variable in one cell, the value isn't accessible in a new cell. I do this so I can annotate each cell to explain why I am doing these operations. Is this a limitation of SQL Notebooks? Or is there a declaration I am missing?
There's a workaround using SQL itself and Session Context to declare variables between your blocks.
See here:
https://www.ericgharrison.com/?p=418
With a Session Context setting, we can store the values using sp_set_session_context…
EXEC sp_set_session_context 'StartDate', '11/01/2020'
EXEC sp_set_session_context 'EndDate', '11/01/2020 23:59:59.99'
…and then retrieve and use them in another code block:
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SELECT #StartDate = CAST(SESSION_CONTEXT(N'StartDate') AS DATETIME)
SELECT #EndDate = CAST(SESSION_CONTEXT(N'EndDate') AS DATETIME)
I have a query that I want to use every month, but the table it will point to will change slightly. I want to use a function analogous to find/replace to just update a portion of the table names referenced. Each table will just change its name by the Month_Year for the file. I have tried a local variable with declare/set and it does not work. This is what I would like to do...
declare #file_name varchar(max)
SET #file_name = 'oct_16' --set as month_year used in table name
alter table sp_panel_#file_name
add LFDOB varchar(max)
You need dynamic query
exec ('alter table sp_panel_+'#file_name+' add LFDOB varchar(max)')
I just realized there is an actual "find/replace" function within SQL. It will do the trick until we can fully automate
I have an existing SP.
I want to start using database snapshots in some cases.
Users can save a snapshot at any time.
If they do, the SP should use it.
Otherwise, use the primary database.
I want to adapt the SPs to handle this, by making the database/table names dynamic instead of hard-coded in the SP.
I can imagine something like this working, with fully qualified table names, but it gives the error 'Must declare the table variable "#db1"':
declare #table1 varchar(25);
set #table1 = Snapshot.schema.tablename;
select * from #table1;
This gives "Incorrect syntax near '#db'."
declare #db varchar(25);
set #db = "Snapshot";
use #db;
This sorta works, but the "use" is only in effect during the execute. By the time the 'select' is executed, you are back to using the original database.
declare #db varchar(25);
set #db = 'use Snapshot';
EXECUTE(#db);
select * from Schema.Tablename;
I know I could generate the entire SP on the fly, but that seems guaranteed to get rejected by the DBAs. I'd rather a less radical solution.
Any better ideas?
I recently encountered an issue while porting an app to SQL Server. It turned out that this issue was caused by a stored procedure parameter being declared too short for the data being passed to it: the parameter was declared as VARCHAR(100) but in one case was being passed more than 100 characters of data. What surprised me was that SQL Server didn't report any errors or warnings -- it just silently truncated the data to 100 characters.
The following SQLCMD session demonstrates this:
1> create procedure WhereHasMyDataGone (#data varchar(5)) as
2> begin
3> print 'Your data is ''' + #data + '''.';
4> end;
5> go
1> exec WhereHasMyDataGone '123456789';
2> go
Your data is '12345'.
Local variables also exhibit the same behaviour:
1> declare #s varchar(5) = '123456789';
2> print #s;
3> go
12345
Is there an option I can enable to have SQL Server report errors (or at least warnings) in such situations? Or should I just declare all local variables and stored procedure parameters as VARCHAR(MAX) or NVARCHAR(MAX)?
SQL Server has no such option. You will either have to manually check the length of strings in your stored procedure and somehow handle the longer strings or use the nvarchar(max) option. If disk space isn't an issue then the nvarchar(max) option is certainly the easiest and quickest solution.
You don't have to use nvarchar(max) just use nvarchar(length+1) [e.g. if your column length is 50 then you would set the parameter to be nvarchar(51)]. See the answer from DavidHyogo - SQL Server silently truncates varchar's in stored procedures.
I don't know of a way to make the server do it, but I've been using the SQL Server Projects feature of Visual Studio Team System Developer Edition. It includes code analysis which caught a truncation problem of mine: using an int parameter to insert into a smallint column.
Though awkward, you can, however, dynamically check for parameter length before a call, e.g.
CREATE FUNCTION MyFunction(#MyParameter varchar(10))
RETURNS int
AS
BEGIN
RETURN LEN(#MyParameter)
END
GO
DECLARE #MyValue varchar(15) = '123456789012345'
DECLARE #ParameterMaxLength int
SELECT #ParameterMaxLength = CHARACTER_MAXIMUM_LENGTH
FROM INFORMATION_SCHEMA.PARAMETERS
WHERE SPECIFIC_SCHEMA = 'dbo' AND
SPECIFIC_name = 'MyFunction' AND
PARAMETER_NAME = '#MyParameter'
IF #ParameterMaxLength <> -1 AND
LEN(#MyValue) > #ParameterMaxLength
PRINT 'It''s too looooooooooooooooooong'
I omitted the called function's database name in the query and in the reference to INFORMATION_SCHEMA.PARAMETERS to ensure that my sample would run without edits.
I don't necessarily advocate this, but I wanted to point out that the information may be available to detect imminent truncation dynamically, if in some critical situation this is needed.
You can use LEFT in SQL and specified the length that you want to insert.
for example.
CREATE TABLE Table1
(
test varchar(10)
)
insert into Table1 values (LEFT('abcdefghijklmnopqrstuvwxyz',10))
This will insert only
abcdefghij on table
How do I set the database name dynamically in a SQL Server stored procedure?
Sometimes, the use of SYNONYMs is a good strategy:
CREATE SYNONYM [schema.]name FOR [[[linkedserver.]database.]schema.]name
Then, refer to the object by its synonym in your stored procedure.
Altering where the synonym points IS a matter of dynamic SQL, but then your main stored procedures can be totally dynamic SQL-free. Create a table to manage all the objects you need to reference, and a stored procedure that switches all the desired synonyms to the right context.
This functionality is only available in SQL Server 2005 and up.
This method will NOT be suitable for frequent switching or for situations where different connections need to use different databases. I use it for a database that occasionally moves around between servers (it can run in the prod database or on the replication database and they have different names). After restoring the database to its new home, I run my switcheroo SP on it and everything is working in about 8 seconds.
Stored Procedures are database specific. If you want to access data from another database dynamically, you are going to have to create dynamic SQL and execute it.
Declare #strSQL VarChar (MAX)
Declare #DatabaseNameParameter VarChar (100) = 'MyOtherDB'
SET #strSQL = 'SELECT * FROM ' + #DatabaseNameParameter + '.Schema.TableName'
You can use if clauses to set the #DatabaseNameParameter to the DB of your liking.
Execute the statement to get your results.
This is not dynamic SQL and works for stored procs
Declare #ThreePartName varchar (1000)
Declare #DatabaseNameParameter varchar (100)
SET #DatabaseNameParameter = 'MyOtherDB'
SET #ThreePartName = #DatabaseNameParameter + '.Schema.MyOtherSP'
EXEC #ThreePartName #p1, #p2... --Look! No brackets