4

TABLE変数(MySQLには存在しないと聞きました)または一時テーブルのいずれかを使用する必要がある関数を作成しています。

ただし、一時テーブルはストアドプロシージャでのみ機能し、関数では機能しないようです。私はこのエラーを受け取り続けます:

ストアド関数またはトリガーでは、明示的または暗黙的なコミットは許可されていません。


私が構築しようとしているのは、私の以前の質問に対する解決策です。これは、開始日、終了日、およびコンマで区切られた文字列を受け取る関数です。最初に開始日から終了日までのすべての月を検索し、それらを個別のレコードとして最初の一時テーブルに保存します。次に、コンマで区切られた文字列を解析し、それらを2番目の一時テーブルに保存します。次に、2つに対して選択結合を実行し、レコードが存在する場合はtrueを返し、存在しない場合はfalseを返します。

私の意図は、これを別のクエリWHERE句の一部として使用することです。したがって、ストアドプロシージャではなく、関数である必要があります。

保存された関数で一時テーブルを使用するにはどうすればよいですか?そして、私ができない場合、代わりに何ができますか?

これが私の(現在壊れている)関数です(または要点として):

-- need to parse out a string like '4,2,1' and insert values into temporary table
-- MySQL doesn't have a native string split function, so we make our own
-- taken from: http://blog.fedecarg.com/2009/02/22/mysql-split-string-function/
DROP FUNCTION IF EXISTS SPLIT_STR;
CREATE FUNCTION SPLIT_STR(x VARCHAR(255), delim VARCHAR(12), pos INT) RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos), LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1), delim, '');

-- need to find all months between the start and end date and insert each into a temporary table
DROP FUNCTION IF EXISTS months_within_range;

DELIMITER //

CREATE FUNCTION months_within_range(starts_at DATE, ends_at DATE, filter_range VARCHAR(255)) RETURNS TINYINT
BEGIN

    DROP TABLE IF EXISTS months_between_dates;
    DROP TABLE IF EXISTS filter_months;
    CREATE TEMPORARY TABLE months_between_dates (month_stuff VARCHAR(7));
    CREATE TEMPORARY TABLE filter_months (filter_month VARCHAR(7));

    SET @month_count = (SELECT PERIOD_DIFF(DATE_FORMAT(ends_at, "%Y%m"), DATE_FORMAT(starts_at, "%Y%m")));
    -- PERIOD_DIFF only gives us the one month, but we want to compare to, so add one
    -- as in, the range between 2011-01-31 and 2011-12-01 should be 12, not 11

    INSERT INTO months_between_dates (month_stuff) VALUES (DATE_FORMAT(starts_at, "%Y-%m"));
    SET @month_count = @month_count + 1;
    -- start he counter at 1, since we've already included the first month above
    SET @counter = 1;
    WHILE @counter < @month_count DO
        INSERT INTO months_between_dates (month_stuff) VALUES (DATE_FORMAT(starts_at + INTERVAL @counter MONTH, "%Y-%m"));
        SET @counter = @counter + 1;
    END WHILE;

    -- break up the filtered string
    SET @counter = 1;
    -- an infinite loop, since we don't know how many parameters are in the filtered string
    filters: LOOP
        SET @filter_month = SPLIT_STR(filter_range, ',', @counter);
        IF @filter_month = '' THEN LEAVE filters;
        ELSE
            INSERT INTO filter_months (filter_month) VALUES (@filter_month);
            SET @counter = @counter + 1;
        END IF;
    END LOOP;

    SELECT COUNT(*) INTO @matches FROM months_between_dates INNER JOIN filter_months ON months_between_dates.month_stuff = filter_months.filter_month;

    IF @matches >= 1 THEN RETURN 1;
    ELSE RETURN 0;

END//

DELIMITER ;
4

1 に答える 1

9

ドロップテーブルステートメントは暗黙のコミットを引き起こしますが、これはmysql関数では許可されていません。ただし、一時テーブルを削除してもコミットは発生しません。months_between_datesまたはfilter_monthsという名前の通常の(一時的ではない)テーブルが存在することを心配していない場合は、変更できるはずです。

DROP TABLE IF EXISTS months_between_dates;
DROP TABLE IF EXISTS filter_months;

DROP TEMPORARY TABLE IF EXISTS months_between_dates;
DROP TEMPORARY TABLE IF EXISTS filter_months;
于 2011-11-06T00:46:19.407 に答える