2011-11-05 59 views
3

我正在寫一個函數,我需要使用TABLE變量(I hear they don't exist in MySQL)或臨時表。存儲函數中的臨時表?

但是,似乎臨時表似乎只適用於存儲過程,而不是函數。我不斷收到此錯誤:

Explicit or implicit commit is not allowed in stored function or trigger.


我試圖建立是an earlier question of mine的解決方案。它是一個接收開始日期,結束日期和逗號分隔字符串的函數。它首先查找開始和結束日期之間的所有月份,並將它們作爲單獨記錄保存在第一個臨時表中。然後解析出逗號分隔的字符串並將其保存到第二個臨時表中。然後它在兩者上進行選擇連接,如果存在記錄,則返回true,否則返回false。

我的意圖是將其用作另一個查詢WHERE子句的一部分,因此它需要是一個函數而不是存儲過程。

如何在存儲函數中使用臨時表?如果我不能,我能做些什麼呢?

這裏是我的(目前破碎)函數(或作爲gist):

-- 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 ; 

回答

6

DROP TABLE語句將導致一個隱含的承諾,這是不是在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; 
+0

謝謝!看起來像是工作。 – neezer