I can't find a full solution to my problem. I have an existing stored procedure that takes dynamic input as a parameter value. I need to execute this procedure (with a dynamic variable) and would like to somehow SELECT * INTO #mytable without having to declare the schema of the temp table.
I've tried using OPENROWSET but it doesn't allow me to specify the variable (only hard-code it):
select * into #table from openrowset('SQLNCLI', 'Server=localhost;Trusted_Connection=yes;', 'exec SERVER..MYSTOREDPROCEDURE #parameter = 123')
The only other way I'm aware of is wrapping it in a string and using EXEC(#sql), but I can't figure out how to "SELECT * INTO #table" from that.
What are my options? Can I create a UDF table function that can return a dynamic table? Doubtful...
I'm guessing here, but you'll need to do the whole thing in dynamic SQL. So, instead, something like:
DECLARE #SQL nvarchar(MAX);
DECLARE #param nvarchar(10) = 123;
SET #SQL = N'SELECT *' + NCHAR(10) +
N'INTO #table' + NCHAR(10) +
N'FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'', ''exec SERVER..MYSTOREDPROCEDURE #parameter = ' + QUOTENAME(#param,N'''') +N''');' + NCHAR(10) +
N'SELECT *' + NCHAR(10) + --Of course, I assume you're doing something more complex that a SELECT *.
N'FROM #table;';
PRINT #SQL;
EXEC sp_executesql #SQL;
I think I figured it out. I really only had to modify the temp variable names to put the temp table into the global scope. This works for me with my actual tables (I renamed them for the purposes of this post).
IF OBJECT_ID ('tempdb..##mytemptable') is not null drop table ##mytemptable
declare #id int = 112
declare #sql nvarchar(max) ='SELECT * INTO ##mytemptable FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'', ''exec SERVER..MyStoredProcedure #ID =' + convert(varchar(10), id) + ''')'
-- invokes and inserts into ##mytemptable
exec sp_executesql #sql
-- now I can query from the global scope
select * from ##mytemptable
Related
I want to create a stored procedure for coping table using dynamic query.
I followed this step for creating stored proceduce, link:-https://stackoverflow.com/questions/8698231/sql-server-stored-procedures-to-copy-tables
but I got an error:
Could not find stored procedure 'Select * into tblDetail from salesDetail'
Here is my code:
ALTER PROCEDURE sp_copyOneTableToAnother
#newtable nvarchar(50),
#oldtable nvarchar(50)
AS
BEGIN
DECLARE #sql nvarchar(1000)
SET #sql = 'SELECT * INTO ' + #newtable +
' FROM ' + #oldtable
EXEC #sql
END
exec sp_copyOneTableToAnother #newtable='tblDetail',#oldtable='salesDetail'
The stored procedure was created from above syntax but while calling sp_copyOneTableToAnother, I get an error. Please help me solve it.
There are several problems here, first, your procedure name starts with sp_, which is reserved by Microsoft for Special / System Procedures. That should go.
Next, your parameter types are wrong; the correct data type for an object is a sysname, a synonym of nvarchar(128) NOT NULL, not varchar.
Next, the injection issue; you blindly inject the values of your parameters into your statement and hope that said values aren't malicious. Validate the value of #oldtable and properly quote both parameters.
Finally, the execution should be done by sp_executesql; not using it promotes further injection issues as you can't parametrise EXEC (#SQL) statements.
You also don't define your schemas, which you really should be. I add them as NULLable parameters here, and get the USER's default schema
This results in something like this:
CREATE OR ALTER PROCEDURE dbo.CopyOneTableToAnother #NewTable sysname,
#OldTable sysname,
#NewSchema sysname = NULL,
#OldSchema sysname = NULL AS
BEGIN
SET NOCOUNT ON;
SELECT #NewSchema = ISNULL(#NewSchema,default_schema_name),
#OldSchema = ISNULL(#OldSchema,default_schema_name)
FROM sys.database_principals
WHERE name = USER_NAME();
DECLARE #SQL nvarchar(MAX);
SELECT #SQL = N'SELECT * INTO ' + QUOTENAME(#NewSchema) + N'.' + QUOTENAME(#NewTable) + N' FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + N';'
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
WHERE s.name = #OldSchema
AND t.[name] = #OldTable;
EXEC sys.sp_executesql #SQL;
END;
db<>fiddle
I have a products table and i need to concat my string and my sql statements. Is there any way?
My purpose is that i want to define column names just one time in a string variable and i will use it alot of times. Otherwise my sql statements has alot of column name and it complex my code.
For example, i use this
DECLARE #MyStr NVARCHAR(MAX) = 'ProdId,ProdName'
SELECT TOP 10 #MyStr FROM Products
Result is here
But i need the result as this.
You'll need to use dynamic SQL here. I also suggest you fix your design and don't store delimited data, and ideally use a table type parameter. This would look like the following:
DECLARE #Columns table (ColumnName sysname);
INSERT INTO #Columns (ColumnName)
VALUES(N'Column1'),(N'Column2');
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SELECT #SQL = N'SELECT ' + STRING_AGG(QUOTENAME(ColumnName),N',') + #CRLF +
N'FROM dbo.Products;'
FROM #Columns;
PRINT #SQL; --Your best friend
EXEC sys.sp_executesql #SQL;
If you don't want to use a table type, you can use STRING_SPLIT:
SELECT #SQL = N'SELECT ' + STRING_AGG(QUOTENAME([Value]),N',') + #CRLF +
N'FROM dbo.Products;'
FROM STRING_SPLIT(#Columns,',');
Having a table populated with databases and table names, is it possible to create some dynamic query based on those fields? Something like:
DECLARE #mysearch NVARCHAR(MAX)= 'SELECT db_name, tbl_name FROM UserConfig where ID = 1';
SELECT * FROM [db_name]..[tbl_name]
Being db_name and tbl_name the result values of #mysearch query.
For clarification, database and table names from where I need to select data are in a table, not hardcoded.
Example:
SELECT * FROM MYDB..MyTable
But "MYDB" and "MyTable" are values stored somewhere else.
Thanks.
I am reading a lot through the lines here, but are you actually after this?
DECLARE #SQL nvarchar(MAX);
DECLARE #CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SELECT #SQL = N'SELECT *' + #CRLF +
N'FROM ' + QUOTENAME(db_name) + N'.dbo.' + QUOTENAME(tbl_name) + N';'
FROM UserConfig
WHERE ID = 1;
EXEC sp_executesql #SQL;
This assumes a single row would be returned for a single value of ID in the table UserConfig.
I have several tables having the same structure. The tables are named by year that is 2001,2002 and so on. I am in need to search a column for a value in each table and get the count for each table.
I have created a stored procedure below but I keep getting an error
Invalid column 'lol'
This is the stored procedure used:
CREATE PROCEDURE [dbo].[CountSP]
#TableName NVARCHAR(128),
#SearchParam NVARCHAR(50),
#SearchInput NVARCHAR(200)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'SELECT COUNT('+QUOTENAME(#SearchParam)+') FROM ' + QUOTENAME(#TableName) +'WHERE'+QUOTENAME(#SearchParam)+'LIKE '+QUOTENAME(#SearchInput)+
+ N' SELECT * FROM '+QUOTENAME(#TableName)
EXECUTE sp_executesql #Sql
END
Executing it:
DECLARE #return_value INT
EXEC #return_value = [dbo].[CountSP]
#TableName = N'1999',
#SearchParam = N'USERDESC',
#SearchInput = N'lol'
SELECT 'Return Value' = #return_value
I don't know why you are using LIKE operator there while you don't use wildcards, also use SysName datatype directly for object names.
Create PROCEDURE [dbo].[CountSP]
(
#TableName SysName,
#SearchInput NVARCHAR(50),
#SearchParam SysName
)
AS
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX) = N'SELECT COUNT(' +
QUOTENAME(#SearchParam) +
N') FROM ' +
QUOTENAME(#TableName) +
N' WHERE ' +
QUOTENAME(#SearchParam) +
N' = ' + --You can change it to LIKE if needed
QUOTENAME(#SearchInput, '''') +
N';';
-- There is no benifits of using LIKE operator there
EXEC sp_executesql #SQL;
Then you can call it as
EXEC [dbo].[CountSP] N'YourTableNameHere', N'SearchInput', N'ColumnName';
This is because it is currently translated to :
SELECT COUNT([USERDESC]) FROM [1999] WHERE [USERDESC] LIKE [lol]
this means that it is comparing the "USERDESC" column with the "lol" column but from what I am understanding lol isn't a column but a value? which means you should lose the QUOTENAME for that variable.
See the documentation here : https://learn.microsoft.com/en-us/sql/t-sql/functions/quotename-transact-sql?view=sql-server-2017
You need to pass your parameter #SearchInput as a parameter to sp_execute:
CREATE PROCEDURE [dbo].[CountSP] #TableName sysname, --This is effectively the same datatype (as sysname is a synonym for nvarchar(128))
#SearchParam sysname, --Have changed this one though
#SearchInput nvarchar(200)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql nvarchar(MAX);
SET #Sql = N'SELECT COUNT(' + QUOTENAME(#SearchParam) + N') FROM ' + QUOTENAME(#TableName) + N'WHERE' + QUOTENAME(#SearchParam) + N' LIKE #SearchInput;' + NCHAR(13) + NCHAR(10) +
N'SELECT * FROM ' + QUOTENAME(#TableName);
EXECUTE sp_executesql #SQL, N'#SearchInput nvarchar(200)', #SearchInput;
END;
QUOTENAME, by default, will quote a value in brackets ([]). It does accept a second parameter which can be used to define a different character (for example QUOTENAME(#Value,'()') will wrap the value in parentheses). For what you want though, you want to parametrise the value, not inject (a quoted) value.
I want to select the store procedure parameter as aliases in select statement in sql
example i have two parameter in store procedure
#programcode int,
#class int
Query where I want use those parameters as alias.
select programcode as #programcode from tbl_name
Why would you want a column alias to be a number?
In any case, you can write this as:
DECLARE #sql nvarchar(MAX);
SET #sql = N'
SELECT programcode AS [' + CAST(#programcode AS VARCHAR(MAX)) + ']
FROM tbl_name
';
EXEC sp_executesql #sql;
Numbers are not really recommended for column aliases, so they need to use escapes.
Try this query.
DECLARE #SqlText nvarchar(MAX);
SET #sqlText = N'SELECT programcode AS ' + CAST(#programcode AS VARCHAR(MAX)) + ' FROM tbl_name'
Exec (#sqlText)