Хранимая процедура MySQL с переменным аргументом

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

Кто-нибудь может мне помочь?

DROP PROCEDURE IF EXISTS medatabase.SP_rptProvince2;
CREATE PROCEDURE medatabase.`SP_rptProvince2`(
 IN e_Region VARCHAR(45)
  )
BEGIN

 DECLARE strQuery VARCHAR(1024);
 DECLARE stmtp   VARCHAR(1024);
  SET @strQuery = CONCAT('SELECT * FROM alldata where 1=1');
  IF e_region IS NOT NULL THEN
   SET @strQuery = CONCAT(@strQuery, ' AND (regionName)'=e_Region);
  END IF;

 PREPARE  stmtp FROM  @strQuery;
 EXECUTE  stmtp;
END;

Ответ 1

AFAIK, вы не можете иметь такой список переменных аргументов. Вы можете сделать одну из двух вещей:

  • Возьмите фиксированное максимальное количество параметров и проверите их для null-ness перед конкатенацией:

    CREATE PROCEDURE SP_rptProvince2(a1 VARCHAR(45), a2 VARCHAR(45), ...)
    
    ...
    
      IF a1 IS NOT NULL THEN
        SET @strQuery = CONCAT(@strQuery, ' AND ', a2);
      END IF;
    

    Если вам нужны предопределенные поля, к которым применяются критерии в аргументе (например, параметр e_Region в вашем существующем коде), то вы соответствующим образом изменяете операцию CONCAT.

    Возможный вызов:

    CALL SP_rptProvince2('''North''', 'column3 = ''South''')
    
  • Возьмите один параметр, который намного больше, чем всего 45 символов, и просто добавьте его в запрос (если он не является нулевым).

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

    Возможный вызов:

    CALL SP_rptProvince2('RegionName = ''North'' AND column3 = ''South''')
    

Нельзя выбирать между ними. Либо можно заставить работать; ни один из них не является полностью удовлетворительным.

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

Ответ 2

Я нашел подход, основанный на JSON, который работает с новейшими системами MySQL/MariaDB. Проверьте ссылку ниже (оригинальный автор Федерико Раззоли): https://federico-razzoli.com/variable-number-of-parameters-and-optional-parameters-in-mysql-mariadb-procedures

По сути, вы берете параметр BLOB, который на самом деле является объектом JSON, а затем выполняете JSON_UNQUOTE (JSON_EXTRACT (json object, key)) в зависимости от ситуации.

Снял выписку здесь:

CREATE FUNCTION table_exists(params BLOB)
    RETURNS BOOL
    NOT DETERMINISTIC
    READS SQL DATA
    COMMENT '
Return whether a table exists.
Parameters must be passed in a JSON document:
* schema (optional). : Schema that could contain the table.
                       By default, the schema containing this procedure.
* table              : Name of the table to check.
'
BEGIN
    DECLARE v_table VARCHAR(64)
        DEFAULT JSON_UNQUOTE(JSON_EXTRACT(params, '$.table'));
    DECLARE v_schema VARCHAR(64)
        DEFAULT JSON_UNQUOTE(JSON_EXTRACT(params, '$.schema'));

    IF v_schema IS NULL THEN
        RETURN EXISTS (
            SELECT TABLE_NAME
                FROM information_schema.TABLES
                WHERE
                    TABLE_SCHEMA = SCHEMA()
                    AND TABLE_NAME = v_table
        );
    ELSE
        RETURN EXISTS (
            SELECT TABLE_NAME
                FROM information_schema.TABLES
                WHERE
                    TABLE_SCHEMA = v_schema
                    AND TABLE_NAME = v_table
        );
    END IF;
END;