问题描述
|
我做了一些搜索,但没有找到关于我的问题的明确答案。
有没有一种方法可以定义SQL查询中的哪个“ 0”属于哪个参数?
例如,我需要执行以下操作:
SELECT * FROM myTable WHERE myField = @Param1 OR myField2 = @Param1
OR myField1 = @Param2 OR myField2 = @Param2
ODBC
中的相同查询是:
SELECT * FROM myTable WHERE myField = ? or myField2 = ? or myField1 = ?
or myField2 = ?
除了为每个值两次加载参数外,是否有办法告诉ODBC命令哪个参数是哪个参数?
我怀疑没有,但是可以使用更有经验的ODBC程序员的观点。
编辑:我正在使用的ODBC驱动程序是BBj ODBC驱动程序。
解决方法
在MSDN中,明确声明不能命名参数,这是“告诉ODBC命令哪个参数是哪个”的唯一方法。
尽管文档可能会引起一些混乱:
从MSDN的OdbcParameter类:
当CommandType设置为Text时,用于ODBC的.NET Framework数据提供程序不支持将命名参数传递给SQL语句或OdbcCommand调用的存储过程。在这两种情况下,均使用问号(?)占位符。
将OdbcParameter对象添加到OdbcParameterCollection的顺序必须直接对应于命令文本中参数的问号占位符的位置。
从上面看来,似乎暗示当CommandType未设置为Text时,您可以使用命名参数,但是不幸的是,您不能:
从MSDN的OdbcCommand.CommandType属性:
当CommandType属性设置为StoredProcedure时,应将CommandText属性设置为完整的ODBC调用语法。然后,当您调用Execute方法之一(例如ExecuteReader或ExecuteNonQuery)时,命令将执行此存储过程。
用于ODBC的.NET Framework数据提供程序不支持将命名参数传递给SQL语句或OdbcCommand调用的存储过程。在这两种情况下,均使用问号(?)占位符...
, 谢谢汤姆的创意和代码。
但是,代码在我的测试中无法正常工作。
因此,我写了一个简单的解决方案(至少在我的测试中),用位置参数(其中使用?代替名称)替换了命名参数:
public static class OdbcCommandExtensions
{
public static void ConvertNamedParametersToPositionalParameters(this OdbcCommand command)
{
//1. Find all occurrences parameters references in the SQL statement (such as @MyParameter).
//2. Find the corresponding parameter in the command\'s parameters list.
//3. Add the found parameter to the newParameters list and replace the parameter reference in the SQL with a question mark (?).
//4. Replace the command\'s parameters list with the newParameters list.
var newParameters = new List<OdbcParameter>();
command.CommandText = Regex.Replace(command.CommandText,\"(@\\\\w*)\",match =>
{
var parameter = command.Parameters.OfType<OdbcParameter>().FirstOrDefault(a => a.ParameterName == match.Groups[1].Value);
if (parameter != null)
{
var parameterIndex = newParameters.Count;
var newParameter = command.CreateParameter();
newParameter.OdbcType = parameter.OdbcType;
newParameter.ParameterName = \"@parameter\" + parameterIndex.ToString();
newParameter.Value = parameter.Value;
newParameters.Add(newParameter);
}
return \"?\";
});
command.Parameters.Clear();
command.Parameters.AddRange(newParameters.ToArray());
}
}
, 我无法使用命名参数-仅使用位置参数。
您可以像下面一样添加所需的所有参数,但是必须按顺序添加值。
SELECT * FROM myTable WHERE myField = ? or myField1 = ? or myField2 = ?
or myField2 = ?
myOdbcCommand.Parameters.AddWithValue(\"DoesNotMatter\",val1); //myField
myOdbcCommand.Parameters.AddWithValue(\"WhatYouPutHere\",val2); //myField1
myOdbcCommand.Parameters.AddWithValue(\"DoesNotMatter\",val3); //myField2
myOdbcCommand.Parameters.AddWithValue(\"WhatYouPutHere\",val4); //myField2
从上面可以看到,参数名称无关紧要,也没有使用。如果需要,甚至可以用相同的名称命名,请将参数名称留空empty6ѭ。
, 我知道使用Oracle Rdb ODBC时,不能使用占位符名称,而必须使用\'?\';。我觉得这很烦人。
, 我需要编写代码来处理将带问号的命名参数转换为序数参数的过程。我需要的是OleDb而不是Odbc…,但是我敢肯定,如果您更改类型,它将对您有用。
using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.Linq;
using System.Text.RegularExpressions;
namespace OleDbParameterFix {
static class Program {
[STAThread]
static void Main() {
string connectionString = @\"provider=vfpoledb;data source=data\\northwind.dbc\";
using (var connection = new OleDbConnection(connectionString))
using (var command = connection.CreateCommand()) {
command.CommandText = \"select count(*) from orders where orderdate=@date or requireddate=@date or shippeddate=@date\";
command.Parameters.Add(\"date\",new DateTime(1996,7,11));
connection.Open();
OleDbParameterRewritter.Rewrite(command);
var count = command.ExecuteScalar();
connection.Close();
}
}
}
public class OleDbParameterRewritter {
public static void Rewrite(OleDbCommand command) {
HandleMultipleParameterReferences(command);
ReplaceParameterNamesWithQuestionMark(command);
}
private static void HandleMultipleParameterReferences(OleDbCommand command) {
var parameterMatches = command.Parameters
.Cast<OleDbParameter>()
.Select(x => Regex.Matches(command.CommandText,\"@\" + x.ParameterName))
.ToList();
// Check to see if any of the parameters are listed multiple times in the command text.
if (parameterMatches.Any(x => x.Count > 1)) {
var newParameters = new List<OleDbParameter>();
// order by descending to make the parameter name replacing easy
var matches = parameterMatches.SelectMany(x => x.Cast<Match>())
.OrderByDescending(x => x.Index);
foreach (Match match in matches) {
// Substring removed the @ prefix.
var parameterName = match.Value.Substring(1);
// Add index to the name to make the parameter name unique.
var newParameterName = parameterName + \"_\" + match.Index;
var newParameter = (OleDbParameter)((ICloneable)command.Parameters[parameterName]).Clone();
newParameter.ParameterName = newParameterName;
newParameters.Add(newParameter);
// Replace the old parameter name with the new parameter name.
command.CommandText = command.CommandText.Substring(0,match.Index)
+ \"@\" + newParameterName
+ command.CommandText.Substring(match.Index + match.Length);
}
// The parameters were added to the list in the reverse order to make parameter name replacing easy.
newParameters.Reverse();
command.Parameters.Clear();
newParameters.ForEach(x => command.Parameters.Add(x));
}
}
private static void ReplaceParameterNamesWithQuestionMark(OleDbCommand command) {
for (int index = command.Parameters.Count - 1; index >= 0; index--) {
var p = command.Parameters[index];
command.CommandText = command.CommandText.Replace(\"@\" + p.ParameterName,\"?\");
}
}
}
}
, 这是该帖子的简短解决方案:https://stackoverflow.com/a/21925683/2935383
我已经为OpenEdge(Progress)ODBC包装器编写了此代码。 DatabaseAdapter-class是此包装器,此处不会显示。
string _convertSql( string queryString,List<DatabaseAdapter.Parameter> parameters,ref List<System.Data.Odbc.OdbcParameter> odbcParameters ) {
List<ParamSorter> sorter = new List<ParamSorter>();
foreach (DatabaseAdapter.Parameters item in parameters) {
string parameterName = item.ParameterName;
int indexSpace = queryString.IndexOf(paramName + \" \"); // 0
int indexComma = queryString.IndexOf(paramName + \",\"); // 1
if (indexSpace > -1){
sorter.Add(new ParamSorter() { p = item,index = indexSpace,type = 0 });
}
else {
sorter.Add(new ParamSorter() { p = item,index = indexComma,type = 1 });
}
}
odbcParameters = new List<System.Data.Odbc.OdbcParameter>();
foreach (ParamSorter item in sorter.OrderBy(x => x.index)) {
if (item.type == 0) { //SPACE
queryString = queryString.Replace(item.p.ParameterName + \" \",\"? \");
}
else { //COMMA
queryString = queryString.Replace(item.p.ParameterName + \",\",\"?,\");
}
odbcParameters.Add(
new System.Data.Odbc.OdbcParameter(item.p.ParameterName,item.p.Value));
}
}
实用程序分类
class ParamSorter{
public DatabaseAdapter.Parameters p;
public int index;
public int type;
}
如果命名参数是字符串中的最后一个-您必须添加一个空格。
例如\"SELECT * FROM tab WHERE col = @mycol\"
必须\"SELECT * FROM tab WHERE col = @mycol \"