Параметризованные запросы Sql

Это орех, который я раскалываю в наши дни

Приложение, над которым я работаю, имеет некоторую расширенную обработку для SQL. Одна из операций выбирает различные метаданные для объектов в текущем контексте из разных таблиц на основе имен элементов в коллекции. Для этого выполняется диапазон «select ... from ... where ... in ()», и для предотвращения вредоносного кода SQL используются параметры Sql для создания содержимого предложения «in ()».

Однако, когда набор элементов для создания предложения in () превышает 2100 элементов, это не удается из-за ограничения сервера Sql на максимальное количество параметров Sql в 2100 на запрос.

Один из подходов, который я сейчас пробую, - это создание таблицы #temp для хранения всех имен элементов и последующее присоединение к таблице в исходном запросе вместо использования «where in ()». Это заставляет меня ломать голову над тем, как заполнить таблицу именами элементов, хранящимися в массиве в коде .NET. Конечно, должен быть какой-то массовый способ вставить все, а не выпускать отдельную «вставку в» для каждого элемента?

Кроме того, меня очень интересуют альтернативные подходы к решению этой проблемы.

Большое спасибо

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
735
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Хм, не зная контекста и дополнительной информации о данных и о том, как вы используете результаты и проблемы с производительностью, я попытаюсь предложить альтернативу. Не могли бы вы разбить на несколько запросов? Сделайте то же самое, что и сейчас, но вместо того, чтобы строить запрос с 2100+ элементами, создайте два по 1050 в каждом, а затем объедините результаты.

На самом деле мне удалось сделать это довольно легко. Мы все равно проведем рефакторинг для запроса к таблице xml или #temp, но спасибо вам за простой выход из беспорядка ...

danijels 03.10.2008 17:58

Один из возможных обходных путей - использовать возможность запрашивать XML и просто отправлять все данные для вашего «входа» в виде столбца xml, а затем присоединяться к нему.

Тот же подход можно использовать для заполнения вашей временной таблицы, но опять же, почему бы просто не использовать ее напрямую.

Вот небольшой пример, который должен проиллюстрировать:

declare @wanted xml
set @wanted = '<ids><id>1</id><id>2</id></ids>'
select * 
from (select 1 Id union all select 3) SourceTable 
where Id in(select Id.value('.', 'int') from @wanted.nodes('/ids/id') as Foo(Id))

Просто создайте xml в своем приложении и передайте его в качестве параметра.

Мне было бы очень интересно, если бы вы могли подробнее рассказать об этом варианте.

danijels 03.10.2008 15:10

Еще раз спасибо, это похоже на решение, которое стоит изучить. Вопрос только в том, будет ли производительность лучше, чем при использовании таблицы #temp или нет.

danijels 03.10.2008 16:01

Prevengint вредоносный код SQL:> Используйте хранимую процедуру.

И да, в SQL Server 2005 есть массовая вставка: http://msdn.microsoft.com/en-us/library/ms188365.aspx

Знаю, но не все так просто. Базы данных создаются автоматически, и есть некоторые проблемы, связанные с использованием и поддержанием кода в базах данных.

danijels 03.10.2008 15:09

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

Похоже, вам следует более внимательно изучить бизнес-проблему или домен, чтобы определить лучший способ фильтрации элементов в вашем запросе. Предложение IN () может быть не лучшим способом сделать это. Возможно, в вашем случае будет лучше добавить категории данных или фильтры вместо большого списка элементов для включения. Трудно сказать, не зная больше о бизнес-проблеме / контексте.

Вы можете использовать класс SqlBulkCopy, представленный в .NET 2.0. На самом деле им очень просто пользоваться. Проверить это:

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx

Хорошо, я не уверен, насколько это хорошо для вас и насколько он эффективен, но вот код, который я использовал в прошлом для достижения аналогичного:

    CREATE FUNCTION [dbo].[Split](
    @list ntext
)
RETURNS @tbl TABLE (listpos int IDENTITY(1, 1) NOT NULL,
                          number  int NOT NULL) 
AS
BEGIN
    DECLARE @pos      int,
            @textpos  int,
            @chunklen smallint,
            @str      nvarchar(4000),
            @tmpstr   nvarchar(4000),
            @leftover nvarchar(4000)

    SET @textpos = 1
    SET @leftover = ''
    WHILE @textpos <= datalength(@list) / 2
    BEGIN
       SET @chunklen = 4000 - datalength(@leftover) / 2
       SET @tmpstr = ltrim(@leftover + substring(@list, @textpos, @chunklen))
       SET @textpos = @textpos + @chunklen

       SET @pos = charindex(',', @tmpstr)
       WHILE @pos > 0
       BEGIN
          SET @str = substring(@tmpstr, 1, @pos - 1)
          INSERT @tbl (number) VALUES(convert(int, @str))
          SET @tmpstr = ltrim(substring(@tmpstr, @pos + 1, len(@tmpstr)))
          SET @pos = charindex(',', @tmpstr)
       END

       SET @leftover = @tmpstr
    END

    IF ltrim(rtrim(@leftover)) <> ''
       INSERT @tbl (number) VALUES(convert(int, @leftover))

    RETURN
END

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

select a.number from split('1,2,3') a inner join myothertable b on a.number = b.ID

Как я уже сказал, это, вероятно, действительно плохо, потому что оно включает в себя множество манипуляций со строками, и я не могу вспомнить, откуда я взял функцию ... но она там, чтобы выбирать ...

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

Спасибо, но, как я упоминал ранее в другом комментарии, я не ищу SQL-код, поскольку базы данных создаются автоматически по запросу на основе определенных действий пользователя. Поэтому код лучше в .net

danijels 03.10.2008 15:57

SQL Server 2008 будет иметь параметры таблицы. Это молоток, который вам нужен.

Другие вопросы по теме