有没有办法使用准备好的语句 select 变量列?

Is there a way to use a prepared statement to select a variable column?

以下代码使用准备好的语句,似乎不适用于 select home_address 的 table students :

SET @mycolumn = 'home_address' ;
SET @s = 'SELECT ? FROM students' ;
PREPARE statement FROM @s;
EXECUTE statement USING @mycolumn ;

实际上,这些指令将只是 return 一个名为“?”的列,其中填充了字符串 'home_address',并且行数与 table students 一样多.

我怎样才能完成这项工作?我知道这种语法是可行的,因为以下示例(取自 Is it possible to execute a string in MySQL?)有效:

SET @username = 'test';
SET @password = 'asdf';
SET @Expression = 'SELECT id FROM Users WHERE name = ? AND pass = ?;' ;
PREPARE myquery FROM @Expression;
EXECUTE myquery USING @username, @password;

这不可能。不同之处在于您动态引用数据库的对象,而不是仅仅传递一个字符串。

准备好的语句通过指定完整的 SQL 语句和您要传入的 strings/values 的占位符来工作。然后您的 RDBMS 可以解析查询并在您传入之前确定它的完整执行路径参数。一旦该步骤完成,它就会接收参数并获取数据。这就是准备好的语句如此安全的原因。执行路径是预先确定的,所以不可能传入更多SQL并更改它。

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

为了扩展 JNevill 所说的内容,而不是根据原始 post 中的示例动态构建 SQL 查询,您可以 select 来自 [student] 并让应用层 return 只有你想要的一列。虽然这意味着在后端和前端之间传输更多数据,但它会更加安全。例如,如果您在 C# .NET 中构建(它可以是任何 language/platform- 仅以此为例来说明我的意思):

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]);
}

这样,您的应用层将处理一些数据管理。