有没有办法使用预准备语句来选择变量列?

时间:2018-01-10 16:58:39

标签: mysql mysql-workbench mysql-error-1064

使用预准备语句的以下代码似乎无法选择表home_address的{​​{1}}:

students

实际上,这些指令只返回一个名为“?”的列,其中填充了字符串“home_address”,并且包含与表SET @mycolumn = 'home_address' ; SET @s = 'SELECT ? FROM students' ; PREPARE statement FROM @s; EXECUTE statement USING @mycolumn ; 一样多的行。

我怎么能让这个工作?我知道这种语法是可行的,因为以下示例(取自Is it possible to execute a string in MySQL?)起作用:

students

2 个答案:

答案 0 :(得分:2)

这是不可能的。区别在于您动态引用数据库的对象,而不是传入字符串。

预备语句通过为您传入的字符串/值的占位符完整地指定SQL语句来工作。然后,您的RDBMS可以在传递参数之前解析查询并确定它的完整执行路径。完成该步骤后,它将获取参数并获取数据。这就是准备好的陈述如此安全的原因。执行路径是预先确定的,因此无法传递更多SQL并进行更改。

因此,如果您不知道列或表,那么它无法解析和构建执行路径。相反,您必须使用连接和执行动态构建SQL。如果您从用户输入中获取列名或表名,那么您必须尽可能地对其进行消毒,并祈祷您的卫生工作比您偷偷摸摸的用户注入SQL的能力更好。

答案 1 :(得分:1)

要扩展JNevill所说的内容,而不是根据原始帖子中的示例动态构建SQL查询,您可以从[student]中选择所有可能的列,并让应用程序层只返回一列想。虽然这意味着在您的后端和前端之间传输更多数据,但它会更加安全。例如,如果您使用C#.NET构建(它可以是任何语言/平台 - 仅以此为例向您展示我的意思):

DataTable dataTable = new DataTable();
string columnName = "home_address";

string connString = @"your connection string here";
string query = "SELECT home_address, work_address, name /*... any other columns the user may want*/ FROM students";

//Alternatively, you can use the following, but it leaves you exposed to SQL injections, even after sanitizing:
//string query = $"SELECT [{columnName}] FROM students";

SqlConnection conn = new SqlConnection(connString);        
SqlCommand cmd = new SqlCommand(query, conn);
conn.Open();

SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dataTable);
conn.Close();
da.Dispose();

List<object> list = new List<object>();
foreach (DataRow row in dataTable.Rows)
{
    list.Add(row[columnName]);
}

这样,您的应用程序层就可以处理一些数据管理。