在子查询中绕过顺序以获取记录查询次数

时间:2017-12-07 12:41:45

标签: c# sql sql-server

我有一个函数,它使用给定的commandtext执行一个datareader,并为读者返回的每个数据记录调用一个给定的动作。

由于datareader是一个只向前的阅读器,我无法从datareader获取行数。要调用进度条,我必须知道我的datareader将返回的记录数。

我目前的尝试是这样的:

protected void RunConversion(string commandText, Action<IDataRecord> actionConversion)
{
    try
    {
        var curIndex = 0;
        var maxIndex = this.Source.ExecuteScalar<int?>($"SELECT COUNT(*) FROM ({commandText}) AS QUERY"); //Here i try to get the count of rows from the result 

        OnProgress?.Invoke(0);

        foreach (var dataRecord in this.Source.ExecuteReader(commandText))
        {
            try
            {
                actionConversion?.Invoke(dataRecord);
            }
            catch (Exception e)
            {
                OnReport?.Invoke($"Error: {e}{Environment.NewLine}");
            }
            finally
            {
                OnProgress?.Invoke((int)((double)++curIndex / maxIndex * 100f));
            }
        }
    }
    catch (Exception e)
    {
        OnReport?.Invoke($"Fatal Error: {e}{Environment.NewLine}");
        OnProgress?.Invoke(100);
    }
}

问题是,有时commandText-Parameter包含一个查询,其中包含order by ...而不使用top by order by子查询中不允许。

另一种尝试是提供thrid参数,该参数是仅计算当前commandText-Parameter结果的查询。这不是一个好的解决方案,因为我必须编写两个查询,它们可能非常复杂。

想要一个简单的解决方案吗?

1 个答案:

答案 0 :(得分:0)

您提到您不能使用计数,因为您使用的是DataReader。您是否正在显示查询的进度条?如果是这样,我建议不要使用进度条,只需显示“等待”图标,而不是执行两次查询,并延长用户等待显示等待时间的时间。

考虑到这一点,您有两种选择。第一个是取消进度条和SELECT COUNT(*) FROM (...);,只是按原样传递查询。然后,当您执行它并获得结果集时,如果仍需要显示进度条以进行记录处理,则可以对记录进行计数。当然,如果您不打算使用实际数据,这会给您的操作增加数据传输开销的缺点,所以如果值得多花一点额外的债务,这取决于您。

您的第二个选择是通过执行以下操作简单地删除任何查询的ORDER BY部分:

public string RemoveOrderBy(string query)
{
    return query.SubString(0, query.IndexOf("ORDER BY"));
}

这将删除任何ORDER BY语句,但如果您在子查询中有任何其他可能无法解决的问题,则必须以与上述相同的方式对其进行说明。