我有以下代码:

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

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

用于记录(失败的)语句 可以将其复制粘贴到企业管理器中进行测试


当前回答

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

解决方案: 在SQL Server Management Studio中打开活动监视器,将进程部分缩小为应用程序在连接字符串中使用的登录用户名、数据库或应用程序名称。当调用db刷新活动监视器时。当您看到流程时,右键单击它并查看详细信息。

注意,对于繁忙的db来说,这可能不是一个可行的选项。但是您应该能够使用这些步骤大大缩小结果。

其他回答

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

我的解决方案:

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()));
    }
}

也需要覆盖非存储过程,所以我用以下逻辑扩充了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);
    }

pull请求在: https://github.com/jphellemons/CommandAsSql/pull/3/commits/527d696dc6055c5bcf858b9700b83dc863f04896

Regex的想法是基于@stambikk和EvZ上面的评论,以及https://stackoverflow.com/a/2544661/903783的“更新:”部分提到了“消极的事后判断”。在正则表达式的开头使用\B而不是\B来进行单词边界检测是因为p.parameterName总是以“@”开头,而“@”不是单词字符。

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

//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;
    }

如果你要转换命令文本:

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

现在你可以像下面这样获得非参数commandtext:

    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)

结果是“更新someTable SET值= 'myValue' WHERE Id = 1234”,不再带参数