是什么导致了这个语法错误? oledb 插入语句
What's causing this syntax error? oledb INSERT statement
我发布了我之前遇到的另一个问题,并在一些帮助下解决了这个问题。
我现在收到围绕以下代码的语法错误:
importConnection.Open();
Console.WriteLine("Foxpro connection open");
OleDbCommand deleteOleDbCommand = new OleDbCommand(@"TRUNCATE TABLE CLIENT",
importConnection);
Console.WriteLine("writing to table");
Console.ReadKey();
using (OleDbCommand importCommand = new OleDbCommand(
string.Format("INSERT INTO CLIENT (Title,Fname,Sname)" + "VALUES ({0},{1},{2})",
exportReader.GetValue(0), exportReader.GetValue(1), exportReader.GetValue(2))))
importCommand.ExecuteReader();
这是输出:
使用断点我确定导出 reader 调用正在接收数据。我已将其缩小为以下问题:
"VALUES ({0},{1},{2})",
exportReader.GetValue(0), exportReader.GetValue(1), exportReader.GetValue(2))))
我已确认可以通过执行以下操作插入数据:
using (OleDbCommand importCommand =
new OleDbCommand(string.Format(
"INSERT INTO CLIENT (Title,Fname,Sname)" + "VALUES (Mr,Joshua,Cameron-Mackintosh)",
importConnection)))
这不会导致任何问题,所以我知道问题不在于底层连接或命令。
插入语句不需要 ExecuteReader
。只需使用 ExecuteNonQuery
.
在你的例子中,如果你的列是字符类型的,你需要使用单引号;
VALUES ('{0}', '{1}', '{2}')
在 VALUES
部分之前也使用白色 space(不是必须,但作为一个好的做法)。
"INSERT INTO CLIENT (Title,Fname,Sname)" + " VALUES (Mr,Joshua,Cameron-Mackintosh)",
// ^^^ here
但更重要;
你应该总是使用 parameterized queries. Prepared statements automatically handle for escape characters for example and this kind of string concatenations are open for SQL Injection 攻击。
你必须给你的串联字符串 space。
"INSERT INTO CLIENT (Title,Fname,Sname)" + "[space here]VALUES (Mr,Joshua,Cameron-Mackintosh)"
然而,它应该是这样的:
"INSERT INTO CLIENT (Title,Fname,Sname) VALUES (?,?,?)"
始终使用参数化查询。请参阅:
http://blogs.technet.com/b/neilcar/archive/2008/05/21/sql-injection-mitigation-using-parameterized-queries.aspx
其他人对 SQL-Injection 的评论是正确的,但是 VFP 对 SQL-Injection 的影响较小,可能是一样的。主要原因是,VFP 并不像其他 sql 引擎通过“;”允许的那样真正处理多个查询。识别语句之间的中断。但是,如果引号不匹配,它可以并且将会破坏您的 sql-statements 实际上 运行.
话虽如此,VFP OleDb 提供程序确实允许参数化,但没有 "named" 参数。它用“?”来做作为 .net Framework 插入值的位置的占位符,并且您不必转换数据类型,只要它具有相同的预期格式(例如:字符串、数字、日期)
将您的 OleDbCommand 更改为
"INSERT INTO CLIENT (Title, Fname, Sname ) values ( ?, ?, ? )"
然后,通过
设置您的参数
importCommand.Parameters.Add( "parmForTitle", exportReader.GetValue(0));
importCommand.Parameters.Add( "parmForFName", exportReader.GetValue(1));
importCommand.Parameters.Add( "parmForSName", exportReader.GetValue(2));
此外,添加参数的顺序必须与它们在查询中出现的顺序完全相同。所以,我在它们前面加了前缀 "parmFor" 来表示它是相应字段被插入(或更新,或在 select 中使用,也插入或删除)的参数放置。命令对象对所有命令的作用相同。即使您编写了 select 语句并在 WHERE、JOIN 或任何其他位置具有值。
然后,ExecuteNonQuery()
- 那里说"foxpro connection string"。如果反对
VFP 数据库,那么 "Truncate table client" 将无法在
第一名。 VFP 中不存在该命令。相反,你可以
尝试使用 "Delete From Client" 来标记要删除的记录。
或者您可以将 "zap" 命令与 ExecSript 对应
"truncate table" 但是连接需要使用 table
独家.
- 您应该引用字符串值。更好的是,对于任何 SQL 操作,您都应该使用参数。当您使用参数时,您应该以正确的方式为您使用的连接执行此操作。这里你使用的是 OLEDB 连接,那么你应该使用 ?作为参数占位符。
您的代码的修订版本将是:
importConnection.Open();
Console.WriteLine("Foxpro connection open");
OleDbCommand deleteOleDbCommand = new OleDbCommand(@"Delete from CLIENT",
importConnection);
Console.WriteLine("writing to table");
Console.ReadKey();
using (OleDbCommand importCommand = new OleDbCommand(
@"INSERT INTO CLIENT (Title,Fname,Sname) VALUES (?,?,?)",
importConnection))
{
importCommand.Parameters.AddWithValue("title","");
importCommand.Parameters.AddWithValue("fname","");
importCommand.Parameters.AddWithValue("sname","");
// maybe in a loop here
importCommand.Parameters["title"].Value = exportReader.GetValue(0);
importCommand.Parameters["fname"].Value = exportReader.GetValue(1);
importCommand.Parameters["sname"].Value = exportReader.GetValue(2);
importCommand.ExecuteNonQuery();
// ...
}
PS:您可以直接在 Parameters.AddWithValue 上提供值,而不是创建一个单独的 .Parameters["..."].Value = ... 但那样你只会能够为单个插入做到这一点(与 VFP 无关,OleDb 或 Sql 或其他任何东西都是这种情况)。
我发布了我之前遇到的另一个问题,并在一些帮助下解决了这个问题。
我现在收到围绕以下代码的语法错误:
importConnection.Open();
Console.WriteLine("Foxpro connection open");
OleDbCommand deleteOleDbCommand = new OleDbCommand(@"TRUNCATE TABLE CLIENT",
importConnection);
Console.WriteLine("writing to table");
Console.ReadKey();
using (OleDbCommand importCommand = new OleDbCommand(
string.Format("INSERT INTO CLIENT (Title,Fname,Sname)" + "VALUES ({0},{1},{2})",
exportReader.GetValue(0), exportReader.GetValue(1), exportReader.GetValue(2))))
importCommand.ExecuteReader();
这是输出:
使用断点我确定导出 reader 调用正在接收数据。我已将其缩小为以下问题:
"VALUES ({0},{1},{2})",
exportReader.GetValue(0), exportReader.GetValue(1), exportReader.GetValue(2))))
我已确认可以通过执行以下操作插入数据:
using (OleDbCommand importCommand =
new OleDbCommand(string.Format(
"INSERT INTO CLIENT (Title,Fname,Sname)" + "VALUES (Mr,Joshua,Cameron-Mackintosh)",
importConnection)))
这不会导致任何问题,所以我知道问题不在于底层连接或命令。
插入语句不需要 ExecuteReader
。只需使用 ExecuteNonQuery
.
在你的例子中,如果你的列是字符类型的,你需要使用单引号;
VALUES ('{0}', '{1}', '{2}')
在 VALUES
部分之前也使用白色 space(不是必须,但作为一个好的做法)。
"INSERT INTO CLIENT (Title,Fname,Sname)" + " VALUES (Mr,Joshua,Cameron-Mackintosh)",
// ^^^ here
但更重要;
你应该总是使用 parameterized queries. Prepared statements automatically handle for escape characters for example and this kind of string concatenations are open for SQL Injection 攻击。
你必须给你的串联字符串 space。
"INSERT INTO CLIENT (Title,Fname,Sname)" + "[space here]VALUES (Mr,Joshua,Cameron-Mackintosh)"
然而,它应该是这样的:
"INSERT INTO CLIENT (Title,Fname,Sname) VALUES (?,?,?)"
始终使用参数化查询。请参阅: http://blogs.technet.com/b/neilcar/archive/2008/05/21/sql-injection-mitigation-using-parameterized-queries.aspx
其他人对 SQL-Injection 的评论是正确的,但是 VFP 对 SQL-Injection 的影响较小,可能是一样的。主要原因是,VFP 并不像其他 sql 引擎通过“;”允许的那样真正处理多个查询。识别语句之间的中断。但是,如果引号不匹配,它可以并且将会破坏您的 sql-statements 实际上 运行.
话虽如此,VFP OleDb 提供程序确实允许参数化,但没有 "named" 参数。它用“?”来做作为 .net Framework 插入值的位置的占位符,并且您不必转换数据类型,只要它具有相同的预期格式(例如:字符串、数字、日期)
将您的 OleDbCommand 更改为
"INSERT INTO CLIENT (Title, Fname, Sname ) values ( ?, ?, ? )"
然后,通过
设置您的参数importCommand.Parameters.Add( "parmForTitle", exportReader.GetValue(0));
importCommand.Parameters.Add( "parmForFName", exportReader.GetValue(1));
importCommand.Parameters.Add( "parmForSName", exportReader.GetValue(2));
此外,添加参数的顺序必须与它们在查询中出现的顺序完全相同。所以,我在它们前面加了前缀 "parmFor" 来表示它是相应字段被插入(或更新,或在 select 中使用,也插入或删除)的参数放置。命令对象对所有命令的作用相同。即使您编写了 select 语句并在 WHERE、JOIN 或任何其他位置具有值。
然后,ExecuteNonQuery()
- 那里说"foxpro connection string"。如果反对 VFP 数据库,那么 "Truncate table client" 将无法在 第一名。 VFP 中不存在该命令。相反,你可以 尝试使用 "Delete From Client" 来标记要删除的记录。 或者您可以将 "zap" 命令与 ExecSript 对应 "truncate table" 但是连接需要使用 table 独家.
- 您应该引用字符串值。更好的是,对于任何 SQL 操作,您都应该使用参数。当您使用参数时,您应该以正确的方式为您使用的连接执行此操作。这里你使用的是 OLEDB 连接,那么你应该使用 ?作为参数占位符。
您的代码的修订版本将是:
importConnection.Open();
Console.WriteLine("Foxpro connection open");
OleDbCommand deleteOleDbCommand = new OleDbCommand(@"Delete from CLIENT",
importConnection);
Console.WriteLine("writing to table");
Console.ReadKey();
using (OleDbCommand importCommand = new OleDbCommand(
@"INSERT INTO CLIENT (Title,Fname,Sname) VALUES (?,?,?)",
importConnection))
{
importCommand.Parameters.AddWithValue("title","");
importCommand.Parameters.AddWithValue("fname","");
importCommand.Parameters.AddWithValue("sname","");
// maybe in a loop here
importCommand.Parameters["title"].Value = exportReader.GetValue(0);
importCommand.Parameters["fname"].Value = exportReader.GetValue(1);
importCommand.Parameters["sname"].Value = exportReader.GetValue(2);
importCommand.ExecuteNonQuery();
// ...
}
PS:您可以直接在 Parameters.AddWithValue 上提供值,而不是创建一个单独的 .Parameters["..."].Value = ... 但那样你只会能够为单个插入做到这一点(与 VFP 无关,OleDb 或 Sql 或其他任何东西都是这种情况)。