ODBC参数占位符可以命名吗?

| 我做了一些搜索,但没有找到关于我的问题的明确答案。 有没有一种方法可以定义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 \"
    

要回复问题请先登录注册