Using table columns in prepared statement parameter - sql

My page has a dropdown list that let a user choose any search category like title, description and so forth. So I have this SQL statement:
select * from table where "selected value from dropdown list" = "searchform"
I would like to pass it to the prepared statement like this:
select * from table where ? = ?
Since my select statements have the same form, only the columns in the where clause are different, is there a way to do this without manually creating select statements for every column?

Yes, it is called dynamic sql.
DECLARE #sql AS VARCHAR(MAX)
SET #sql = 'select * from table where ' + #column + ' = ''' + #value + ''''
EXEC(#sql)
You must check if the column is of numeric type.
You should also be careful for sql injection. My example is a very simplistic one, so you have to do your own checks.
For instance use of QUOTENAME would be useful:
DECLARE #sql AS VARCHAR(MAX)
SET #sql = 'select * from table where ' + QUOTENAME(#column) + ' = ''' + #value + ''''
EXEC(#sql)
The above examples are simply TSQL. In your prepared statement i think you could have the following:
PreparedStatement pstmt = con.prepareStatement("
DECLARE #sql AS VARCHAR(MAX)
SET #sql = 'select * from table where ' + QUOTENAME(?) + ' = ? '
EXEC(#sql)
");
pstm.setString(1,columnName);
pstm.setString(2,filterValue);
Unfortunately i am not familiar with JAVA, so i have not tested this. I think it worths a try though.
The above #sql variable will produce a statement like :
select * from table where [columnname] = filtervalue
columnname wrapped with brackets will help against SQL injection.

Related

Use dynamic column name in where clause without executing a variable

I use SQL Server and have the following query:
declare #variable nvarchar(max)
set #variable = 'Fixed_Assets'
declare #sql nvarchar(max)
set #sql = 'Select ' + #variable + ' from table where ' + #variable + '= 1 '
But how could I still use #variable as a value and not a column name?
I want to add a column (Name) and then with the constant value of Fixed Assets
You can't directly insert a variable as a column name into a command, but you can create a command as a nvarchar, concat another variable into it (in your case the column name), then use Exec() to run it.
DECLARE #variable varchar(10)
SET #variable = 'YourColumn'
DECLARE #sqlCommandText nvarchar(1000);
SET #sqlCommandText = N'select * from table where ' + #variable + ' = ''1'''
Exec (#sqlCommandText)
Don't forget if you have a single quote inside a string in sql you need to escape them by doubling them up.

selecting a variable string name in sql select query in case of stored procedures

Suppose I want to select a constant value in an sql query, I could do something like this :
select name,age,'tick' from tableA
I want to dynamically generating an sql query using stored procedures. For example :
SELECT #SQL = 'SELECT CID,DOB, NAME, '+#Scname+' from ' + #TableName
Where #TableName, #Scname are dynamically generated variables in a while loop. Here #Scname is interpreted as a column name instead of a constant string when executing query on #TableName. I have tried using escape characters as follows :
SELECT #SQL = 'SELECT CID,DOB, NAME, \"'+#Scname+'\" from ' + #TableName
But it returns a floating point value full of zeros instead of the string contained in #Scname.
I think following should work
SET #SQL = 'SELECT CID,DOB, NAME,'+''''+#Scname+''''+' from '+ #TableName
Try
SELECT #SQL = 'SELECT CID,DOB, NAME,' + QUOTENAME(#Scname, '''') + ' from ' + #TableName

How to pass column names in a SQL query as parameters using report builder 3.0

I am using "Microsoft SQL Server Report Builder 3.0" on "SQL Server Reporting Services 2012".
From a main report main.rdl I am calling a drillthrough report detail.rdl
The main.rdl report has a table and each text box of this table is clickable and drillthrough action. When user clicks on any text box the detail.rdl report is called. One parameter that is passed to detail.rdl report is used as a column name in the SQL. This SQL fetches data needed for detail.rdl report
When I run the SQL query for detail.rdl report that is built using parameters, it is not showing any error but doesn't fetch any data either. I think what is happening is that as the parameter has data type Text, it's replaced in SQL with quotes which might be causing it not to fetch any data.
When I run the same SQL directly on DB after replacing the column name with parameter value (without quotes) it does fetch data.
Is there any specific way to pass parameters that will be used as column names that I am missing here?
SQL that I am trying from report builder:
SELECT
table_name.column1
,table_name.column21
,table_name.column15
,table_name.column6
,table_name.column9
,table_name.column2
,table_name.column19
,#column --the value in this variable is an existing column name from table table_name
FROM
table_name
WHERE
table_name.column1 LIKE #company
AND table_name.column21 LIKE #platform
AND (#column is null OR #column = '' OR #column = 'N/A' OR #column = 'Unknown');--I want to use same variable here as well
UPDATE:
I was able to get the SQL working by adding
DECLARE #company varchar(10)
SET #company = ''company_name''
DECLARE #platform varchar(10)
SET #platform = ''platform_name''
after the line
SET #SQL =
'
Unfortunately "Microsoft SQL Server Report Builder 3.0" is not able to execute this SQL as it asks for value of variable #SQL even though it's value is defined. I did try Declaring and setting the value of #SQL in same line as:
DECLARE #SQL varchar(5000) = 'DECLARE #company varchar(10)
But report builder still asks for value of #SQL and report doesn't run :-(
It's hard to tell what the problem is without seeing your code but you can't just swap a string in the SQL like (I think) you are trying to do.
To test your SQL just do something simple in Management Studio like
DECLARE #MyParm varchar(256) = 'myColumnName'
SELECT *, #MyParm FROM myTable
This will return all columns from MyTable, plus a string value of 'myColumnName' as the final column.
If this is what you are trying to do then you'll probably need to change your SQL to use dynamic SQL, something like this.
DECLARE #MyParm varchar(256) = 'myCOlumnName'
DECLARE #SQL varchar(max)
SET #SQL = 'SELECT *, ' + #MyParm + ' FROM myTable'
EXEC (#SQL)
If I've got this completely wrong, please post some sample code so we can see what you are attempting.
EDIT: here is a specific answer based on your sample code
DECLARE #Column sysname = 'Column999'
DECLARE #SQL varchar(max)
SET #SQL =
'SELECT
table_name.column1 ,table_name.column21 ,table_name.column15 ,table_name.column6
,table_name.column9 ,table_name.column2 ,table_name.column19
,' + #column +
' FROM table_name
WHERE table_name.company LIKE #company
AND table_name.platform LIKE #platform
AND (' + #column + ' is null OR ' + #column + ' = '''' OR ' + #column + ' = ''N/A'' OR ' + #column + ' = ''Unknown'')'
-- uncomment below to check SQL statement is correct
--print #sql
-- exec the SQL statement
exec (#sql)
As it stands, this will execute the following sql
SELECT
table_name.column1 ,table_name.column21 ,table_name.column15 ,table_name.column6
,table_name.column9 ,table_name.column2 ,table_name.column19
,Column999 FROM table_name
WHERE table_name.company LIKE #company
AND table_name.platform LIKE #platform
AND (Column999 is null OR Column999 = '' OR Column999 = 'N/A' OR Column999 = 'Unknown')

Adding a table variable in Dynamic SQL

I am a beginner in Dynamic SQL and trying to write a dynamic sql code in which I need to include a table variable .When I try to include the table variable I am getting an error saying that I need to include the Static variable.
Below is just part of the code
DECLARE #NAMES TABLE (name varchar)
DECLARE #fields varchar(max);
.
.
.
Select #fields=FROM sys.columns
WHERE object_id=object_id('dbo.employees')
order by name
SET #SQL=''
SET #SQL='Select '+ #fields
SET #SQL=#SQL + ' from dbo.test()'
SET #SQL = #SQL + ' WHERE name IN'
SET #SQL= #SQL + '(Select name from '
SET #SQL=#SQL + #NAMES +')'
To start with, your SELECT to get the column names won't work at all. You need something like this:
DECLARE #fields nvarchar(max);
SET #fields = N'';
SELECT #fields += CASE WHEN LEN(#fields) = 0 THEN N'' ELSE N', ' END + name
FROM sys.columns
WHERE object_id=object_id('dbo.employees')
ORDER BY column_id
PRINT #fields;
I'm honestly not sure what the rest of your SQL is trying to do... it's trying to select the fields from the employee table from the return of a table-valued function called test()? Where the 'name' column from that test() result set is in ... what? You'll need to be a lot more clear before I can give you a complete answer. One major problem is that you've never actually filled your table variable with anything, so ... I have no idea what you're going for. Knowing the definition of the Test() function would also be helpful.
But at least the above will give you the #fields variable set correctly to the list of columns in the table dbo.employee.
When doing Dynamic SQL, it really helps to write out the end resulting SQL you want, and then identify what parts of that SQL should be filled in by variable data, and work backwards. It's then a lot easier to construct your SQL to build your dynamic SQL.
You need to include the tablevariable logic to dynamic sql
--You need to load #names inside dynamic sql
DECLARE #fields varchar(max);
.
.
.
Select #fields=FROM sys.columns
WHERE object_id=object_id('dbo.employees')
order by name
SET #SQL='DECLARE #NAMES TABLE (name varchar); '
SET #SQL +=' Select '+ #fields
SET #SQL=#SQL + ' from dbo.test()'
SET #SQL = #SQL + ' WHERE name IN'
SET #SQL= #SQL + '(Select name from '
SET #SQL=#SQL + ' #NAMES )'
Or you can load into temp table and access the temptable inside dynamic sql. This means you will be loading temptable like #names and then use that in dynamic sql...

Update data in a SQL Server temp table where the column names are unknown

In a stored procedure I dynamically create a temp table by selecting the name of applications from a regular table. Then I add a date column and add the last 12 months. The result looks like this:
So far so good. Now I want to update the data in columns by querying another regular table. Normally it would be something like:
UPDATE ##TempTable
SET [columName] = (SELECT SUM(columName)
FROM RegularTable
WHERE FORMAT(RegularTable.Date,'MM/yyyy') = FORMAT(##TempMonths.x,'MM/yyyy'))
However, since I don't know what the name of the columns are at any given time, I need to do this dynamically.
So my question is, how can I get the column names of a temp table dynamically while doing an update?
Thanks!
I think you can use something like the following.
select name as 'ColumnName'
from tempdb.sys.columns
where object_id = object_id('tempdb..##TempTable');
And then generate dynamic sql using something like the following.
DECLARE #tableName nvarchar(50)
SET #tableName = 'RegularTable'
DECLARE #sql NVARCHAR(MAX)
SET #sql = ''
SELECT #sql = #sql + ' UPDATE ##TempTable ' + CHAR(13) +
' SET [' + c.name + '] = (SELECT SUM([' + c.name + ']) ' + CHAR(13) +
' FROM RegularTable' + CHAR(13) +
' WHERE FORMAT(RegularTable.Date,''MM/yyyy'') = FORMAT(##TempMonths.x,''MM/yyyy''));' + CHAR(13)
from tempdb.sys.columns c
where object_id = object_id('tempdb..##MyTempTable');
print #sql
-- exec sp_executesql #sql;
Then print statement in above snippet shows that the #sql variable has the following text.
UPDATE ##TempTable
SET [Test Application One] = (SELECT SUM([Test Application One])
FROM RegularTable
WHERE FORMAT(RegularTable.Date,'MM/yyyy') = FORMAT(##TempMonths.x,'MM/yyyy'));
UPDATE ##TempTable
SET [Test Application Two] = (SELECT SUM([Test Application Two])
FROM RegularTable
WHERE FORMAT(RegularTable.Date,'MM/yyyy') = FORMAT(##TempMonths.x,'MM/yyyy'));
So now, you use sp_exec to execute the updates as follows (un-comment it from above snippet).
exec sp_executesql #sql;
If it's a 1 time UPDATE you can PRINT the dynamic SQL statement (as shown above) and then execute it in the SSMS Query Windows.
I recommend you use the print statement first to make sure the UPDATE statements generated are what you want, and then do the sp_executesql or run the printed UPDATE statement in the query window.