Целочисленные массивы Postgres в качестве параметров?

Я понимаю, что в чистом Postgres вы можете передать целочисленный массив в функцию, но это не поддерживается в поставщике данных .NET Npgsql.

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

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

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

Обычно я живу в LINQ 2 SQL, смакуя абстракцию Db, работая над этим проектом с ручным доступом к данным, все это становится немного грязным, как люди обычно передают такие параметры в postgres?


person Tristan Warner-Smith    schedule 20.02.2009    source источник
comment
Для тех, кто не читает выбранные ответы: параметры массива поддерживаются с поставщиком .NET Npgsql (хотя я не могу сказать, было ли это правдой, когда был задан вопрос). См. мой ответ ниже.   -  person brichins    schedule 30.09.2014


Ответы (4)


См.: http://www.postgresql.org/docs/9.1/static/arrays.html

Если ваш неродной драйвер по-прежнему не позволяет вам передавать массивы, то вы можете:

  • передать строковое представление массива (который ваша хранимая процедура может затем преобразовать в массив -- см. string_to_array)

    CREATE FUNCTION my_method(TEXT) RETURNS VOID AS $$ 
    DECLARE
           ids INT[];
    BEGIN
           ids = string_to_array($1,',');
           ...
    END $$ LANGUAGE plpgsql;
    

    потом

    SELECT my_method(:1)
    

    с: 1 = '1,2,3,4'

  • полагаться на сам Postgres для преобразования строки в массив

    CREATE FUNCTION my_method(INT[]) RETURNS VOID AS $$ 
           ...
    END $$ LANGUAGE plpgsql;
    

    потом

    SELECT my_method('{1,2,3,4}')
    
  • выберите не использовать переменные связывания и вместо этого введите явную командную строку со всеми параметрами (убедитесь, что все параметры, поступающие извне, проверены или экранированы, чтобы избежать атак SQL-инъекций).

    CREATE FUNCTION my_method(INT[]) RETURNS VOID AS $$ 
           ...
    END $$ LANGUAGE plpgsql;
    

    потом

    SELECT my_method(ARRAY [1,2,3,4])
    
person vladr    schedule 20.02.2009
comment
Спасибо! Нет, я полагался на то, что мне сказали мои коллеги. Я попробую. - person Tristan Warner-Smith; 21.02.2009
comment
У вас есть какие-либо доказательства отсутствия встроенной поддержки подготовленных операторов в PG? Я не смог найти никаких упоминаний об этом факте в руководстве. Что касается ведения журнала, я предполагаю, что сервер регистрирует запросы по мере их выполнения, а не по мере их передачи от клиента, поэтому в журнале нет операторов EXECUTE. - person Ihor Kaharlichenko; 13.08.2012
comment
@IhorKaharlichenko формулировка была плохой и не по теме. Отредактировал ответ. Ре. Согласно исходному утверждению, драйверы не будут использовать PREPARE, если не включены подготовленные операторы на стороне сервера (иногда явно) и, в некоторых случаях, если для команды не превышен определенный порог числа выполнений. Если ведение журнала команд включено в postgresql.conf, вы увидите фактические SELECT/INSERT/и т. д. команды, когда подготовленные операторы на стороне сервера НЕ используются. - person vladr; 13.08.2012

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

SELECT * FROM some_table WHERE id_column = ANY(@id_list)

где @id_list привязан к параметру int[] посредством

command.Parameters.Add("@id_list", NpgsqlDbType.Array | NpgsqlDbType.Integer).Value = my_id_list;

где команда — это NpgsqlCommand (с использованием C# и Npgsql в Visual Studio).

person brichins    schedule 11.10.2011
comment
не уверен, что на это ответят, но ваш ответ, похоже, напрямую касается ситуации. В моем коде C# я создаю список идентификаторов для фильтрации таблицы данных DGV. Список идентификаторов выглядит как 1234,2345,3456. Я добавлял параметр обычным способом: cmd.Parameters.Add(new NpgsqlParameter("idList", idFilter)); но получал ошибку при заполнении адаптера данных набором данных, оператора не существует: integer = text'. Я нашел ваш код и подключил его, но получаю другую ошибку: Невозможно записать тип System.String как массив System.Int32'. Предложения? - person marky; 07.04.2020
comment
@marky, похоже, вы пытаетесь присвоить параметру idList строковый литерал ("123,456") вместо целочисленного массива ([123, 456]). Суть инструментария Npgsql заключается в том, что вы не прокручиваете оператор SQL вручную с введенными текстовыми значениями, вы создаете строго типизированный запрос с безопасными для типов параметрами, который ожидает типизированные объекты. - person brichins; 07.04.2020
comment
Хорошо, в этом есть смысл, так как мне перейти от строки чисел ("1234,2345, 3456") к целочисленному массиву? Возможно, еще лучше, как мне построить список в виде целочисленного массива (текущий код: idToAddToList = dt.Rows[rowIndex][0].ToString();), передать его функции GetDgvData() и добавить этот массив в качестве параметра? Могу ли я использовать List<int> в этом случае? - person marky; 08.04.2020
comment
Что ж, я получил от List<> идентификаторов до GetDgvData(), но я не могу понять, что с ним делать в этот момент, чтобы получить значения в запросе. - person marky; 08.04.2020
comment
@marky второй блок кода в ответе указывает int[] или Array<int>, если вы предпочитаете этот синтаксис. Прекратите вызывать .ToString() и просто поместите целые числа из столбца dt в массив, а затем передайте это. Я не думаю, что Npgsql поддерживает тип List, но если вам удобнее работать со списками, вы можете продолжить сначала создавать List<int>, а затем вызывать .ToArray(), но процесс почти идентичен, поэтому я предлагаю пропустить промежуточный шаг. Затем ваш параметр (который я назвал my_id_list) связан, как показано выше. - person brichins; 08.04.2020

Вы можете всегда использовать правильно отформатированную строку. Хитрость заключается в форматировании.

command.Parameters.Add("@array_parameter", string.Format("{{{0}}}", string.Join(",", array));

Обратите внимание, что если ваш массив представляет собой массив строк, вам нужно будет использовать array.Select(value => string.Format("\"{0}\", value)) или его эквивалент. Я использую этот стиль для массив перечисляемого типа в PostgreSQL, потому что нет автоматического преобразования из массива.

В моем случае мой перечисляемый тип имеет некоторые значения, такие как «значение1», «значение2», «значение3», и мое перечисление C# имеет совпадающие значения. В моем случае окончательный SQL-запрос выглядит примерно так (E'{"value1","value2"}'), и это работает.

person user2738265    schedule 01.09.2013
comment
Разумеется, применяются все стандартные предупреждения о SQL-инъекциях. - person brichins; 10.05.2014

Полная структура кодирования

функция postgresql

CREATE OR REPLACE FUNCTION admin.usp_itemdisplayid_byitemhead_select(
    item_head_list int[])
    RETURNS TABLE(item_display_id integer) 
    LANGUAGE 'sql'

    COST 100
    VOLATILE 
    ROWS 1000
    
AS $BODY$ 
        SELECT vii.item_display_id from admin.view_item_information as vii
where vii.item_head_id = ANY(item_head_list);
    $BODY$;

Модель

public class CampaignCreator
    {
        public int item_display_id { get; set; }
        public List<int> pitem_head_id { get; set; }
    }

Функция .NET CORE

DynamicParameters _parameter = new DynamicParameters();
                _parameter.Add("@item_head_list",obj.pitem_head_id);
                
                string sql = "select * from admin.usp_itemdisplayid_byitemhead_select(@item_head_list)";
                response.data = await _connection.QueryAsync<CampaignCreator>(sql, _parameter);
person Mahydul Islam Shajal    schedule 26.01.2021