SQL Server expression substitution in SELECT statements as column names - sql-server

How do I evaluate a character expression to resolve to a valid column name in a SELECT statement that would return column row values? Eg valid column name = Customer_1 == 'Customer_'+'1'

You need to use dynamic SQL. An example
DECLARE #DynSQL nvarchar(max)
DECLARE #Suffix int = 1
SET #DynSQL = N'SELECT Customer_' + CAST(#Suffix as nvarchar(10)) +
N' FROM YourTable WHERE foo = #foo'
EXEC sp_executesql #DynSQL, N'#foo int', #foo=1
As always with dynamic SQL you need to consider SQL injection if any of the inputs to the process will be user supplied.

How do I evaluate a character expression to resolve to a valid column name in a SELECT statement that would return column row values? Eg valid column name = Customer_1 == 'Customer_'+'1'
You're probably doing something wrong if you need to do this, but if you have to: build the column names as rows and then pivot.

Related

Passing Int to dynamic stored procedure fails

I have a dynamic stored procedure in SQL Server that works well to pivot a table:
CREATE PROCEDURE dbo.DynamicPivotTableInSql
#ColumnToPivot NVARCHAR(255),
#ListToPivot NVARCHAR(255),
#SurveyID INT=10
AS
BEGIN
DECLARE #SqlStatement NVARCHAR(MAX)
SET #SqlStatement = N'SELECT *
FROM
(SELECT
[resp_id], [benefit], [weight]
FROM Segment_Responses) myResults
PIVOT
(SUM([weight])
FOR [' + #ColumnToPivot + ']
IN (' + #ListToPivot + ')) AS PivotTable';
EXEC (#SqlStatement)
END
and I call it like this
EXEC DynamicPivotTableInSql
#ColumnToPivot = 'benefit',
#ListToPivot = '[OBSERVABILITY], [COST], [EASE OF USE], [SERVICE]'
Here is where I run into problems. You'll notice I have hardcoded #SurveyID = 10 and if I try to add that as a where statement in the stored procedure like this:
FROM Segment_Responses
WHERE survey_id = ' + #SurveyID + '
and run the stored procedure again I get this error:
Conversion failed when converting the nvarchar value '
SELECT * FROM (
SELECT
[resp_id],
[benefit],
[weight]
FROM Segment_Responses where survey_id=' to data type int.
I've tried to solve this many ways (e.g., passed the Int variable instead of hard coding it) but always get the same result. Any ideas what is going on?
Just to try to add some clarity, when you add together two different types, SQL Server will (where it can) implicitly convert one to the other - the result must be a single type after all.
It decides which one to convert "to the other" based on an order of precedence.
So where you are trying to concatenate a varchar with an int, the int has the higher order of precedence. This is also a common cause of errors and bugs when using a case expression when mixing types in different execution paths of the expression.
You need to be explicit and cast the int to a varchar.
Ideally you would use a parameterised query which would also reuse the cached execution plan - this may be beneficial if the cardinality of the data is similar but sometimes making the value part of the query dynamically can be advantagous, it depends on the use-case.
This is why the syntax EXEC (#SQL) is strongly suggested against. Use sys.sp_executesql and parametrise your statement:
SET #SQL = N'SELECT ...
FROM ...
WHERE survey_id = #SurveyID ...;';
EXEC sys.sp_executesql #SQL, N'#SurveyID int',SurveyID;
The + only works with strings. If you use a number TSQL assumes you are trying to use the addition operator, and tries to convert the string argument to int.
eg this
select 1 + '2'
works and returns 3.
Use CONCAT instead of +, or use an explicit conversion on the int.
eg
WHERE survey_id = ' + cast(#SurveyID as varchar(20)) + '

Dynamic SQL - How to use a value from a result as a column name?

I am working on a dynamic SQL query for a MsSQL stored procedure.
There is a table search.ProfileFields that contains the actual column names in a table I need to query.
My goal is to have the SQL select the specific column in the table, dynamically from its parent query..
A little confusing, heres an example:
DECLARE #sql nvarchar(max)
SELECT #sql = '
SELECT
pfs.SectionID,
pfs.SectionName,
pfs.Link,
(
SELECT
pf.FieldID,
pf.FieldTitle,
pf.FieldSQL,
pf.Restricted,
pf.Optional,
(
SELECT
pf.FieldSQL
FROM
Resources.emp.EmployeeComplete as e
WHERE
e.QID = #QID
) as Value
FROM
search.ProfileFields as pf
WHERE
pf.SectionID = pfs.SectionID
ORDER BY
pf.[Order]
FOR XML PATH (''field''), ELEMENTS, TYPE, ROOT (''fields'')
)
FROM
search.ProfileFieldSections as pfs
WHERE
pfs.Status = 1
FOR XML PATH (''data''), ELEMENTS, TYPE, ROOT (''root'')'
PRINT #sql
EXECUTE sp_executesql #sql, N'#QID varchar(10)', #QID = #QID
In the inner most select. I am querying pf.FieldSQL. I am looking for the actual value that was received by the parent select.
search.ProfileFields has a column called FieldSQL with a few results such as Name, Age, Location.
That is what I am trying to get my inner most select to do.
SELECT Name FROM ... - Name in this case comes from the value of pf.FieldSQL.
How can I go about querying a dynamic column name in this situation?
Have a look at this answer for a couple of suggestions. If your table definition is complex or changes occasionally you probably should use pivot. Here's one that might work for you, so long as column names in the FieldSQL column are well defined, there are not too many of them, and they don't ever change or get added to:
DECLARE #sql nvarchar(max)
SELECT #sql = '
SELECT
pfs.SectionID,
pfs.SectionName,
pfs.Link,
(
SELECT
pf.FieldID,
pf.FieldTitle,
pf.FieldSQL,
pf.Restricted,
pf.Optional,
(
SELECT case pf.FieldSQL
when 'Name' then e.Name
when 'DOB' then convert(nvarchar(10), e.DOB, 126)
-- ... etc.
-- NOTE: may need to aggregated depending on uniqueness of QID:
-- when 'Name' then min(e.Name)
-- when 'DOB' then convert(nvarchar(10), min(e.DOB), 126)
end
FROM
Resources.emp.EmployeeComplete as e
WHERE
e.QID = #QID
) as Value
FROM
search.ProfileFields as pf
WHERE
pf.SectionID = pfs.SectionID
ORDER BY
pf.[Order]
FOR XML PATH (''field''), ELEMENTS, TYPE, ROOT (''fields'')
)
FROM
search.ProfileFieldSections as pfs
WHERE
pfs.Status = 1
FOR XML PATH (''data''), ELEMENTS, TYPE, ROOT (''root'')'
PRINT #sql
EXECUTE sp_executesql #sql, N'#QID varchar(10)', #QID = #QID
Take a look at "PIVOT" operators here PIVOT
Thisshould give you some ideas how to use them.

SQL Server binary value in dynamic sql

I need binary value in dynamic SQL but I am getting an error
The data types nvarchar and binary are incompatible in the add operator
I need help.
DECLARE #MaxSeqValue binary(10)=NULL
DECLARE #script varchar(max)
-- I have incremental binary values in my table,which I can sort it.
SELECT
#MaxSeqValue = MAX(seqvalue)
FROM [dbr].[DBA_CDClog]-- this my log table
WHERE TableName = #TableName2
set #script = 'Select seq value, tablename
from table X
where SeqValue >'+#MaxSeqValue+'
'
You have to cast #MaxSeqValue to nvarchar.
set #script ='
Select seq value,
tablename
from table X
where SeqValue >' + cast(#MaxSeqValue as nvarchar(max))
This answer is worked for me. CAST option didnt workout.
WHERE SeqValue >0x'+CONVERT(nvarchar(max),#MaxSeqValue,2)+'

TSQL Passing a varchar variable of column name to SUM function

I need to write a procedure where I have to sum an unknown column name.
The only information I have access to is the column position.
I am able to get the column name using the following:
SELECT #colName = (SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='TABLENAME' AND ORDINAL_POSITION=#colNum)
I then have the following:
SELECT #sum = (SELECT SUM(#colName) FROM TABLENAME)
I then receive the following error:
Operand data type varchar is invalid for sum operator
I am confused about how to make this work. I have seen many posts on convert and cast, but I cannot cast to an float, numeric, etc because this is a name.
I would appreciate any help.
Thank you
This is not possible. You will have to assemble the SQL query and then execute it. Something like this:
SET #sqlquery = 'SELECT SUM(' + #colName + ') FROM TABLENAME'
EXECUTE ( #sqlquery )
Adjust accordingly.

How to add column dynamically in where clause

I want to include column in where clause depending on the condition.
e.g
select * From emp
where id=7,
and if(code is not null) then code=8;
how can i do this in sql server
If I understand you correct, you could make use of COALESCE.
COALESCE()
Returns the first nonnull expression
among its arguments.
SQL Statement
SELECT *
FROM emp
WHERE id=7
AND code = COALESCE(#code, code)
If code is a column rather than a variable the query in your question would be rewritten as follows.
SELECT *
FROM emp
WHERE id=7 AND (code IS NULL OR code=8)
You'll probably have to create a query dynamically, as a string, and then use the Execute method to actually execute it. This approach has some potentially optimization issues, but it's commonly done. You might wan to Google T-SQL Dynamic Query, or something like that.
Also use this in case of Null value in #var1.
Select * from ABC where Column1 = isNull(#var1, Column1)
here is the example:
declare #SQL varchar(500)
declare #var1 int
set int = 1
set #SQL = 'Select * from ABC Where 1 = 1'
if(#var1 = 1)
set #SQL + #SQL ' And column1 = ' #var1
exec(#SQL)
You can use COALESCE function.
Well,
I don't know if i understood your question, but i guess that you want to include the value of the code column in the results.
If i'm right it can be done in the select part instead of the where clause. i. e.
Select ..., case when code is not null then 8 else code end as code from emp where id = 7
The other interpretation is that you want to filter rows where code <> 8,that would be
Select * from emp where id = 7 and (code is null OR code = 8)

Resources