Referencing SQL Server columns dynamically in SP - sql

SQL 2008
Hello,
I have a rather different task I have to do in SQL. It's a bit more involved than this, but I'm going to try to make it simple.
I need to somehow SELECT a column dynamically. Like this:
declare #ColName varchar(50)
select #ColName = 'Column1' --This is an actual column name in a real table called 'MyTable'
select #ColName from MyTable where Column2 = 123
Is there a way to do something like this? Any help or direction would be greatly appreciated!
Thanks,
Jason

you need dynamic SQL, but first read The Curse and Blessings of Dynamic SQL to make sure you don't open yourself up for SQL Injection

DECLARE #colNameIn AS varchar(50) = 'Column1'
DECLARE #template AS varchar(MAX) = 'select {#ColName} from MyTable where Column2 = 123' -- This template can be expanded
-- Protect yourself from injection or invalid columns:
DECLARE #ColName AS varchar(50)
SELECT #ColName = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'MyTable'
AND COLUMN_NAME = #ColNameIn
IF #ColName IS NOT NULL
BEGIN
DECLARE #sql AS varchar(MAX)
SET #sql = REPLACE(#template, '{#ColName}', QUOTENAME(#ColName))
EXEC (#sql)
END

Read the link in #SQLMenace answer!
declare #ColName varchar(50)
select #ColName = 'Column1'
declare #sql varchar(MAX)
select #sql = 'select ' + #ColName + ' MyTable where Column2 = 123'
exec (#sql)

You can do this as using a CASE statement if you have predefined all of the acceptable column names in the procedure.
DECLARE #ColName varchar(50)
SET #ColName = 'Column1'
SELECT CASE #ColName
WHEN 'Column1' THEN Column1
WHEN 'Column2' THEN Column2
END
FROM MyTable
WHERE Column2 = 123

Related

Convert string from column to parameter in dynamic SQL?

I created a dictionary table with 'Condition' column where I store conditions for particular customers. Table's name is CustomerConditions:
Then I created dynamic SQL where I want to use this Condition:
declare
#TableName as nvarchar(10),
#FieldName as nvarchar(20),
#CustName as Nvarchar(50),
#Condition as NVARCHAR(MAX)
set #Condition = (SELECT o.Condition FROM CustomerConditions o WHERE o.Group = #CustName)
declare #strSQL as NVARCHAR(MAX)
SET #strSQL =
'DECLARE #FieldName as nvarchar(20),
#CustName as nvarchar(50)
;WITH NewCTE AS (
SELECT Tab1.Group, '+#FieldName+'
FROM (
SELECT
'+#Condition+' AS Group,
'+#FieldName+'
FROM '+#TableName+' as c) as Tab1)
SELECT * FROM NewCTE'
EXEC(#strSQL)
The problem is that when I pass #Condition to dynamic SQL string from column 'Condition' does not become part of SQL syntax - it's passed as expression, in the result I got:
This is not what I want. I want this 'Case WHEN...' to become part of my SQL syntax.
On the other hand when I'm not using #Condition but pass 'CASE WHEN..' explicitly then everything works well (all declared parameters works well, all is good):
;WITH NewCTE AS (
SELECT Tab1.Group, '+#FieldName+'
FROM (
SELECT
CASE WHEN '+ #FieldName +' LIKE ''XY%'' OR '+ #FieldName +' LIKE ''XYZ%'' then '''+ #CustName +''' END AS Group,
'+#FieldName+'
FROM '+#TableName+' as c) as Tab1)
So how can I pass this 'Case when' condition into dynamic SQL using parameter?
While agreeing with the issue of dynamic prone to injection attacks, and assuming some random values for your non initialized variables, here is how I approach
The trick is
SELECT #Condition = REPLACE(#Condition, '#FieldName', #FieldName )
SELECT #Condition = REPLACE(#Condition, '#CustName', #CustName )
So the main Query will be
declare
#TableName as nvarchar(10) = 'MyTbl',
#FieldName as nvarchar(20) = 'FldName',
#CustName as Nvarchar(50) = 'C1' ,
#Condition as NVARCHAR(MAX)
SELECT #Condition = (SELECT o.Condition FROM CustomerConditions o WHERE o.[Group] = #CustName)
SELECT #Condition = REPLACE(#Condition, '#FieldName', #FieldName )
SELECT #Condition = REPLACE(#Condition, '#CustName', #CustName )
declare #strSQL as NVARCHAR(MAX)
SET #strSQL = 'DECLARE #FieldName as nvarchar(20),
#CustName as nvarchar(50)
;WITH NewCTE AS (
SELECT Tab1.Group, '+#FieldName+'
FROM (
SELECT
'+#Condition+'
'+#FieldName+'
FROM '+#TableName+' as c) as Tab1)
SELECT * FROM NewCTE'
Select(#strSQL)
First provide proper values to your variables and execute this.
Instead of executing the query, what I did was create the query to see whether it got created as you want.
To be certain, you can copy paste the outcome and execute that.
Then you can change the last line to Execute ...

Wrong answer on COL_NAME statement in SQL

I have a problem with that statement
SELECT GENDER
FROM tableName
WHERE (SELECT COL_NAME(OBJECT_ID('[tableName ]'), 5)) = 'M'
It should return all the GENDER from the table where the sex is equal to M
But it returns nothing!
This is the same select but with 'classical' parameters
SELECT GENDER
FROM tableName
WHERE GENDER = 'M'
I also tried using a variable, but with the same blank result!
DECLARE #var NVARCHAR(MAX)
SET #var = (select COL_NAME(OBJECT_ID('[MD_PRODUCT].[TABSOURCE]'), 5))
SELECT GENDER FROM MD_PRODUCT.TABSOURCE WHERE #var = 'M'
I need to use the COL_NAME (or in alternative the COLUMN_NAME of the INFORMATION_SCHEMA) because whole the parameters in the select are generated dynamically...
Can anyone help me?
Thank you
I'm working with SQL Server in SSMS
You seem to be looking for dynamic SQL. You need to prepare your query in a string and use EXEC() to run it.
Consider:
DECLARE #sqlCommand varchar(1000)
DECLARE #columnName varchar(75)
SET #columnName = 'foo'
SET #sqlCommand = 'SELECT GENDER FROM tableName WHERE ' + #columnName + ' = M'
EXEC (#sqlCommand)
Why in the world are you using COL_NAME here??? You should reference the column.
SELECT GENDER
FROM tableName
WHERE GENDER = 'M'
Thank You all i found the solution with the help of GMB answer.
Here is the correct code:
DECLARE #columnName varchar(75)
DECLARE #tableName varchar(75)
declare #sqlCommand varchar(75)
SET #columnName = (select COL_NAME(OBJECT_ID('tableName'), 1))
set #tableName = 'tableName'
SET #sqlCommand = 'SELECT ' +#columnName+ ' FROM ' +#tableName+ ' WHERE ' +#columnName+ ' = 1'
print #sqlCommand --just for print out the the sql command variable #sqlCommand
EXEC (#sqlCommand)

How to store a dynamic SQL result in a variable in T-SQL?

I have a stored procedure which takes 'table name' as parameter. I want to store my 'exec' results to a variable and display using that variable.
Here is my T-SQL stored procedure..
create procedure DisplayTable( #tab varchar(30))
as
begin
Declare #Query VARCHAR(30)
set #Query='select * from ' +#tab
EXEC (#Query)
END
I want to do something like this..
SET #QueryResult = EXEC (#Query)
select #QueryResult
How do i achieve this.. Please help.. I am a beginner..
You can use XML for that. Just add e.g. "FOR XML AUTO" at the end of your SELECT. It's not tabular format, but at least it fulfills your requirement, and allows you to query and even update the result. XML support in SQL Server is very strong, just make yourself acquainted with the topic. You can start here: http://technet.microsoft.com/en-us/library/ms178107.aspx
alter procedure DisplayTable(
#tab varchar(30)
,#query varchar(max) output
)
as
BEGIN
Declare #execution varchar(max) = 'select * from ' +#tab
declare #tempStructure as table (
pk_id int identity
,ColumnName varchar(max)
,ColumnDataType varchar(max)
)
insert into
#tempStructure
select
COLUMN_NAME
,DATA_TYPE
from
INFORMATION_SCHEMA.columns
where TABLE_NAME= #tab
EXEC(#execution)
declare #ColumnCount int = (SELECT count(*) from #tempStructure)
declare #counter int = 1
while #counter <= #ColumnCount
BEGIN
IF #counter = 1
BEGIN
set #query = (SELECT ColumnName + ' ' + ColumnDataType FROM #tempStructure where pk_id= #counter)
END
IF #counter <> 1
BEGIN
set #query = #query + (SELECT ',' + ColumnName + ' ' + ColumnDataType FROM #tempStructure where #counter = pk_id)
END
set #counter = #counter + 1
END
END
When you execute the SP, you'll now get a return of the structure of the table you want.
This should hopefully get you moving.
If you want the table CONTENTS included, create yourself a loop for the entries, and append them to the #query parameter.
Remember to delimit the #query, else when you read it later on, you will not be able to restructure your table.
First of all you have to understand that you can't just store the value of a SELECTon a table in simple variable. It has to be TABLE variable which can store the value of a SELECTquery.
Try the below:
select 'name1' name, 12 age
into MyTable
union select 'name2', 15 union
select 'name3', 19
--declaring the table variable and selecting out of it..
declare #QueryResult table(name varchar(30), age int)
insert #QueryResult exec DisplayTable 'MyTable'
select * from #QueryResult
Hope this helps!

Can I pass column name as input parameter in SQL stored Procedure

create procedure sp_First
#columnname varchar
AS
begin
select #columnname from Table_1
end
exec sp_First 'sname'
My requirement is to pass column names as input parameters.
I tried like that but it gave wrong output.
So Help me
You can do this in a couple of ways.
One, is to build up the query yourself and execute it.
SET #sql = 'SELECT ' + #columnName + ' FROM yourTable'
sp_executesql #sql
If you opt for that method, be very certain to santise your input. Even if you know your application will only give 'real' column names, what if some-one finds a crack in your security and is able to execute the SP directly? Then they can execute just about anything they like. With dynamic SQL, always, always, validate the parameters.
Alternatively, you can write a CASE statement...
SELECT
CASE #columnName
WHEN 'Col1' THEN Col1
WHEN 'Col2' THEN Col2
ELSE NULL
END as selectedColumn
FROM
yourTable
This is a bit more long winded, but a whole lot more secure.
No. That would just select the parameter value. You would need to use dynamic sql.
In your procedure you would have the following:
DECLARE #sql nvarchar(max) = 'SELECT ' + #columnname + ' FROM Table_1';
exec sp_executesql #sql, N''
Try using dynamic SQL:
create procedure sp_First #columnname varchar
AS
begin
declare #sql nvarchar(4000);
set #sql='select ['+#columnname+'] from Table_1';
exec sp_executesql #sql
end
go
exec sp_First 'sname'
go
This is not possible. Either use dynamic SQL (dangerous) or a gigantic case expression (slow).
Create PROCEDURE USP_S_NameAvilability
(#Value VARCHAR(50)=null,
#TableName VARCHAR(50)=null,
#ColumnName VARCHAR(50)=null)
AS
BEGIN
DECLARE #cmd AS NVARCHAR(max)
SET #Value = ''''+#Value+ ''''
SET #cmd = N'SELECT * FROM ' + #TableName + ' WHERE ' + #ColumnName + ' = ' + #Value
EXEC(#cmd)
END
As i have tried one the answer, it is getting executed successfully but while running its not giving correct output, the above works well
You can pass the column name but you cannot use it in a sql statemnt like
Select #Columnname From Table
One could build a dynamic sql string and execute it like EXEC (#SQL)
For more information see this answer on dynamic sql.
Dynamic SQL Pros and Cons
As mentioned by MatBailie
This is much more safe since it is not a dynamic query and ther are lesser chances of sql injection . I Added one situation where you even want the where clause to be dynamic . XX YY are Columns names
CREATE PROCEDURE [dbo].[DASH_getTP_under_TP]
(
#fromColumnName varchar(10) ,
#toColumnName varchar(10) ,
#ID varchar(10)
)
as
begin
-- this is the column required for where clause
declare #colname varchar(50)
set #colname=case #fromUserType
when 'XX' then 'XX'
when 'YY' then 'YY'
end
select SelectedColumnId from (
select
case #toColumnName
when 'XX' then tablename.XX
when 'YY' then tablename.YY
end as SelectedColumnId,
From tablename
where
(case #fromUserType
when 'XX' then XX
when 'YY' then YY
end)= ISNULL(#ID , #colname)
) as tbl1 group by SelectedColumnId
end
First Run;
CREATE PROCEDURE sp_First #columnname NVARCHAR(128)--128 = SQL Server Maximum Column Name Length
AS
BEGIN
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT ' + #columnname + ' FROM Table_1'
EXEC(#query)
END
Second Run;
EXEC sp_First 'COLUMN_Name'
Please Try with this.
I hope it will work for you.
Create Procedure Test
(
#Table VARCHAR(500),
#Column VARCHAR(100),
#Value VARCHAR(300)
)
AS
BEGIN
DECLARE #sql nvarchar(1000)
SET #sql = 'SELECT * FROM ' + #Table + ' WHERE ' + #Column + ' = ' + #Value
--SELECT #sql
exec (#sql)
END
-----execution----
/** Exec Test Products,IsDeposit,1 **/

Using dynamic SQL to specify a column name by adding a variable to simple sql query

sql 2005/ sql 2008
Declare #temp nvarchar(1000)
set #temp = 'ABC'
select col1,col2 from tableA
Along with select query, how to add a variable to the select query ?
expected output :-
select col1,col2,#temp as [col3] from tableA
Where #temp specifies the name of a column in tableA.
If you are trying to specify the column name dynamically, you could take a look at executing dynamic sql. However, you should make sure to read about the dangers of this approach first:
http://www.sommarskog.se/dynamic_sql.html
From that page, there is a sample that shows dynamically specifying the table name -- you could change it so it dynamically specifies the column name instead:
CREATE PROCEDURE general_select #tblname nvarchar(128),
#key varchar(10),
#debug bit = 0 AS
DECLARE #sql nvarchar(4000)
SET #sql = 'SELECT col1, col2, col3
FROM dbo.' + quotename(#tblname) + '
WHERE keycol = #key'
IF #debug = 1 PRINT #sql
EXEC sp_executesql #sql, N'#key varchar(10)', #key = #key
So for example if you had a table 'MyTable' with columns named 'x', 'y', and 'z', it might look like:
DECLARE #columnName nvarchar(128)
DECLARE #sql nvarchar(4000)
set #columnName = 'z'
SET #sql = 'SELECT x, y, ' + #columnName + ' from MyTable'
EXEC sp_executesql #sql, N'#columnName varchar(128)', #columnName = #columnName
Something like this:
select col1,col2 from tableA WHERE col1 = #temp
Or this:
select col1,col2,#temp as col3 from tableA WHERE col1 = #temp
Or this:
select col1,col2,#temp as col3 from tableA
Or if #temp is a column name, then maybe you're looking for a dynamic query?
SET #temp = 'select col1,col2, ' + #temp + ' as col3 from tableA'
EXEC sp_executesql #temp
...