I've tried every avenue on every damn forum suggested, but to no avail!
Need to send results of SQLPERF(logspace), that have been stored in a table, via sp_send_dbmail to recipient.
Step 2 of job is where failure occurs. Please help!
EXEC msdb.dbo.sp_send_dbmail
#profile_name= 'MyDBA',
#recipients= 'Mack#mydba.co.za',
#subject='Log Warning',
#query='SELECT * from #TempForLogSpace WHERE LogSpaceUsed >80
You can't query from a temp table using database mail. The session that you used to create the temp table (step 1 of your job I assume) has been closed and a new session started when step 2 started. Because the session has been closed the table has been dropped (even if the table hasn't been dropped because it's a new session you don't have access to the other sessions temp table).
Either create a physical table and use that (either in the tempdb database or your database) or put the code which creates the output in the #query with the select * from #TempForLogSpace at the end (a stored procedure will be much easier to deal with in this case).
I know this thread is a bit old, but in case someone stumbles on this, the problem is like mrdenny said that sp_send_dbmail stored procedure runs in it's own session, however you can get around this by using a global temporary table instead (prefix the table with two pound signs (##)).
Just use a global temp table like ##temp_table. This table will be accessible by all sessions and will remain in database until all sessions that referred it have been closed.
Local and global temporary tables in SQL Server
Related
When using a # temporary table in a stored procedure activated by a service broker queue, if ~ simultaneous messages activate the stored procedure multiple times, will the "readers" of the queue use the same session, and, de facto, the same temporary tables ?
ref : this post that sounds like each activation will have its own session.. but am I understanding it wrong ?
ref 2 : That msdn doc that left me puzzled
Each reader thread, up to MAX_QUEUE_READERS, will have its own session. This must be true, otherwise they could not execute in parallel. Within a session (thread), the stored procedure may be called repeatedly. So two simultaneous instances of the stored proc cannot collide on accessing #temp table, but the #temp table may be already populated from a previous execution on the same session.
I query my database from within a .NET application (time recoding). I send the Windows user name to the database and query it depending on this information.
I query a lot of different information with stored procedures, such as holiday, overtime etc. and send them back to the .NET application where I show this data in one form.
Let's say I need the information from SP1, 3 and 4 on Form1:
FORM1:
SP1
SP3
SP4
My problem:
I have a quite complicated table that I need for these stored procedures. At the moment I create this table in every of those stored procedures as temporary tables what is obviously quite time consuming.
What I have tried so far is creating a stored procedure that creates a temp table but this one is not accessable within my other stored procedures.
My question: I am looking for a way to create this table for Form1 once, so I can just access these table in the other stored procedures.
I'm using SQL Server 2014 Express.
If you create the temporary table outside of any stored procedure, it will be accessible within each. Assuming that the actual table definition isn't too complex (but populating it may be), this may be doable.
So you'd execute (effectively):
CREATE TABLE #T (A int not null, B varchar(17) not null)
EXEC PopulateTempTable
EXEC SP1
EXEC SP3
EXEC SP4
All on a single connection. PopulateTempTable may or may not be required, depending on how complex the population of the table is and whether you want that to be performed by your calling code or the database.
You cannot create the temp table inside of a stored procedure since temp tables are automatically dropped when the scope of a stored procedure is exited.
Alternatively, you may want to simulate "session-global" temp tables, as I suggest in this answer1.
The risk with using a global temp table is that it is truly global - all sessions see and interact with the data in the same table. You have to be very careful in such circumstances if it's at all possible that two sessions will attempt to use it at the same time; You generally need some means to filter the data in the table so that each session only works with its own data.
1Probably enhanced these days by also adding a Logon Trigger to clear down the old contents of the table whenever a new connection is established.
You have to create global temp table
CREATE TABLE ##TEMP1
(
Name varchar(50)
)
In MS SQL Server, I'm using a global temp table to store session related information passed by the client and then I use that information inside triggers.
Since the same global temp table can be used in different sessions and it may or may not exist when I want to write into it (depending on whether all the previous sessions which used it before are closed), I'm doing a check for the global temp table existence based on which I create before I write into it.
IF OBJECT_ID('tempdb..##VTT_CONTEXT_INFO_USER_TASK') IS NULL
CREATE TABLE ##VTT_CONTEXT_INFO_USER_TASK (
session_id smallint,
login_time datetime,
HstryUserName VDT_USERNAME,
HstryTaskName VDT_TASKNAME,
)
MERGE ##VTT_CONTEXT_INFO_USER_TASK As target
USING (SELECT ##SPID, #HstryUserName, #HstryTaskName) as source (session_id, HstryUserName, HstryTaskName)
ON (target.session_id = source.session_id)
WHEN MATCHED THEN
UPDATE SET HstryUserName = source.HstryUserName, HstryTaskName = source.HstryTaskName
WHEN NOT MATCHED THEN
INSERT VALUES (##SPID, #LoginTime, source.HstryUserName, source.HstryTaskName);
The problem is that between my check for the table existence and the MERGE statement, SQL Server may drop the temp table if all the sessions which were using it before happen to close in that exact instance (this actually happened in my tests).
Is there a best practice on how to avoid this kind of concurrency issues, that a table is not dropped between the check for its existence and its subsequent use?
The notion of "global temporary table" and "trigger" just do not click. Tables are permanent data stores, as are their attributes -- including triggers. Temporary tables are dropped when the server is re-started. Why would anyone design a system where a permanent block of code (trigger) depends on a temporary shared storage mechanism? It seems like a recipe for failure.
Instead of a global temporary table, use a real table. If you like, put a helpful prefix such as temp_ in front of the name. If the table is being shared by databases, then put it in a database where all code has access.
Create the table once and leave it there (deleting the rows is fine) so the trigger code can access it.
I'll start by saying that, on the long term, I will follow Gordon's advice, i.e. I will take the necessary steps to introduce a normal table in the database to store client application information which needs to be accessible in the triggers.
But since this was not really possible now because of time constrains (it takes weeks to get the necessary formal approvals for a new normal table), I came up with a solution for preventing SQL Server from dropping the global temp table between the check for its existence and the MERGE statement.
There is some information out there about when a global temp table is dropped by SQL Server; my personal tests showed that SQL Server drops a global temp table the moment the session which created it is closed and any other transactions started in other sessions which changed data in that table are finished.
My solution was to fake data changes on the global temp table even before I check for its existence. If the table exists at that moment, SQL Server will then know that it needs to keep it until the current transaction finishes, and it cannot be dropped anymore after the check for its existence. The code looks now like this (properly commented, since it is kind of a hack):
-- Faking a delete on the table ensures that SQL Server will keep the table until the end of the transaction
-- Since ##VTT_CONTEXT_INFO_USER_TASK may actually not exist, we need to fake the delete inside TRY .. CATCH
-- FUTURE 2016, Feb 03: A cleaner solution would use a real table instead of a global temp table.
BEGIN TRY
-- Because schema errors are checked during compile, they cannot be caught using TRY, this can be done by wrapping the query in sp_executesql
DECLARE #QueryText NVARCHAR(100) = 'DELETE ##VTT_CONTEXT_INFO_USER_TASK WHERE 0 = 1'
EXEC sp_executesql #QueryText
END TRY
BEGIN CATCH
-- nothing to do here (see comment above)
END CATCH
IF OBJECT_ID('tempdb..##VTT_CONTEXT_INFO_USER_TASK') IS NULL
CREATE TABLE ##VTT_CONTEXT_INFO_USER_TASK (
session_id smallint,
login_time datetime,
HstryUserName VDT_USERNAME,
HstryTaskName VDT_TASKNAME,
)
MERGE ##VTT_CONTEXT_INFO_USER_TASK As target
USING (SELECT ##SPID, #HstryUserName, #HstryTaskName) as source (session_id, HstryUserName, HstryTaskName)
ON (target.session_id = source.session_id)
WHEN MATCHED THEN
UPDATE SET HstryUserName = source.HstryUserName, HstryTaskName = source.HstryTaskName
WHEN NOT MATCHED THEN
INSERT VALUES (##SPID, #LoginTime, source.HstryUserName, source.HstryTaskName);
Although I would call it a "use it at your own risk" solution, it does prevent that the use of the global temp table in other sessions affects its use in the current one, which was the concern that made me start this thread.
Thanks all for your time! (from text formatting edits to replies)
I have a stored procedure that has boolean result parameter as output. But my project needs to use 3 databases. Basically, there is a main database and 2 others. The other databases using same stored procedure but they just depend on params. If I explain the scenario, you will understand. Firstly, Sorry for bad explaining.
This application using main database for session management, user configurations and so on. This is okay. The problem is same user has to use 2 different databases for creating invoices. We can pretend that these users are IT support staff. They works for 2 different companies and supporting their products and they are managing their solutions in different databases.
User
Main Database
A Company Data
B Company Data
Users have to create their invoices for each company's customers. Basically they are using same database but the name of databases are totally different. Maybe my problem has easier solution so I want to ask that How can I use Dynamic Database Name in my Stored Procedure? and my current question is I'm initialising Stored Procedure as String and after that I execute the stored procedure as String.
Procedure has no error, also says me completed successfully but there is no insert (in stored procedure). When I use the sql command (which I set manually as String) in Management Studio, Query is running perfectly.
As a summary,
I have 3 databases, Main database need to execute generating Invoice stored procedure. But database names are must be dynamic because of different companies.
When I send the database name A_COMPANY_DB, stored procedure should execute in A_COMPANY_DB. When I send B_COMPANY_DB, stored procedure should execute B_COMPANY_DB.
Both of A_COMPANY and B_COMPANY databases are same. I have to manage sql query as String because of Dynamic Database Name. So I can't reach the output parameter.
My stored procedure has only one output parameter which is bit type. But I can't use it like:
Set #dynsql = 'USE ' + QUOTENAME(#DbName) + ' exec.[dbo].[spName] ' + other params
EXECUTE sp_executesql #dynsql
In this situation I couldn't reach Output parameter. How can I set or use my Output parameter in this stored procedure?
EXECUTE sp_executesql #dynsql #outputparam OUT
Is it possible or any solution?
Sorry for bad explaining.
I have sometimes a problem when running a script. I have the probelm when using an application (that I didn't write and therefore cannot debug) that launches the scripts. This app isn't returning the full error from SQL Server, but just the error description, so I don't know exactly where th error comes.
I have the error only using this tool (it is a tool that sends the queries directly to SQL Server, using a DAC component), if I run the query manuallyin management studio I don't have the error. (This error moreover occurs only on a particular database).
My query is something like:
SELECT * INTO #TEMP_TABLE
FROM ANOTHER_TABLE
GO
--some other commands here
GO
INSERT INTO SOME_OTHER_TABLE(FIELD1,FIELD2)
SELECT FIELDA, FIELDB
FROM #TEMP_TABLE
GO
DROP TABLE #TEMP_TABLE
GO
The error I get is #TEMP_TABLE is not a valid object
So somehow i suspect that the DROP statement is executed before the INSERT statement.
But AFAIK when a GO is there the next statement is not executed until the previous has been completed.
Now I suspoect that this is not true with temp tables... Or do you have another ideas?
Your problem is most likely caused by either an end of session prior to the DROP TABLE causing SQL Server to automatically drop the table or the DROP TABLE is being executed in a different session than the other code (that created and used the temporary table) causing the table not to be visible.
I am assuming that stored procedures are not involved here, because it looks like you are just executing batches, since local temporary tables are also dropped when a stored proc is exited.
There is a good description of local temporary table behavior in this article on Temporary Tables in SQL Server:
You get housekeeping with Local Temporary tables; they are
automatically dropped when they go out of scope, unless explicitly
dropped by using DROP TABLE. Their scope is more generous than a table
Variable so you don't have problems referencing them within batches or
in dynamic SQL. Local temporary tables are dropped automatically at
the end of the current session or procedure. Dropping it at the end of
the procedure that created it can cause head-scratching: a local
temporary table that is created within a stored procedure or session
is dropped when it is finished so it cannot be referenced by the
process that called the stored procedure that created the table. It
can, however, be referenced by any nested stored procedures executed
by the stored procedure that created the table. If the nested
procedure references a temporary table and two temporary tables with
the same name exist at that time, which table is the query is resolved
against?
I would start up SQL Profiler and verify if your tool uses one connection to execute all batches, or if it disconnects/reconnects. Also it could be using a connection pool.
Anyway, executing SQL batches from a file is so simple that you might develop your own tool very quickly and be better off.