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

问题描述 投票:0回答:2

以下代码使用准备好的语句,似乎无法选择表的

home_address
students
:

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

事实上,这些指令只会返回一个名为“?”的列,其中填充字符串“home_address”,行数与表一样多

students

我怎样才能做到这一点?我知道这种语法是可能的,因为以下示例(取自是否可以在 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;
mysql mysql-workbench mysql-error-1064
2个回答
5
投票

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

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

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


2
投票

为了扩展 JNevill 所说的内容,您可以从

[student]
中选择所有可能的列,并让应用程序层仅返回您想要的一列,而不是动态构建 SQL 查询。尽管这意味着在后端和前端之间传输更多数据,但它会更加安全。例如,如果您使用 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]);
}

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

© www.soinside.com 2019 - 2024. All rights reserved.