1

I am creating a web page to host a database.

I want this web page to have a search box feature that can update a GridView in visual studio 2017 for tables in SSMS 2014.

I want this GrideView to be dynamic in that a end user could select a table, a column, and then specify a "searchString" to apply to the data in the column.

The web page looks like this:

On to the code.

On the search button click event I want the values in each of the three text boxes to be passed into a stored procedure.

Here is the current code for the button click event.

protected void btnSearch_Click(object sender, EventArgs e)
{
    using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["CID1ConnectionString"].ConnectionString))
    {
        SqlDataAdapter searchAdapter = new SqlDataAdapter("Search", con);
        searchAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;
        searchAdapter.SelectCommand.Parameters.AddWithValue("@TableName", TableSearchBox.Text.Trim());   // passing text in first text box in
        searchAdapter.SelectCommand.Parameters.AddWithValue("@columnSpecifier", ColumnSearchBox.Text.Trim());   // passing text in second text box in
        searchAdapter.SelectCommand.Parameters.AddWithValue("@searchString", searchStringBox.Text.Trim());   // passing text in third text box in

        DataTable temptable = new DataTable(); //table to have data that satisfies searchString copied to
        searchAdapter.Fill(temptable); //filling table from adapter

        tableDisplay.DataSource = temptable;
        //tableDisplay.Columns[0].Visible = false;
        tableDisplay.DataBind();//bind step
    }
}

Here is my current stored procedure:

ALTER PROCEDURE dbo.Search 
    (@tableName NVARCHAR(50),
     @columnSpecifier NVARCHAR(50),
     @searchString NVARCHAR(50)) 
AS 
     EXEC('SELECT * FROM ' + @tableName + ' WHERE ' + @columnSpecifier + ' LIKE '' + @searchString + %''')

Which is supposed to achieve a query similar to this if the end user populated the first text box with "Basic_Info", the second text box with "Name", and the final text box with "M".

SELECT Name 
FROM Basic_Info 
WHERE Name LIKE 'M%'

It appears since I am using a dynamic table name in the FROM clause I need to use dynamic SQL. I have put my query in an EXEC block and surrounded my SQL syntax with single quotes ('). These single quotes appear to make using the % operator in my LIKE clause impossible but maybe I'm just not seeing it.

Is there a way of achieving this functionality? Should I back up and do this another way? I have read that this might cause SQL injection which sounds like something to be avoided. Any advice is appreciated even about this post and its format. This is my first question on stack overflow!

EDIT: Turns out the stored procedure and parameter use is unnecessary. My final button click event looks like this and just gets the textbox text value to fill out the query.

        protected void btnSearch_Click(object sender, EventArgs e)
    {
            using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["CID1ConnectionString"].ConnectionString))
            {
            DataTable temptable = new DataTable(); //table to have data that satisfies searchString copied to
            SqlDataAdapter searchAdapter = new SqlDataAdapter("SELECT * FROM " + TableSearchBox.Text.Trim() + " WHERE " + ColumnSearchBox.Text.Trim() + " LIKE '"  + searchStringBox.Text.Trim() + "%'", con);
            searchAdapter.Fill(temptable); //filling table from adapter
            tableDisplay.DataSource = temptable;
            tableDisplay.DataBind();//bind step
            }
    }
marc_s
  • 675,133
  • 158
  • 1,253
  • 1,388
MasonBaird
  • 11
  • 5
  • You likely want to escape the `searchString` - `public static string SqlLikeEscape(this string value) { if (string.IsNullOrEmpty(value)) { return value; } return Regex.Replace(value, @"(?%|_|\[)", @"[${ch}]"); }` Otherwise, for example, you will struggle to search for a `%` value in the table. – mjwills Jul 17 '18 at 03:35
  • I would suggest using drop down lists for the user to select from for the table and column names. – Mary Jul 17 '18 at 04:07
  • They are in place! (although poorly labeled) They are right below the the search boxes for each. – MasonBaird Jul 17 '18 at 04:12
  • Possible duplicate of [What are good ways to prevent SQL injection?](https://stackoverflow.com/questions/14376473/what-are-good-ways-to-prevent-sql-injection) – mjwills Jul 18 '18 at 02:25

1 Answers1

3

Here's a parameterized dynamic SQL example, using QUOTENAME for identifiers:

CREATE PROCEDURE dbo.Search
    @tableName sysname,
    @columnSpecifier sysname,
    @searchString nvarchar(50)
AS
DECLARE @SQL nvarchar(MAX);
SET @SQL = N'SELECT * FROM ' + QUOTENAME(@tableName) + N' WHERE ' + QUOTENAME(@columnSpecifier) + N' LIKE @searchString + ''%'';';
EXEC sp_executesql
      @SQL
    , N'@searchString nvarchar(50)'
    , @searchString = @searchString;
GO

I suggest one generally avoid AddWithValue because it infers the SQL database type from the provided .NET type. Although this isn't a concern here because you are using a stored procedure and System.String maps to SQL Server nvarchar, it is best to specify the desired SqlDbType and length (or precision and scale) explicitly. Below is one method to do that.

searchAdapter.SelectCommand.Parameters.Add("@TableName", SqlDbType.NVarChar, 128).Value = TableSearchBox.Text.Trim());   // passing text in first text box in
searchAdapter.SelectCommand.Parameters.Add("@columnSpecifier", SqlDbType.NVarChar, 128).Value = ColumnSearchBox.Text.Trim());   // passing text in second text box in
searchAdapter.SelectCommand.Parameters.Add("@searchString", SqlDbType.NVarChar, 50).Value = searchStringBox.Text.Trim());   // passing text in third text box in
Dan Guzman
  • 35,410
  • 3
  • 30
  • 55
  • How would you call this from C#? `cmd.Parameters.Add("@tableName", SqlDbType. ` ??? sysname is not available from the provider. – Mary Jul 17 '18 at 04:04
  • 1
    @Mary, `sysname` is an alias for nvarchar(128). I used it for the table and column name parameters because that's the actual type of these identifiers. I added an example and information about avoiding AddWithValue. – Dan Guzman Jul 17 '18 at 11:10
  • Thanks for clarifying what data type to use. I did see that when I looked up sysname but I wasn't sure. Sees a bit version dependent. Plus one for the excellent blog on `.AddWithValue` vs.`.Add` I have always used `.Add` but am lax about the size parameter. I have let posters slide with `.AddWithValue because I was so happy that they were at least using Parameters. – Mary Jul 17 '18 at 17:33