Column heading contained in TSQL variable - sql

Please see the DDL below:
CREATE TABLE TestTable (id int identity, name varchar(30))
INSERT INTO TestTable (Name) VALUES ('Ian')
declare #Test As varchar(100)
set #Test = 'Name'
SELECT #Test FROM TestTable
The output from the SELECT is 'Name'. I want the output to be: 'Ian'. How?

You can't use a variable to tell SQL Server what column, table, database etc. you want to use. You need to enclose this type of code in dynamic SQL.
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT ' + QUOTENAME(#Test) + ' FROM dbo.TestTable;';
EXEC sp_executesql #sql;
Here's why I prefer sp_executesql instead of EXEC() as a standard best practice, and here's why you should always use the schema prefix (e.g. dbo.) when referencing objects. QUOTENAME() can help protect you from SQL injection in this case, since I don't know where the value for #Test ultimately comes from.

You can use EXEC to execute a fabricated SQL string:
declare #Test As varchar(100)
set #Test = 'Name'
EXEC ('SELECT ' + #Test + ' FROM TestTable')
The standard warning for these answers is be certain that you can control what gets put in the SQL statement or use restrictive rights (e.g. read-only) to execute them, otherwise you could get something like this:
declare #Test As varchar(100)
set #Test = '1 ; DROP TABLE TestTable; --'
EXEC ('SELECT ' + #Test + ' FROM TestTable')

Generate a string dynamically and use exec
EXEC ('SELECT ' + #Test + ' FROM TestTable')

Related

Execute sp_executesql, Table Variabe not Declared

I am Using SQL server 2012 and i want to select random columns from my table by applying where condition in this query:
EXECUTE sp_executesql
N'SELECT *
FROM #table
WHERE #Col = #Value',
N'#Value nvarchar(44),#table nvarchar(55),#Col nvarchar(30)',
#Value = 'Cus_1',#Col='CustId',#table='SaleOrder';
But when I execute it, it shows error
Must declare the table variable "#table"
I also tried it to declare by this: #table table(Id nvarchar(30)), but thin it shows again an error on table type...
Please help
This is what you are trying to run:
EXECUTE sp_executesql
N'SELECT * FROM #table WHERE #Col = #Value',
N'#Value nvarchar(44), #table nvarchar(55), #Col nvarchar(30)',
#Value = 'Cus_1', #Col='CustId', #table='SaleOrder';
Alas. You cannot substitute in a table name or column name using parameter substitution. So, SQL Server is looking for a table variable called #table. You can fix this by putting the values directly into the string:
declare #Col = 'CustId', #table = 'SaleOrder';
declare #sql nvarchar(max) = N'SELECT * FROM ' + #table + ' WHERE ' + #Col + ' = #Value';
EXECUTE sp_executesql #sql,
N'#Value nvarchar(44)',
#Value = 'Cus_1';
Unfortunately, I cannot find a good reference in the documentation that explains what is happening. When a statement is compiled, it is allowed to have parameters. However, the parameters are for values in the statement, not for column, table, database, or UDF names or for keywords. The statement itself is compiled, with place holders for the parameters, and in order to be compiled, the SQL engine needs to resolve all object names.

How to access a database given a string of its name

Alright so say I have code that looks like this.
CREATE Table database_info
(
DBName NVARCHAR (MAX)
);
INSERT INTO database_info (DBName)
VALUES ('db1')
SELECT * FROM database_info
DECLARE #temp nvarchar(MAX)
SET #temp = (SELECT DBName FROM database_info where database_info.DBName = 'db1')
--How I want it to work SELECT * FROM #temp
Is there any kind of operation I could do on this temporary variable to have the string act as a regular SQL command?
Thanks
You may execute a dynamic sql using EXEC. Now, declaring the #sql variable would be quite too much in this case, but it is useful when you are not sure of the length of the statement you will pass to it.
DECLARE #sql AS VARCHAR(MAX)
SET #sql = 'SELECT * FROM ' + #temp
EXEC(#sql)

Send query as parameter to SQL function

I want to create a SQL tabled-value function that will receive a query as n parameter through my API. In my function I want execute that query. The query will be a SELECT statement.
This is what I have done so far and what to achieve but it is not the correct way to do so.
CREATE FUNCTION CUSTOM_EXPORT_RESULTS (
#query varchar(max),
#guid uniqueidentifier,
#tableName varchar(200))
RETURNS TABLE
AS
RETURN
(
-- Execute query into a table
SELECT *
INTO #tableName
FROM (
EXEC(#query)
)
)
GO
Please suggest the correct way!
Try this one -
CREATE PROCEDURE dbo.sp_CUSTOM_EXPORT_RESULTS
#query NVARCHAR(MAX) = 'SELECT * FROM dbo.test'
, #guid UNIQUEIDENTIFIER
, #tableName VARCHAR(200) = 'test2'
AS BEGIN
SELECT #query =
REPLACE(#query,
'FROM',
'INTO [' + #tableName + '] FROM')
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = '
IF OBJECT_ID (N''' + #tableName + ''') IS NOT NULL
DROP TABLE [' + #tableName + ']
' + #query
PRINT #SQL
EXEC sys.sp_executesql #SQL
RETURN 0
END
GO
Output -
IF OBJECT_ID (N'test2') IS NOT NULL
DROP TABLE [test2]
SELECT * INTO [test2] FROM dbo.test
What I see in your question is encapsulation of:
taking a dynamic SQL expression
executing it to fill a parametrized table
Why do you want to have such an encapsulation?
First, this can have a negative impact on your database performance. Please read this on EXEC() and sp_executesql() . I hope your SP won't be called from multiple parts of your application, because this WILL get you into trouble, at least performance-wise.
Another thing is - how and where are you constructing your SQL? Obviously you do it somewhere else and it seems its manually created. If we're talking about a contemporary application, there are lot of OR/M solutions for this and manual construction of TSQL in runtime should be always avoided if possible. Not to mention EXEC is not guarding you against any form of SQL injection attacks. However, if all of this is a part of some database administration TSQL bundle, forget his paragraph.
At the end, if you want to simply load a new table from some existing table (or part of it) as a part of some administration task in TSQL, consider issuing a SELECT ... INTO ... This will create a new target table structure for you (omitting indexes and constraints) and copy the data. SELECT INTO will outperform INSERT INTO SELECT because SELECT INTO gets minimally logged.
I hope this will get you (and others) at least a bit on the right track.
You can use stored procedure as well, here is the code that you can try.
CREATE FUNCTION CUSTOM_EXPORT_RESULTS
(
#query varchar(max),
#guid uniqueidentifier,
#tableName varchar(200)
)
RETURNS TABLE
AS
RETURN
(
declare #strQuery nvarchar(max)
-- Execute query into a table
SET #strQuery = REPLACE(#query,'FROM', 'INTO '+#tableName+' FROM')
exec sp_executesql #strQuery
)
GO

Getting IDENTITY from dynamic INSERT

In a stored procedure I am dynamically creating a query with a INSERT. This is done in order to force default values (like with #name if it is NULL).
SET #sql = 'INSERT INTO table (username, password'
+ CASE #name IS NULL THEN '' ELSE ',name' END
+ ') VALUES (''root'',''gelehallon''' +
+ CASE #name IS NULL THEN '' ELSE ',''#name''' END
+ ')'
EXEC sp_executesql #sql
SET #id = SCOPE_IDENTITY()
#id will be 0 no matter.
How can I retrieve the IDENTITY in a safe manner even if another thread is running the same stored procedure simultaneously?
SET #sql = 'INSERT INTO table (username, password) VALUES (#username,#pwd)
SELECT #id = SCOPE_IDENTITY()'
EXEC sp_executesql #sql,
N'#username VARCHAR(50), #pwd VARCHAR(50), #id INTEGER OUTPUT',
'root', 'gelehallon', #id OUTPUT
-- #id now has SCOPE_IDENTITY() value in
Though a few points:
- assuming this is a simplified example as there doesn't seem to be a need to use dynamic SQL in this example
- assuming you're not going to store real passwords in plain text in the db!
Alternatively, you can use the OUTPUT clause with the INSERT statement. That will cause the dynamic statement, and, consequently, the system stored procedure used to invoke it, to return a rowset (one row in your case). You can grab at the chance and insert the rowset into a table variable, and then read the value.
Basically, it might look like this:
SET #sql = 'INSERT INTO table (...) OUTPUT inserted.ID VALUES (...)';
DECLARE #ScopeIdentity (ID int);
INSERT INTO #ScopeIdentity
EXEC sp_executesql #sql;
SELECT #id = ID FROM #ScopeIdentity;

Don't display dynamic query in result

Is it possible to hide a dynamic query from the result sets provided from a Stored Procedure?
I am using the ##rowcount of the dynamic query to set a variable that is used to determine whether another query runs or not.
The other query is used by code that I cannot change - hence why I am changing the Stored Procedure. The dynamic query returns as the first result set from the Stored Procedure is now the result of the dynamic query which currently is "breaking" the calling code.
Thanks in advance
I have managed to solve this by inserting the result of the dynamic query into a temporary table and then retrieving the rowcount from the temporary table.
-- Create query
declare #query nvarchar(max)
set #query = 'select ' + #entityname + 'id from ' + #entityname + ' where ' + #entityname + 'id = ' + cast(#entityid as nvarchar(100))
-- Insert into to temp table - no new result set displayed!
declare #tbl table (EntityID int not null primary key)
insert into #tbl
exec (#query)
-- Retrieve variable from temporary table
declare #count int
select #count = count(*) from #tbl
Above is the code I ended up using.
Try wrapping the dynamic query like this:
Set #query = 'SELECT COUNT(*) FROM (' + #Query + ') t'