SQL-запрос на ограничение ADO.net с параметрами 2100+ - PullRequest
0 голосов
/ 05 января 2019

Я пытаюсь реализовать код ADO.NET, который выполняет запрос SQL с несколькими параметрами. Похоже, предел параметра SQL равен 2100 и не принимает больше, чем этот предел. Как мне добиться с помощью приведенного ниже кода, чтобы принять это больше, чем ограничение.

Мне трудно понять реализации при проверке онлайновых статей, связанных с тем, как отправлять запросы в подмножествах или порциями для выполнения моего запроса.

Это мой код:

using (Connection = new SqlConnection(CS))
{
    Connection.Open();

    string query = "SELECT FamilyID, FullName, Alias FROM TABLE (nolock) WHERE FamilyID IN ({0})";

    var stringBuiler = new StringBuilder();
    var familyIds = new List<string>();

    string line;

    while ((line = TextFileReader.ReadLine()) != null)
    {
        line = line.Trim();

        if (!familyIds.Contains(line) & !string.IsNullOrEmpty(line))
        {
            familyIds.Add(line);
        }
    }

    var sqlCommand = new SqlCommand
    {
        Connection = Connection,
        CommandType = CommandType.Text
    };

    var index = 0; // Reset the index
    var idParameterList = new List<string>();

    foreach (var familyId in familyIds)
    {
        var paramName = "@familyId" + index;
        sqlCommand.Parameters.AddWithValue(paramName, familyId);
        idParameterList.Add(paramName);
        index++;
    }

    sqlCommand.CommandText = String.Format(query, string.Join(",", idParameterList));

    var dt = new DataTable();

    using (SqlDataReader sqlReader = sqlCommand.ExecuteReader())
    {
        dt.Load(sqlReader);
    }

    try
    {
        if (dt.Rows.Count > 0)
        {
            OutputdataGridView.DataSource = lstDownloadOwnerOutput;
            OutputdataGridView.ColumnHeadersDefaultCellStyle.Font = new Font(DataGridView.DefaultFont, FontStyle.Bold);
            OutputdataGridView.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
            Gridviewdisplaylabel.Text = "Total no of rows: " + this.OutputdataGridView.Rows.Count.ToString();
        }
        else if (dt.Rows.Count == 0)
        {
            MessageBox.Show("Data returned blank!!!");
        }
    }
    catch (Exception Ex)
    {
        if (Connection != null)
        {
            Connection.Close();
        }
        MessageBox.Show(Ex.Message);
    }
}

Ответы [ 3 ]

0 голосов
/ 05 января 2019

Вы можете просто добавить вызов загрузки таблицы каждые 2000 параметров в вашем коде:

var index = 0; // Reset the index
var idParameterList = new List<string>();
var dt = new DataTable();

foreach (var familyId in familyIds) {
    var paramName = "@familyId" + index;
    sqlCommand.Parameters.AddWithValue(paramName, familyId);
    idParameterList.Add(paramName);
    index++;
    if (index > 2000) {
        sqlCommand.CommandText = String.Format(query, string.Join(",", idParameterList));

        using (SqlDataReader sqlReader = sqlCommand.ExecuteReader())
            dt.Load(sqlReader);

        sqlCommand.Parameters.Clear();
        idParameterList.Clear();
        index = 0;
    }
}
if (index > 0) {
    sqlCommand.CommandText = String.Format(query, string.Join(",", idParameterList));

    using (SqlDataReader sqlReader = sqlCommand.ExecuteReader())
        dt.Load(sqlReader);
}
0 голосов
/ 05 января 2019

Для такого динамического sql я обычно рекомендую использовать Табличный параметр .

Требуется немного настройки: вам нужно создать определяемый пользователем тип в БД для хранения значений, но это довольно тривиальная операция:

CREATE TYPE PrimaryKeyType AS TABLE ( VALUE INT NOT NULL );  

Обычно мы используем их вместе с хранимыми процедурами:

CREATE PROCEDURE dbo.getFamily(@PrimaryKeys PrimaryKeyType READONLY)
AS
SELECT FamilyID, FullName, Alias 
  FROM TABLE (nolock) INNER JOIN @PrimaryKeys ON TABLE.FamilyID = @PrimaryKeys.Value
GO

Однако вы также можете использовать встроенный SQL, если хотите.

Присвоить значения хранимому параметру proc или inline довольно просто, но есть одна ошибка (более позднее):

    public static void AssignValuesToPKTableTypeParameter(DbParameter parameter, ICollection<int> primaryKeys)
    {
        // Exceptions are handled by the caller

        var sqlParameter = parameter as SqlParameter;
        if (sqlParameter != null && sqlParameter.SqlDbType == SqlDbType.Structured)
        {
            // The type name may look like DatabaseName.dbo.PrimaryKeyType,
            // so remove the database name if it is present
            var parts = sqlParameter.TypeName.Split('.');
            if (parts.Length == 3)
            {
                sqlParameter.TypeName = parts[1] + "." + parts[2];
            }
        }

        if (primaryKeys == null)
        {
            primaryKeys = new List<int>();
        }

        var table = new DataTable();

        table.Columns.Add("Value", typeof(int));

        foreach (var wPrimaryKey in primaryKeys)
        {
            table.Rows.Add(wPrimaryKey);
        }

        parameter.Value = table;
    }

Здесь нужно следить за именованием параметра. См. Код в методе выше, который удаляет имя базы данных для решения этой проблемы.

Если у вас динамический SQL, вы можете сгенерировать правильный параметр, используя следующий метод:

    public static SqlParameter CreateTableValuedParameter(string typeName, string parameterName)
    {
        // Exceptions are handled by the caller

        var oParameter = new SqlParameter();

        oParameter.ParameterName = parameterName;
        oParameter.SqlDbType = SqlDbType.Structured;
        oParameter.TypeName = typeName;

        return oParameter;
    }

Где typeName - имя вашего типа в БД.

0 голосов
/ 05 января 2019

Наличие предложения WHERE IN с параметрами 2100 или даже 100, как правило, не является хорошей практикой кодирования. Возможно, вы захотите поместить эти значения в отдельную достоверную таблицу, например,

families (ID int PK, ...)

Затем вы можете переписать ваш запрос как:

SELECT FamilyID, FullName, Alias
FROM TABLE (nolock)
WHERE FamilyID IN (SELECT ID FROM families);

Вы также можете выразить вышеизложенное с помощью предложения EXISTS или объединения, но в любом случае все три подхода могут просто оптимизироваться под очень похожий план запроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...