代码之家  ›  专栏  ›  技术社区  ›  dummy

从SqlCommand对象获取生成的SQL语句?

  •  220
  • dummy  · 技术社区  · 16 年前

    我有以下代码:

    Using cmd As SqlCommand = Connection.CreateCommand
        cmd.CommandText = "UPDATE someTable SET Value = @Value"
        cmd.CommandText &= " WHERE Id = @Id"
        cmd.Parameters.AddWithValue("@Id", 1234)
        cmd.Parameters.AddWithValue("@Value", "myValue")
        cmd.ExecuteNonQuery
    End Using
    

    我想知道是否有任何方法可以将最终的SQL语句作为字符串获取,它应该看起来像这样:

    UPDATE someTable SET Value = "myValue" WHERE Id = 1234
    

    如果有人想知道我为什么要这样做:

    • 用于记录(失败的)语句
    • 因为有可能复制和;将其粘贴到Enterprise Manager以进行测试
    25 回复  |  直到 9 年前
        1
  •  140
  •   user3071284    6 年前

    出于日志记录的目的,恐怕没有更好的方法了,只能自己构造字符串:

    string query = cmd.CommandText;
    
    foreach (SqlParameter p in cmd.Parameters)
    {
        query = query.Replace(p.ParameterName, p.Value.ToString());
    }
    
        2
  •  123
  •   Hitesh Surani    6 年前

    虽然并不完美,但我为TSQL设计的东西可以很容易地调整为其他口味。..如果没有别的,它将为你自己的改进提供一个起点:)

    这在数据类型和输出参数等方面做得很好,类似于在Contoso中使用“执行存储过程”。我们主要使用SP,因此“text”命令不考虑参数等

        public static String ParameterValueForSQL(this SqlParameter sp)
        {
            String retval = "";
    
            switch (sp.SqlDbType)
            {
                case SqlDbType.Char:
                case SqlDbType.NChar:
                case SqlDbType.NText:
                case SqlDbType.NVarChar:
                case SqlDbType.Text:
                case SqlDbType.Time:
                case SqlDbType.VarChar:
                case SqlDbType.Xml:
                case SqlDbType.Date:
                case SqlDbType.DateTime:
                case SqlDbType.DateTime2:
                case SqlDbType.DateTimeOffset:
                    retval = "'" + sp.Value.ToString().Replace("'", "''") + "'";
                    break;
    
                case SqlDbType.Bit:
                    retval = (sp.Value.ToBooleanOrDefault(false)) ? "1" : "0";
                    break;
    
                default:
                    retval = sp.Value.ToString().Replace("'", "''");
                    break;
            }
    
            return retval;
        }
    
        public static String CommandAsSql(this SqlCommand sc)
        {
            StringBuilder sql = new StringBuilder();
            Boolean FirstParam = true;
    
            sql.AppendLine("use " + sc.Connection.Database + ";");
            switch (sc.CommandType)
            {
                case CommandType.StoredProcedure:
                    sql.AppendLine("declare @return_value int;");
    
                    foreach (SqlParameter sp in sc.Parameters)
                    {
                        if ((sp.Direction == ParameterDirection.InputOutput) || (sp.Direction == ParameterDirection.Output))
                        {
                            sql.Append("declare " + sp.ParameterName + "\t" + sp.SqlDbType.ToString() + "\t= ");
    
                            sql.AppendLine(((sp.Direction == ParameterDirection.Output) ? "null" : sp.ParameterValueForSQL()) + ";");
    
                        }
                    }
    
                    sql.AppendLine("exec [" + sc.CommandText + "]");
    
                    foreach (SqlParameter sp in sc.Parameters)
                    {
                        if (sp.Direction != ParameterDirection.ReturnValue)
                        {
                            sql.Append((FirstParam) ? "\t" : "\t, ");
    
                            if (FirstParam) FirstParam = false;
    
                            if (sp.Direction == ParameterDirection.Input)
                                sql.AppendLine(sp.ParameterName + " = " + sp.ParameterValueForSQL());
                            else
    
                                sql.AppendLine(sp.ParameterName + " = " + sp.ParameterName + " output");
                        }
                    }
                    sql.AppendLine(";");
    
                    sql.AppendLine("select 'Return Value' = convert(varchar, @return_value);");
    
                    foreach (SqlParameter sp in sc.Parameters)
                    {
                        if ((sp.Direction == ParameterDirection.InputOutput) || (sp.Direction == ParameterDirection.Output))
                        {
                            sql.AppendLine("select '" + sp.ParameterName + "' = convert(varchar, " + sp.ParameterName + ");");
                        }
                    }
                    break;
                case CommandType.Text:
                    sql.AppendLine(sc.CommandText);
                    break;
            }
    
            return sql.ToString();
        }
    

    这会沿着这些路线产生输出。..

    use dbMyDatabase;
    declare @return_value int;
    declare @OutTotalRows   BigInt  = null;
    exec [spMyStoredProc]
        @InEmployeeID = 1000686
        , @InPageSize = 20
        , @InPage = 1
        , @OutTotalRows = @OutTotalRows output
    ;
    select 'Return Value' = convert(varchar, @return_value);
    select '@OutTotalRows' = convert(varchar, @OutTotalRows);
    
        3
  •  52
  •   Tomalak    16 年前

    你不能,因为它不会生成任何SQL。

    参数化查询(中的查询 CommandText )作为准备好的语句发送到SQL Server。执行命令时,参数和查询文本将分别处理。在任何时候都不会生成完整的SQL字符串。

    您可以使用SQL Profiler查看幕后。

        4
  •  33
  •   Brian Mitch    4 年前

    我需要一个类似于字符串转换器的命令来允许更详细的日志记录,所以我写了这个。它将生成在新会话中重新执行命令所需的文本,包括输出参数和结构化参数。它经过了轻微的测试,但买者自负。

    例子:

    SqlCommand cmd = new SqlCommand("GetEntity", con);
    cmd.Parameters.AddWithValue("@foobar", 1);
    cmd.Parameters.Add(new SqlParameter(){
        ParameterName = "@outParam",
        Direction = ParameterDirection.Output,
        SqlDbType = System.Data.SqlDbType.Int
    });
    cmd.Parameters.Add(new SqlParameter(){
        Direction = ParameterDirection.ReturnValue
    });
    cmd.CommandType = CommandType.StoredProcedure;
    

    将生产:

    -- BEGIN COMMAND
    DECLARE @foobar INT = 1;
    DECLARE @outParam INT = NULL;
    DECLARE @returnValue INT;
    -- END PARAMS
    EXEC @returnValue = GetEntity @foobar = @foobar, @outParam = @outParam OUTPUT
    -- RESULTS
    SELECT 1 as Executed, @returnValue as ReturnValue, @outParam as [@outParam];
    -- END COMMAND
    

    实施:

    public class SqlCommandDumper
    {
        public static string GetCommandText(SqlCommand sqc)
        {
            StringBuilder sbCommandText = new StringBuilder();
    
            sbCommandText.AppendLine("-- BEGIN COMMAND");
    
            // params
            for (int i = 0; i < sqc.Parameters.Count; i++)
                logParameterToSqlBatch(sqc.Parameters[i], sbCommandText);
            sbCommandText.AppendLine("-- END PARAMS");
    
            // command
            if (sqc.CommandType == CommandType.StoredProcedure)
            {
                sbCommandText.Append("EXEC ");
    
                bool hasReturnValue = false;
                for (int i = 0; i < sqc.Parameters.Count; i++)
                {
                    if (sqc.Parameters[i].Direction == ParameterDirection.ReturnValue)
                        hasReturnValue = true;
                }
                if (hasReturnValue)
                {
                    sbCommandText.Append("@returnValue = ");
                }
    
                sbCommandText.Append(sqc.CommandText);
    
                bool hasPrev = false;
                for (int i = 0; i < sqc.Parameters.Count; i++)
                {
                    var cParam = sqc.Parameters[i];
                    if (cParam.Direction != ParameterDirection.ReturnValue)
                    {
                        if (hasPrev)
                            sbCommandText.Append(",");
                        sbCommandText.Append(" ");
    
                        sbCommandText.Append(cParam.ParameterName);
                        sbCommandText.Append(" = ");
                        sbCommandText.Append(cParam.ParameterName);
    
                        if (cParam.Direction.HasFlag(ParameterDirection.Output))
                            sbCommandText.Append(" OUTPUT");
    
                        hasPrev = true;
                    }
                }
            }
            else
            {
                sbCommandText.AppendLine(sqc.CommandText);
            }
    
            sbCommandText.AppendLine("-- RESULTS");
            sbCommandText.Append("SELECT 1 as Executed");
            for (int i = 0; i < sqc.Parameters.Count; i++)
            {
                var cParam = sqc.Parameters[i];
    
                if (cParam.Direction == ParameterDirection.ReturnValue)
                {
                    sbCommandText.Append(", @returnValue as ReturnValue");
                }
                else if (cParam.Direction.HasFlag(ParameterDirection.Output))
                {
                    sbCommandText.Append(", ");
                    sbCommandText.Append(cParam.ParameterName);
                    sbCommandText.Append(" as [");
                    sbCommandText.Append(cParam.ParameterName);
                    sbCommandText.Append(']');
                }
            }
            sbCommandText.AppendLine(";");
    
            sbCommandText.AppendLine("-- END COMMAND");
            return sbCommandText.ToString();
        }
    
        private static void logParameterToSqlBatch(SqlParameter param, StringBuilder sbCommandText)
        {
            sbCommandText.Append("DECLARE ");
            if (param.Direction == ParameterDirection.ReturnValue)
            {
                sbCommandText.AppendLine("@returnValue INT;");
            }
            else
            {
                sbCommandText.Append(param.ParameterName);
    
                sbCommandText.Append(' ');
                if (param.SqlDbType != SqlDbType.Structured)
                {
                    logParameterType(param, sbCommandText);
                    sbCommandText.Append(" = ");
                    logQuotedParameterValue(param.Value, sbCommandText);
    
                    sbCommandText.AppendLine(";");
                }
                else
                {
                    logStructuredParameter(param, sbCommandText);
                }
            }
        }
    
        private static void logStructuredParameter(SqlParameter param, StringBuilder sbCommandText)
        {
            sbCommandText.AppendLine(" {List Type};");
            var dataTable = (DataTable)param.Value;
    
            for (int rowNo = 0; rowNo < dataTable.Rows.Count; rowNo++)
            {
                sbCommandText.Append("INSERT INTO ");
                sbCommandText.Append(param.ParameterName);
                sbCommandText.Append(" VALUES (");
    
                bool hasPrev = false;
                for (int colNo = 0; colNo < dataTable.Columns.Count; colNo++)
                {
                    if (hasPrev)
                    {
                        sbCommandText.Append(", ");
                    }
                    logQuotedParameterValue(dataTable.Rows[rowNo].ItemArray[colNo], sbCommandText);
                    hasPrev = true;
                }
                sbCommandText.AppendLine(");");
            }
        }
    
        const string DATETIME_FORMAT_ROUNDTRIP = "o";
        private static void logQuotedParameterValue(object value, StringBuilder sbCommandText)
        {
            try
            {
                if (value == null)
                {
                    sbCommandText.Append("NULL");
                }
                else
                {
                    value = unboxNullable(value);
    
                    if (value is string
                        || value is char
                        || value is char[]
                        || value is System.Xml.Linq.XElement
                        || value is System.Xml.Linq.XDocument)
                    {
                        sbCommandText.Append("N'");
                        sbCommandText.Append(value.ToString().Replace("'", "''"));
                        sbCommandText.Append('\'');
                    }
                    else if (value is bool)
                    {
                        // True -> 1, False -> 0
                        sbCommandText.Append(Convert.ToInt32(value));
                    }
                    else if (value is sbyte
                        || value is byte
                        || value is short
                        || value is ushort
                        || value is int
                        || value is uint
                        || value is long
                        || value is ulong
                        || value is float
                        || value is double
                        || value is decimal)
                    {
                        sbCommandText.Append(value.ToString());
                    }
                    else if (value is DateTime)
                    {
                        // SQL Server only supports ISO8601 with 3 digit precision on datetime,
                        // datetime2 (>= SQL Server 2008) parses the .net format, and will 
                        // implicitly cast down to datetime.
                        // Alternatively, use the format string "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK"
                        // to match SQL server parsing
                        sbCommandText.Append("CAST('");
                        sbCommandText.Append(((DateTime)value).ToString(DATETIME_FORMAT_ROUNDTRIP));
                        sbCommandText.Append("' as datetime2)");
                    }
                    else if (value is DateTimeOffset)
                    {
                        sbCommandText.Append('\'');
                        sbCommandText.Append(((DateTimeOffset)value).ToString(DATETIME_FORMAT_ROUNDTRIP));
                        sbCommandText.Append('\'');
                    }
                    else if (value is Guid)
                    {
                        sbCommandText.Append('\'');
                        sbCommandText.Append(((Guid)value).ToString());
                        sbCommandText.Append('\'');
                    }
                    else if (value is byte[])
                    {
                        var data = (byte[])value;
                        if (data.Length == 0)
                        {
                            sbCommandText.Append("NULL");
                        }
                        else
                        {
                            sbCommandText.Append("0x");
                            for (int i = 0; i < data.Length; i++)
                            {
                                sbCommandText.Append(data[i].ToString("x"));
                            }
                        }
                    }
                    else
                    {
                        sbCommandText.Append("/* UNKNOWN DATATYPE: ");
                        sbCommandText.Append(value.GetType().ToString());
                        sbCommandText.Append(" *" + "/ N'");
                        sbCommandText.Append(value.ToString());
                        sbCommandText.Append('\'');
                    }
                }
            }
    
            catch (Exception ex)
            {
                sbCommandText.AppendLine("/* Exception occurred while converting parameter: ");
                sbCommandText.AppendLine(ex.ToString());
                sbCommandText.AppendLine("*/");
            }
        }
    
        private static object unboxNullable(object value)
        {
            var typeOriginal = value.GetType();
            if (typeOriginal.IsGenericType
                && typeOriginal.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                // generic value, unboxing needed
                return typeOriginal.InvokeMember("GetValueOrDefault",
                    System.Reflection.BindingFlags.Public |
                    System.Reflection.BindingFlags.Instance |
                    System.Reflection.BindingFlags.InvokeMethod,
                    null, value, null);
            }
            else
            {
                return value;
            }
        }
    
        private static void logParameterType(SqlParameter param, StringBuilder sbCommandText)
        {
            switch (param.SqlDbType)
            {
                // variable length
                case SqlDbType.Char:
                case SqlDbType.NChar:
                case SqlDbType.Binary:
                    {
                        sbCommandText.Append(param.SqlDbType.ToString().ToUpper());
                        sbCommandText.Append('(');
                        sbCommandText.Append(param.Size);
                        sbCommandText.Append(')');
                    }
                    break;
                case SqlDbType.VarBinary:
                case SqlDbType.Image:
                        {
                                sbCommandText.Append("VARBINARY");
                                sbCommandText.Append("(MAX /* Specified as ");
                                sbCommandText.Append(param.Size);
                                sbCommandText.Append(" */)");
                        }
                        break;
                case SqlDbType.VarChar:
                case SqlDbType.Text:
                        {
                                sbCommandText.Append("VARCHAR");
                                sbCommandText.Append("(MAX /* Specified as ");
                                sbCommandText.Append(param.Size);
                                sbCommandText.Append(" */)");
                        }
                        break;
                case SqlDbType.NVarChar:
                case SqlDbType.NText:
                        {
                                sbCommandText.Append("NVARCHAR");
                                sbCommandText.Append("(MAX /* Specified as ");
                                sbCommandText.Append(param.Size);
                                sbCommandText.Append(" */)");
                        }
                        break;
                // fixed length
                case SqlDbType.Bit:
                case SqlDbType.TinyInt:
                case SqlDbType.SmallInt:
                case SqlDbType.Int:
                case SqlDbType.BigInt:
                case SqlDbType.SmallMoney:
                case SqlDbType.Money:
                case SqlDbType.Decimal:
                case SqlDbType.Real:
                case SqlDbType.Float:
                case SqlDbType.Date:
                case SqlDbType.DateTime:
                case SqlDbType.DateTime2:
                case SqlDbType.DateTimeOffset:
                case SqlDbType.UniqueIdentifier:
                    {
                        sbCommandText.Append(param.SqlDbType.ToString().ToUpper());
                    }
                    break;
                // Unknown
                case SqlDbType.Timestamp:
                default:
                    {
                        sbCommandText.Append("/* UNKNOWN DATATYPE: ");
                        sbCommandText.Append(param.SqlDbType.ToString().ToUpper());
                        sbCommandText.Append(" *" + "/ ");
                        sbCommandText.Append(param.SqlDbType.ToString().ToUpper());
                    }
                    break;
            }
        }
    }
    
        5
  •  6
  •   Jeroen Pot    10 年前

    我也遇到过这样的问题,一些参数化查询或sp会给我一个SqlException(主要是字符串或二进制数据会被截断),语句也很难调试(据我所知,目前sql Azure没有sql分析器支持)

    我在这里的反应中看到了很多模拟代码。我最终将我的解决方案放入Sql库项目中以供将来使用。

    发电机可在此处获得: https://github.com/jeroenpot/SqlHelper/blob/master/Source/Mirabeau.MsSql.Library/SqlGenerator.cs

    它同时支持CommandType。文本和命令类型。存储程序

    如果你安装 nuget-package 您可以使用以下语句生成它:

    SqlDebugHelper.CreateExecutableSqlStatement(sql, parameters);
    
        6
  •  5
  •   Rockcoder    16 年前

    如果你使用的是SQL Server,你可以使用SQL Server Profiler(如果你有)来查看实际执行的命令字符串。这对于复制/粘贴测试目的很有用,但恐怕不适用于日志记录。

        7
  •  4
  •   Paul Sturm    6 年前

    回答晚了,我知道,但我也想要这个,这样我就可以记录SQL了。以下内容简短,符合我的需求。

    以下生成的SQL可以在Contoso中复制/粘贴(它将参数正确地替换为值)。您可以添加更多类型,但这符合我在本例中使用的所有类型。

        private static void LogSQL(SqlCommand cmd)
            {
                string query = cmd.CommandText;
    
                foreach (SqlParameter prm in cmd.Parameters)
                {
                    switch (prm.SqlDbType)
                    {
                        case SqlDbType.Bit:
                            int boolToInt = (bool)prm.Value ? 1 : 0;
                            query = query.Replace(prm.ParameterName, string.Format("{0}", (bool)prm.Value ? 1 : 0));
                            break;
                        case SqlDbType.Int:
                            query = query.Replace(prm.ParameterName, string.Format("{0}", prm.Value));
                            break;
                        case SqlDbType.VarChar:
                            query = query.Replace(prm.ParameterName, string.Format("'{0}'", prm.Value));
                            break;
                        default:
                            query = query.Replace(prm.ParameterName, string.Format("'{0}'", prm.Value));
                            break;
                    }
                }
    
                // the following is my how I write to my log - your use will vary
                logger.Debug("{0}", query);
    
                return;
            }
    

    现在,我可以在执行SQL之前记录它:

    LogSQL(queryCmd)
    queryCmd.ExecuteNonQuery()
    
        8
  •  2
  •   Ed Guiness    16 年前

    Profiler无疑是您的最佳选择。

    由于涉及准备+执行步骤,您可能需要从分析器中复制一组语句。

        9
  •  2
  •   alan    11 年前

    我也有同样的问题,在阅读了这些回复后,我错误地认为不可能得到确切的查询结果。我错了。

    解决方案: 打开 Activity Monitor 在……里面 SQL Server Management Studio ,将processs部分缩小到连接字符串中应用程序正在使用的登录用户名、数据库或应用程序名称 活动监视器 。当你看到这个过程时,右键单击它,然后 View Details .

    请注意,对于繁忙的数据库来说,这可能不是一个可行的选择。但是,使用这些步骤,您应该能够大大缩小结果范围。

        10
  •  2
  •   Community CDub    8 年前

    使用过的部分 Flapper's code 对于我的解决方案,它返回整个SQL字符串,包括要在MS SQL SMS中运行的参数值。

    public string ParameterValueForSQL(SqlParameter sp)
        {
            string retval = "";
    
            switch (sp.SqlDbType)
            {
                case SqlDbType.Char:
                case SqlDbType.NChar:
                case SqlDbType.NText:
                case SqlDbType.NVarChar:
                case SqlDbType.Text:
                case SqlDbType.Time:
                case SqlDbType.VarChar:
                case SqlDbType.Xml:
                case SqlDbType.Date:
                case SqlDbType.DateTime:
                case SqlDbType.DateTime2:
                case SqlDbType.DateTimeOffset:
                    if (sp.Value == DBNull.Value)
                    {
                        retval = "NULL";
                    }
                    else
                    {
                        retval = "'" + sp.Value.ToString().Replace("'", "''") + "'";
                    }
                    break;
    
                case SqlDbType.Bit:
                    if (sp.Value == DBNull.Value)
                    {
                        retval = "NULL";
                    }
                    else
                    {
                        retval = ((bool)sp.Value == false) ? "0" : "1";
                    }
                    break;
    
                default:
                    if (sp.Value == DBNull.Value)
                    {
                        retval = "NULL";
                    }
                    else
                    {
                        retval = sp.Value.ToString().Replace("'", "''");
                    }
                    break;
            }
    
            return retval;
        }
    
    
        public string CommandAsSql(SqlCommand sc)
        {
            string sql = sc.CommandText;
    
            sql = sql.Replace("\r\n", "").Replace("\r", "").Replace("\n", "");
            sql = System.Text.RegularExpressions.Regex.Replace(sql, @"\s+", " ");
    
            foreach (SqlParameter sp in sc.Parameters)
            {
                string spName = sp.ParameterName;
                string spValue = ParameterValueForSQL(sp);
                sql = sql.Replace(spName, spValue);
            }
    
            sql = sql.Replace("= NULL", "IS NULL");
            sql = sql.Replace("!= NULL", "IS NOT NULL");
            return sql;
        }
    
        11
  •  2
  •   Arithmomaniac    8 年前

    我的解决方案:

    public static class DbHelper
    {
        public static string ToString(this DbParameterCollection parameters, string sqlQuery)
        {
            return parameters.Cast<DbParameter>().Aggregate(sqlQuery, (current, p) => current.Replace(p.ParameterName, p.Value.ToString()));
        }
    }
    
        12
  •  2
  •   Daghan Karakasoglu    8 年前

    我为自己写了这个方法。我使用了 Bruno Ratnieks's 代码。也许它对某人有用。

     public static string getQueryFromCommand(SqlCommand cmd)
        {
            StringBuilder CommandTxt = new StringBuilder();
            CommandTxt.Append("DECLARE ");
            List<string> paramlst = new List<string>();
            foreach (SqlParameter parms in cmd.Parameters)
            {
                paramlst.Add(parms.ParameterName);
                CommandTxt.Append(parms.ParameterName + " AS ");
                CommandTxt.Append(parms.SqlDbType.ToString());
                CommandTxt.Append(",");
            }
    
            if (CommandTxt.ToString().Substring(CommandTxt.Length-1, 1) == ",")
                CommandTxt.Remove(CommandTxt.Length-1, 1);
            CommandTxt.AppendLine();
            int rownr = 0;
            foreach (SqlParameter parms in cmd.Parameters)
            {
                string val = String.Empty;
                if (parms.DbType.Equals(DbType.String) || parms.DbType.Equals(DbType.DateTime))
                    val = "'" + Convert.ToString(parms.Value).Replace(@"\", @"\\").Replace("'", @"\'") + "'";
                if (parms.DbType.Equals(DbType.Int16) || parms.DbType.Equals(DbType.Int32) || parms.DbType.Equals(DbType.Int64) || parms.DbType.Equals(DbType.Decimal) || parms.DbType.Equals(DbType.Double))
                    val = Convert.ToString(parms.Value);
    
                CommandTxt.AppendLine();
                CommandTxt.Append("SET " + paramlst[rownr].ToString() + " = " + val.ToString());
                rownr += 1;
            }
            CommandTxt.AppendLine();
            CommandTxt.AppendLine();
            CommandTxt.Append(cmd.CommandText);
            return CommandTxt.ToString();
        }
    
        13
  •  1
  •   MPelletier    11 年前

    如果您的数据库是Oracle,并且sql文本包含名为的动态变量 :1,:2 ,... 然后您可以使用:

    string query = cmd.CommandText;
    int i = 1;
    foreach (OracleParameter p in cmd.Parameters)
      {
        query = query.Replace(":"+i.ToString(),((p.Value==null)?"":p.Value.ToString()));
        i++;
      }
    
        14
  •  1
  •   Shawn J. Molloy    10 年前

    如果只是检查参数在结果查询中的格式,大多数DBMS将允许从无查询文字。因此:

    Using cmd As SqlCommand = Connection.CreateCommand
        cmd.CommandText = "SELECT @Value"
        cmd.Parameters.AddWithValue("@Value", "myValue")
        Return cmd.ExecuteScalar
    End Using
    

    这样你就可以看到报价是否加倍等。

        15
  •  1
  •   spottedmahn    6 年前

    这是我用来将存储过程的参数列表输出到调试控制台的方法:

    string query = (from SqlParameter p in sqlCmd.Parameters where p != null where p.Value != null select string.Format("Param: {0} = {1},  ", p.ParameterName, p.Value.ToString())).Aggregate(sqlCmd.CommandText, (current, parameter) => current + parameter);
    Debug.WriteLine(query);
    

    这将生成一个与此类似的控制台输出:

    Customer.prGetCustomerDetails: @Offset = 1,  Param: @Fetch = 10,  Param: @CategoryLevel1ID = 3,  Param: @VehicleLineID = 9,  Param: @SalesCode1 = bce,  
    

    我将此代码直接放置在我要调试的任何过程的下方,它类似于sql分析器会话,但使用C#。

        16
  •  1
  •   Seyed Hossein Mirheydari    4 年前

    修改版本 Kon's answer 因为它只能部分地使用类似命名的参数。使用String Replace函数的缺点。除此之外,我完全相信他的解决方案。

    private string GetActualQuery(SqlCommand sqlcmd)
    {
        string query = sqlcmd.CommandText;
        string parameters = "";
        string[] strArray = System.Text.RegularExpressions.Regex.Split(query, " VALUES ");
    
        //Reconstructs the second half of the SQL Command
        parameters = "(";
    
        int count = 0;
        foreach (SqlParameter p in sqlcmd.Parameters)
        {
            if (count == (sqlcmd.Parameters.Count - 1))
            {
                parameters += p.Value.ToString();
            }
            else
            {
                parameters += p.Value.ToString() + ", ";
            }
            count++;
        }
    
        parameters += ")";
    
        //Returns the string recombined.
        return strArray[0] + " VALUES " + parameters;
    }
    
        17
  •  0
  •   dummy    14 年前

    这个解决方案现在对我很有效。也许它对某人有用。请原谅所有的裁员。

        Public Shared Function SqlString(ByVal cmd As SqlCommand) As String
        Dim sbRetVal As New System.Text.StringBuilder()
        For Each item As SqlParameter In cmd.Parameters
            Select Case item.DbType
                Case DbType.String
                    sbRetVal.AppendFormat("DECLARE {0} AS VARCHAR(255)", item.ParameterName)
                    sbRetVal.AppendLine()
                    sbRetVal.AppendFormat("SET {0} = '{1}'", item.ParameterName, item.Value)
                    sbRetVal.AppendLine()
    
                Case DbType.DateTime
                    sbRetVal.AppendFormat("DECLARE {0} AS DATETIME", item.ParameterName)
                    sbRetVal.AppendLine()
                    sbRetVal.AppendFormat("SET {0} = '{1}'", item.ParameterName, item.Value)
                    sbRetVal.AppendLine()
    
                Case DbType.Guid
                    sbRetVal.AppendFormat("DECLARE {0} AS UNIQUEIDENTIFIER", item.ParameterName)
                    sbRetVal.AppendLine()
                    sbRetVal.AppendFormat("SET {0} = '{1}'", item.ParameterName, item.Value)
                    sbRetVal.AppendLine()
    
                Case DbType.Int32
                    sbRetVal.AppendFormat("DECLARE {0} AS int", item.ParameterName)
                    sbRetVal.AppendLine()
                    sbRetVal.AppendFormat("SET {0} = {1}", item.ParameterName, item.Value)
                    sbRetVal.AppendLine()
    
                Case Else
                    Stop
    
            End Select
        Next
    
        sbRetVal.AppendLine("")
        sbRetVal.AppendLine(cmd.CommandText)
    
        Return sbRetVal.ToString()
    End Function
    
        18
  •  0
  •   JotaSantana    10 年前

    正如@pkExec和@Alok所提到的,使用替换在100%的情况下都不起作用。 这是我在DAL中使用的解决方案,它使用RegExp仅“匹配整个单词”并正确格式化数据类型。因此,生成的SQL可以直接在MySQL Workbench(或SQLSMS等)中进行测试:)

    (根据使用的DBMS替换MySQLHelper.EscapeString()函数。)

    Dim query As String = cmd.CommandText
    query = query.Replace("SET", "SET" & vbNewLine)
    query = query.Replace("WHERE", vbNewLine & "WHERE")
    query = query.Replace("GROUP BY", vbNewLine & "GROUP BY")
    query = query.Replace("ORDER BY", vbNewLine & "ORDER BY")
    query = query.Replace("INNER JOIN", vbNewLine & "INNER JOIN")
    query = query.Replace("LEFT JOIN", vbNewLine & "LEFT JOIN")
    query = query.Replace("RIGHT JOIN", vbNewLine & "RIGHT JOIN")
    If query.Contains("UNION ALL") Then
        query = query.Replace("UNION ALL", vbNewLine & "UNION ALL" & vbNewLine)
    ElseIf query.Contains("UNION DISTINCT") Then
        query = query.Replace("UNION DISTINCT", vbNewLine & "UNION DISTINCT" & vbNewLine)
    Else
        query = query.Replace("UNION", vbNewLine & "UNION" & vbNewLine)
    End If
    
    For Each par In cmd.Parameters
        If par.Value Is Nothing OrElse IsDBNull(par.Value) Then
            query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", "NULL")
        ElseIf TypeOf par.Value Is Date Then
            query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", "'" & Format(par.Value, "yyyy-MM-dd HH:mm:ss") & "'")
        ElseIf TypeOf par.Value Is TimeSpan Then
            query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", "'" & par.Value.ToString & "'")
        ElseIf TypeOf par.Value Is Double Or TypeOf par.Value Is Decimal Or TypeOf par.Value Is Single Then
            query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", Replace(par.Value.ToString, ",", "."))
        ElseIf TypeOf par.Value Is Integer Or TypeOf par.Value Is UInteger Or TypeOf par.Value Is Long Or TypeOf par.Value Is ULong Then
            query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", par.Value.ToString)
        Else
            query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", "'" & MySqlHelper.EscapeString(CStr(par.Value)) & "'")
        End If
    Next
    

    例子:

    SELECT * FROM order WHERE order_status = @order_status AND order_date = @order_date
    

    将生成:

    SELECT * FROM order WHERE order_status = 'C' AND order_date = '2015-01-01 00:00:00'
    
        19
  •  0
  •   o_link    8 年前

    sql命令查询将使用exec sp_executesql执行,因此这里有另一种将语句作为字符串获取的方法(SqlCommand扩展方法):

    public static string ToSqlStatement(this SqlCommand cmd)
    {
        return $@"EXECUTE sp_executesql N'{cmd.CommandText.Replace("'", "''")}'{cmd.Parameters.ToSqlParameters()}";
    }
    
    private static string ToSqlParameters(this SqlParameterCollection col)
    {
        if (col.Count == 0)
            return string.Empty;
        var parameters = new List<string>();
        var parameterValues = new List<string>();
        foreach (SqlParameter param in col)
        {
            parameters.Add($"{param.ParameterName}{param.ToSqlParameterType()}");
            parameterValues.Add($"{param.ParameterName} = {param.ToSqlParameterValue()}");
        }
        return $",N\'{string.Join(",", parameters)}\',{string.Join(",", parameterValues)}";
    }
    
    private static object ToSqlParameterType(this SqlParameter param)
    {
        var paramDbType = param.SqlDbType.ToString().ToLower();
        if (param.Precision != 0 && param.Scale != 0)
            return $"{paramDbType}({param.Precision},{param.Scale})";
        if (param.Precision != 0)
            return $"{paramDbType}({param.Precision})";
        switch (param.SqlDbType)
        {
            case SqlDbType.VarChar:
            case SqlDbType.NVarChar:
                string s = param.SqlValue?.ToString() ?? string.Empty;
                return paramDbType + (s.Length > 0 ? $"({s.Length})" : string.Empty);
            default:
                return paramDbType;
        }
    }
    
    private static string ToSqlParameterValue(this SqlParameter param)
    {
        switch (param.SqlDbType)
        {
            case SqlDbType.Char:
            case SqlDbType.Date:
            case SqlDbType.DateTime:
            case SqlDbType.DateTime2:
            case SqlDbType.DateTimeOffset:
            case SqlDbType.NChar:
            case SqlDbType.NText:
            case SqlDbType.NVarChar:
            case SqlDbType.Text:
            case SqlDbType.Time:
            case SqlDbType.VarChar:
            case SqlDbType.Xml:
                return $"\'{param.SqlValue.ToString().Replace("'", "''")}\'";
            case SqlDbType.Bit:
                return param.SqlValue.ToBooleanOrDefault() ? "1" : "0";
            default:
                return param.SqlValue.ToString().Replace("'", "''");
        }
    }
    
    public static bool ToBooleanOrDefault(this object o, bool defaultValue = false)
    {
        if (o == null)
            return defaultValue;
        string value = o.ToString().ToLower();
        switch (value)
        {
            case "yes":
            case "true":
            case "ok":
            case "y":
                return true;
            case "no":
            case "false":
            case "n":
                return false;
            default:
                bool b;
                if (bool.TryParse(o.ToString(), out b))
                    return b;
                break;
        }
        return defaultValue;
    }
    
        20
  •  0
  •   George Birbilis    7 年前

    也需要涵盖非存储过程,所以我用以下逻辑增强了CommandAsSql库(见上面@Flapper答案下的注释):

        private static void CommandAsSql_Text(this SqlCommand command, System.Text.StringBuilder sql)
        {
            string query = command.CommandText;
    
            foreach (SqlParameter p in command.Parameters)
                query = Regex.Replace(query, "\\B" + p.ParameterName + "\\b", p.ParameterValueForSQL()); //the first one is \B, the 2nd one is \b, since ParameterName starts with @ which is a non-word character in RegEx (see https://stackoverflow.com/a/2544661)
    
            sql.AppendLine(query);
        }
    

    拉取请求位于: https://github.com/jphellemons/CommandAsSql/pull/3/commits/527d696dc6055c5bcf858b9700b83dc863f04896

    Regex的想法基于@stambikk和EvZ的上述评论以及 https://stackoverflow.com/a/2544661/903783 这提到了“消极的回头看断言”。在正则表达式的开头使用\B而不是\B进行单词边界检测是因为p.parameterName将始终以“@”开头,而“@”不是单词字符。

    请注意,ParameterValueForSQL()是CommandAsSql库中定义的一个扩展方法,用于处理单引号字符串参数值等问题。

        21
  •  0
  •   user11982798    6 年前

    如果要转换命令文本:

    Private Function ConvToNonParm(ByRef Cmd As SqlClient.SqlCommand) As String
        For myCnt As Int16 = 1 To Cmd.Parameters.Count
            Dim myVal As String = Cmd.Parameters(myCnt - 1).Value
            Select Case Cmd.Parameters(myCnt - 1).SqlDbType
                Case SqlDbType.Char, SqlDbType.NChar, SqlDbType.VarChar, SqlDbType.NChar, SqlDbType.NVarChar 'and so on
                    myVal = "'" & myVal & "'"
                    'Case "others...."
    
                Case Else
                    'please assing
            End Select
            Cmd.CommandText = Replace(Cmd.CommandText, Cmd.Parameters(myCnt - 1).ToString, myVal)
        Next
        Cmd.Parameters.Clear()
        Return Cmd.CommandText
    End Function
    

    现在,您可以按如下方式获取非参数命令文本:

        myCmd.CommandText = "UPDATE someTable SET Value = @Value"
        myCmd.CommandText &= " WHERE Id = @Id"
        myCmd.Parameters.AddWithValue("@Id", 1234)
        myCmd.Parameters.AddWithValue("@Value", "myValue")
    
        myCmd.CommandText = ConvToNonParm(myCmd)
    

    结果是“UPDATE someTable SET Value='myValue'WHERE Id=1234”,不再带参数

        22
  •  0
  •   CAK2    5 年前

    扩展了的 Kon's code 要帮助调试存储过程,请执行以下操作:

        private void ExtractSqlCommandForDebugging(SqlCommand cmd)
        {
            string sql = "exec " + cmd.CommandText;
            bool first = true;
            foreach (SqlParameter p in cmd.Parameters)
            {
                string value = ((p.Value == DBNull.Value) ? "null"
                                : (p.Value is string) ? "'" + p.Value + "'"
                                : p.Value.ToString());
                if (first)
                {
                    sql += string.Format(" {0}={1}", p.ParameterName, value);
                    first = false;
                }
                else
                {
                    sql += string.Format("\n , {0}={1}", p.ParameterName, value);
                }
            }
            sql += "\nGO";
            Debug.WriteLine(sql);
        }
    

    在我的第一个测试用例中,它生成了:

    exec dbo.MyStoredProcName @SnailMail=False
     , @Email=True
     , @AcceptSnailMail=False
     , @AcceptEmail=False
     , @DistanceMiles=-1
     , @DistanceLocationList=''
     , @ExcludeDissatisfied=True
     , @ExcludeCodeRed=True
     , @MinAge=null
     , @MaxAge=18
     , @GenderTypeID=-1
     , @NewThisYear=-1
     , @RegisteredThisYear=-1
     , @FormersTermGroupList=''
     , @RegistrationStartDate=null
     , @RegistrationEndDate=null
     , @DivisionList='25'
     , @LocationList='29,30'
     , @OneOnOneOPL=-1
     , @JumpStart=-1
     , @SmallGroup=-1
     , @PurchasedEAP=-1
     , @RedeemedEAP=-1
     , @ReturnPlanYes=False
     , @MinNetPromoter=-1
     , @MinSurveyScore=-1
     , @VIPExclusionTypes='-2'
     , @FieldSelectionMask=65011584
     , @DisplayType=0
    GO
    

    您可能需要添加一些更有条件的“..is…”类型的作业,例如日期和时间。

        23
  •  -1
  •   CheesusCrust    8 年前
    //For Oracle db in the sql text the parameters could be like :ID,:NAME etc.
    //This is same as above Seyed Hossein Mirheydari, but slightly improved, 
    //this works with parameter names well.
    //Further is straight simple one, you need to format for datatypes 
    //after query is generated.
        private string GetFullOraQuery(OracleCommand cmd)
        {
            string query = cmd.CommandText;
            foreach (OracleParameter p in cmd.Parameters)
            {
                query = query.Replace(":" + p.ParameterName, ((p.Value == null) ? "" : p.Value.ToString()));
            }
            return query;
        }
    
        24
  •  -2
  •   user11982798    6 年前

    一个衬垫:

    string.Join(",", from SqlParameter p in cmd.Parameters select p.ToString())