Creating a view in tempdb in SQL Server through a post request - sql

Since I need to send the query statement through a http post request there are certain limitations.
1. It should be a one liner
2. it should be created in tempdb since i am going to drop it afterwards.
since SQL server takes CREATE VIEW statement only in new line I am feeding new line characters to the statement. here is the statement:
DECLARE #NewLineChar AS CHAR(2) = CHAR(13) + CHAR(10); ('USE tempdb;' +#NewLineChar + 'GO' +#NewLineChar +'CREATE VIEW temp_view AS select name from sys.databases')
This query gives me following error:
Msg 102, Level 15, State 1.
Incorrect syntax near 'USE tempdb;'. (Line 1)
what could be the problem ?
Thanks
edit: The same query works like this
USE tempdb;
GO
CREATE VIEW temp_view AS select name from sys.databases
where is the syntax error?

Since SQL server takes CREATE VIEW statement only in new line I am feeding new line characters to the statement.
I have never heard of such a requirement. What the documentation does state is: The CREATE VIEW must be the first statement in a query batch.
The statement you have in your question doesn't make sense. You can't just drop a VARCHAR in SSMS and expect SQL Server to just execute it.
What you probably want is something like the following:
USE tempdb;
DECLARE #stmt NVARCHAR(MAX)=N'CREATE VIEW temp_view AS SELECT name FROM sys.databases;';
EXECUTE sp_executesql #stmt;
Or in one line:
USE tempdb;DECLARE #stmt NVARCHAR(MAX)=N'CREATE VIEW temp_view AS SELECT name FROM sys.databases;';EXECUTE sp_executesql #stmt;

This is a bit long for a comment.
You can create a view in the current database with a name like _temp_<something>. You can even include session information if you want to emulate temporary tables.
Or, create a temporary table with no rows:
select top 0 *
into #temp
from <whatever>;
You can access the structure of this table.
If you are using a very recent version of SQL Server, use sp_describe_first_result_set (see here).

Related

SQL Updating column after adding it giving "Invalid column name" error

I have the following SQL in SQL Server 2005 but I get an error stating "Invalid column name 'ExpIsLocalTime' (ln 7) when I run it:
IF NOT EXISTS(SELECT * FROM sys.columns WHERE Name = N'ExpIsLocalTime' AND Object_ID = Object_ID(N'[dbo].[tbl_SessionsAvailable]'))
BEGIN
ALTER TABLE dbo.tbl_SessionsAvailable ADD
ExpIsLocalTime bit NOT NULL CONSTRAINT DF_tbl_SessionsAvailable_ExpIsLocalTime DEFAULT (0)
UPDATE dbo.tbl_SessionsAvailable
SET ExpIsLocalTime = 1
END
GO
This will be in a script file that may be run more than once so I'm trying to make sure the UPDATE only runs once. Is there something about BEGIN/END that delays the execution of the DDL statement?
Your SQL query to do the UPDATE refers to a column that has not yet been created. At compile time, SQL Server detects that the column does not exist, so it gives you the error "Invalid column name 'ExpIsLocalTime'".
In order to include the UPDATE in this query, you will need to encapsulate it in a dynamic SQL query. In other words, something like this:
IF NOT EXISTS(SELECT * FROM sys.columns WHERE Name = N'ExpIsLocalTime' AND Object_ID = Object_ID(N'[dbo].[tbl_SessionsAvailable]'))
BEGIN
ALTER TABLE dbo.tbl_SessionsAvailable ADD
ExpIsLocalTime bit NOT NULL CONSTRAINT DF_tbl_SessionsAvailable_ExpIsLocalTime DEFAULT (0)
DECLARE #SQL NVARCHAR(1000)
SELECT #SQL = N'UPDATE dbo.tbl_SessionsAvailable SET ExpIsLocalTime = 1'
EXEC sp_executesql #SQL
END
GO
We have the same issue in our SQL scripts that maintain tables. After a table is created, if we add a column to it later, we have to use dynamic SQL to avoid these compilation errors.
Another possibly simpler solution is using the GO statement after the Alter statement. This would send the DDL to the server. Then run the rest of your SQL. This should work if you are using sqlcmd osql or SSMS.

How to get results from "exec sp_showpendingchanges" into a table

EDIT: The things I've tried below came directly from the alleged duplicate. The solutions actually do work fine with a user defined sp (and probably most system sp's), but for whatever reason it doesn't work with this one.
I can run exec sp_showpendingchanges on the distribution publication database without any issues. However I want to capture the results in a table
I've tried:
SELECT * INTO #tmpTable
FROM OPENROWSET('SQLNCLI', 'Server=SERVER; Trusted_Connection=yes;',
'EXEC sp_showpendingchanges')
and:
SELECT * INTO #tmpTable
FROM OPENQUERY(SERVER, 'exec sp_showpendingchanges')
Both of these statements return an error that says: Invalid object name 'sysmergepublications'.
I tried to specify the initial catalog in the connection string and even tried adding a USE statement in the last parameter of each statement (i.e. I used an embedded EXEC statement with double-single quotes and all that). But I still end up with the same error.
So how can I get the results from exec sp_showpendingchanges into a temporary table, and preferably without having to define the table myself? If all else fails I will make a program in C#, but really hoping there's a simpler way to just do this with just SQL.
Here is a working example
You create a table
DECLARE #result_table TABLE
(
destination_server SYSNAME ,
pub_name SYSNAME ,
destination_db_name SYSNAME ,
is_dest_subscriber BIT ,
article_name SYSNAME ,
pending_deletes INT ,
pending_ins_and_upd INT
)
execute the script
INSERT INTO #result_table
EXEC sp_showpendingchanges
view the results
SELECT * FROM #result_table
I read your question but definetly cannot understand what the problem to create temp table. Anyway, if you can execute SP but get an error when you do it through linkedserver or openrowset - than problem is in permissions.
Check permissions on sysmergepublications table. If user, which you use for linked server or openrowset, has no grant on do select this table you need to add this permission to user.
I hope it will help you.

Error in SQL stored procedure

I am getting the following error when I execute my stored procedure:
Msg 102, Level 15, State 1, Line 6Incorrect syntax near '2011'.(1 row(s) affected)
Here is the stored procedure:
ALTER PROCEDURE [dbo].[DeliveryFileNames]
AS
BEGIN
SET NOCOUNT ON;
declare #SQL nvarchar(4000)
Create Table #DelivTemp(
Style nvarchar(50),
Material nvarchar(50),
Filename nvarchar(100),
delivered_date date)
set #SQL=
N'insert into #DelivTemp
Select distinct Style,Material,filename
from OPENQUERY(GCS_PRODUCTION,
''SELECT LEFT(FILENAME,locate(''''_'''',FILENAME)-1)as Style,
substring_index(filename,''''_'''',2)as Material,filename,
delivered_date FROM view_delivery_log
where delivered_date > ''2011%'' order by Style '')'
exec (#SQL)
drop table dbo.DelivFN
Select * into dbo.DelivFN
from #DelivTemp
END
I am using OpenQuery to update a SQL table from a linked server on SQL Server 2008 R2.
I know that the underscore is a real issue, but I have tried a plethora of options including \, % and both single and double quotes.
Regardless I am getting the same result. I can run the query independently of the stored procedure and achieve the correct results. The filename field referenced several times is formatted 00000000_ABC4_A.png. I am using the underscore to identify the components of the file name that I need for my reporting purposes.
In addition to the the logical error of your date comparison using the % that the others have pointed out, your current issue is a syntactical error.
Since you've got a dynamic sql statement contained within another dynamic sql statement... you'll need to double-escape all of your single quotes... which you did in most of the query, except for the following line:
where delivered_date > ''2011%'' order by Style '')'
Properly escaped, would be:
where delivered_date > ''''2011%'''' order by Style '')'
Which raises the question... why are you building up the string to execute dynamically, instead of just calling the statement directly?
It's the syntax of ''2011%''. This is not a valid date. % being a wildcard means the compiler can't know what to compare against in the WHERE clause. You'd need to use an actual date: i.e. ''2011_01_01'' so the compiler can know what to compare against
I believe the stored proc exec runs under a different session, therefore you won't have access to the temp table anyway. So, it won't matter if you get that sql statement to run. You could always use YEAR(delivered_date) > 2011.
Another approach would be to use the fqn for the linked server to select into and bypass the temp table all together:
SELECT LEFT(FILENAME,locate('_',FILENAME)-1)as Style,
substring_index(filename,'_',2)as Material,filename,delivered_date
FROM [linked_server_name].[db_name].[dbo].view_delivery_log
into dbo.DelivFN

Why can't use INSERT EXEC statement within a stored procedure called by another stored procedure?

First I try to explain the circumstances.
I store the the filter expression in one column separated by line breaks. The base idea was this:
SELECT
'SELECT ''' + REPLACE(topic_filter,CHAR(10),''' UNION ALL SELECT ''') + ''''
FROM dbo.topic_filter T
WHERE
T.id = #id
FOR XML PATH('')
After this I simply execute this string to put the datas into a temp table.
My problem starts here.
The snippet is in a stored procedure and used by multiple stored procedures to generate the base source to fill.
Approach 1:
Call this sp from another SP to fill a temp table.
Result 1:
An INSERT EXEC statement cannot be nested.
(If I call simply with exec dbo... style the code is working. I only get the error if I try to call within a stored procedure)
Approach 2:
I put the code above into a table values function.
Result 2:
Invalid use of a side-effecting operator 'INSERT EXEC' within a function.
(The function itself don't compiled)
Thanks,
Péter
In the meantime I managed to solve the problem (with help :) ). The solution is simple:
exec('insert into t2 ' + #str)
Where #str contains a select statement.
I don't know why but this way there is no error. The method I call the stored procedure:
SET #exec = 'exec dbo.trFilterTopic ''' + #id+ ''',null,null,1'
INSERT INTO #filtered
exec (#exec)
I hope I spare some time to other folks with this solution.
Bye,
Péter
It is an SQL Server restriction. You cannot have a nested insert exec (I'm not sure why).
If you go:
insert into t(value)
exec dbo.proc
, and inside dbo.proc you have
insert into t2(value2)
exec(#str)
, then it will not run.
Consider different ways of passing tables around, such as temporary tables or table-valued parameters.
Functions on SQL Server have limitations,
they arenot procedures, you can't use dynamic SQL like 'EXECUTE STRING', 'INSERT EXEC'...

How do I paramaterise a T-SQL stored procedure that drops a table?

I'm after a simple stored procedure to drop tables. Here's my first attempt:
CREATE PROC bsp_susf_DeleteTable (#TableName char)
AS
IF EXISTS (SELECT name FROM sysobjects WHERE name = #TableName)
BEGIN
DROP TABLE #TableName
END
When I parse this in MS Query Analyser I get the following error:
Server: Msg 170, Level 15, State 1, Procedure bsp_susf_DeleteTable, Line 6
Line 6: Incorrect syntax near '#TableName'.
Which kind of makes sense because the normal SQL for a single table would be:
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'tbl_XYZ')
BEGIN
DROP TABLE tbl_XYZ
END
Note the first instance of tbl_XYZ (in the WHERE clause) has single quotes around it, while the second instance in the DROP statement does not. If I use a variable (#TableName) then I don't get to make this distinction.
So can a stored procedure be created to do this? Or do I have to copy the IF EXISTS ... everywhere?
You should be able to use dynamic sql:
declare #sql varchar(max)
if exists (select name from sysobjects where name = #TableName)
BEGIN
set #sql = 'drop table ' + #TableName
exec(#sql)
END
Hope this helps.
Update: Yes, you could make #sql smaller, this was just a quick example. Also note other comments about SQL Injection Attacks
Personally I would be very wary of doing this. If you feel you need it for administrative purposes, please make sure the rights to execute this are extremely limited. Further, I would have the proc copy the table name and the date and the user executing it to a logging table. That way at least you will know who dropped the wrong table. You may want other protections as well. For instance you may want to specify certain tables that cannot be dropped ever using this proc.
Further this will not work on all tables in all cases. You cannot drop a table that has a foreign key associated with it.
Under no circumstances would I allow a user or anyone not the database admin to execute this proc. If you havea a system design where users can drop tables, there is most likely something drastically wrong with your design and it should be rethought.
Also, do not use this proc unless you have a really, really good backup schedule in place and experience restoring from backups.
You'll have to use EXEC to execute that query as a string. In other words, when you pass in the table name, define a varchar and assign the query and tablename, then exec the variable you created.
Edit: HOWEVER, I don't recommend that because someone could pass in sql rather than a TableName and cause all kinds of wonderful problems. See Sql injection for more information.
Your best bet is to create a parameterized query on the client side for this. For example, in C# I would do something like:
// EDIT 2: on second thought, ignore this code; it probably won't work
SqlCommand sc = new SqlCommand();
sc.Connection = someConnection;
sc.CommandType = Command.Text;
sc.CommandText = "drop table #tablename";
sc.Parameters.AddWithValue("#tablename", "the_table_name");
sc.ExecuteNonQuery();