SQL_CALC_FOUND_ROWS 在 mysql 中不起作用

Posted

技术标签:

【中文标题】SQL_CALC_FOUND_ROWS 在 mysql 中不起作用【英文标题】:SQL_CALC_FOUND_ROWS is not working in mysql 【发布时间】:2015-10-16 06:59:47 【问题描述】:

我有两个过程,其中我使用限制子句进行动态查询,然后从中准备语句并执行。

第一个过程是

CREATE DEFINER=`root`@`%` PROCEDURE `dim_report_revenue_outflow_pivot`( 
IN _start_date VARCHAR(10),
IN _end_date VARCHAR(10),
IN _year VARCHAR(4),
IN _portal_id BIGINT(20),
IN _supervisor_id VARCHAR(100),
IN _assigned_to VARCHAR(100),
IN _column_id_csv TEXT,
IN _campaign_id_csv TEXT,
IN _product_id_csv TEXT,
IN _country_id_csv TEXT,
IN _agent_location TEXT,
IN _group_by VARCHAR(10),
IN _sort_by VARCHAR(20),
IN _sort_order TINYINT(1),
IN _page_no INT(10),
IN _count INT(10),
IN _token BIGINT(20)
)
proc_start: BEGIN
DECLARE _column_names TEXT;
SET SESSION group_concat_max_len = 1000000;
SET @_user_id := (SELECT user_id FROM session_token WHERE token=_token AND is_active=1);    
IF @_user_id IS NULL OR @_user_id = 0 THEN
    SELECT 'Session Expired';
    LEAVE proc_start;
END IF; 
/********************************* Start :  Set Where clause , and date field and group by      ********************/
IF _column_id_csv IS NOT NULL AND _column_id_csv != '' AND _column_id_csv != 'None' THEN
    SET _column_names:=  (SELECT GROUP_CONCAT(column_name) FROM `app_db_column_mappings` WHERE FIND_IN_SET(`column_id`,_column_id_csv));
ELSE 
    SET _column_names := (SELECT GROUP_CONCAT(DISTINCT column_names) FROM user_role_manager T1 
                 INNER JOIN user_access_table T2 ON T1.role_id=T2.role_id
                 WHERE T1.user_id=@_user_id AND T2.table_id=43); 
--            select @_column_names;   
    -- SELECT _column_names;
    SET _column_names := (SELECT GROUP_CONCAT(column_name) FROM `app_db_column_mappings` WHERE FIND_IN_SET(`column_id`,_column_names));

END IF;
SET @_where_clause := 'where 1=1';
SET @_group_by := "GROUP BY DATE_FORMAT(o.sale_on,'%Y-%m')";
IF _year IS NOT NULL AND _year != '' AND _year != ' ' AND _year != 'None' THEN
    SET @_where_clause := CONCAT(@_where_clause,' and year(o.sale_on) =',_year);
    SET @_date_field := 'MONTHNAME(o.sale_on) as date';
    SET @_group_by := "GROUP BY DATE_FORMAT(o.sale_on,'%Y-%m')";  -- if yearly then for every month

ELSEIF _start_date != '0000-00-00' AND _start_date IS NOT NULL AND _end_date != '0000-00-00' AND _end_date IS NOT NULL THEN 
    SET _start_date := STR_TO_DATE(_start_date, '%Y-%m-%d');
    SET _end_date := STR_TO_DATE(_end_date, '%Y-%m-%d');

    SET _end_date := DATE_ADD(_end_date,INTERVAL 1 DAY);
-- SELECT _end_date,_start_date;    
    SET @_where_clause := CONCAT(@_where_clause,' and date(o.sale_on) between "',_start_date,'" and "',_end_date,'"');
    SET @_date_field :='DATE(o.sale_on) as date';
    SET @_group_by := 'GROUP BY DATE(o.sale_on)';   -- if monthly or date range then day wise
END IF;
IF _portal_id != 0 THEN 
    SET @_where_clause := CONCAT(@_where_clause,' and mst.ticket_category_id =',_portal_id);
END IF;
IF _supervisor_id != 0 AND _supervisor_id IS NOT NULL AND _supervisor_id != '' AND _supervisor_id != 'None' THEN 
    SET @_user_list := (SELECT GROUP_CONCAT(DISTINCT user_id) FROM user_org_map WHERE FIND_IN_SET(manager_id,_supervisor_id));
    SET @_where_clause := CONCAT(@_where_clause,' and o.assigned_to in (',@_user_list,')');
END IF;
IF _assigned_to != 0 THEN 
    SET @_where_clause := CONCAT(@_where_clause,' and o.assigned_to in(',_assigned_to,')');
END IF;
IF _campaign_id_csv !=0 AND _campaign_id_csv IS NOT NULL THEN
    SET @_where_clause := CONCAT(@_where_clause,' and cd.campaign_id in(',_campaign_id_csv,')');
END IF;
IF _product_id_csv !=0 AND _product_id_csv IS NOT NULL THEN
    SET @_where_clause := CONCAT(@_where_clause,' and od.product_id in (',_product_id_csv,')');
END IF;
IF _country_id_csv !=0 AND _country_id_csv IS NOT NULL THEN
    SET @_where_clause := CONCAT(@_where_clause,' and cd.country in(',_country_id_csv,')');
END IF;
IF _agent_location IS NOT NULL AND _agent_location !='None' AND _agent_location != '' THEN
    SET @_where_clause := CONCAT(@_where_clause,' and ud.site_location =',_agent_location);
END IF;
-- select _agent_location,_country_id_csv,_product_id_csv,_campaign_id_csv,_assigned_to,_supervisor_id,_portal_id;
-- SELECT @_where_clause;
/********************************* End :  Set Where clause       ********************/
/********************************* Start :  Setting dynamically Group by       ********************/
CASE _group_by

    WHEN '153' THEN SET @_group_by := 'GROUP BY supervisor';
    WHEN '154' THEN SET @_group_by := 'GROUP BY product';
    WHEN '155' THEN SET @_group_by := 'GROUP BY campaign';
    WHEN '156' THEN SET @_group_by := 'GROUP BY agent_location';
    WHEN '157' THEN SET @_group_by := 'GROUP BY country';
    ELSE BEGIN END;
END CASE;
/********************************* End :  Setting dynamically Group by       ********************/
/********************************* STart :  Sort By       ********************/
CASE _sort_by
    WHEN '107' THEN SET @_order_by := 'ORDER BY sales';
    WHEN '108' THEN SET @_order_by := 'ORDER BY refunds';
    WHEN '109' THEN SET @_order_by := 'ORDER BY partially_refunded';
    WHEN '110' THEN SET @_order_by := 'ORDER BY pending';
    WHEN '111' THEN SET @_order_by := 'ORDER BY pending_revenue';
    WHEN '112' THEN SET @_order_by := 'ORDER BY gross_revenue';
    WHEN '113' THEN SET @_order_by := 'ORDER BY total_outflow';
    WHEN '134' THEN SET @_order_by := 'ORDER BY net_revenue';
    WHEN '135' THEN SET @_order_by := 'ORDER BY refund_percentage';
    WHEN '136' THEN SET @_order_by := 'ORDER BY partially_refund_percentage';
    WHEN '137' THEN SET @_order_by := 'ORDER BY pending_percentage';
    WHEN '138' THEN SET @_order_by := 'ORDER BY overall_outflow_percentage';


    WHEN '153' THEN SET @_order_by := 'ORDER BY supervisor';
    WHEN '154' THEN SET @_order_by := 'ORDER BY product';
    WHEN '155' THEN SET @_order_by := 'ORDER BY campaign';
    WHEN '156' THEN SET @_order_by := 'ORDER BY agent_location';
    WHEN '157' THEN SET @_order_by := 'ORDER BY country';
     ELSE SET @_order_by := 'ORDER BY o.sale_on';
END CASE;
IF _sort_order = 0 THEN -- that is desc order
    SET @_order_by := CONCAT(@_order_by,' DESC');
ELSE
    SET @_order_by := CONCAT(@_order_by,' ASC');

END IF;
/********************************* End :  Sort By       ********************/
SET @_query := CONCAT('SELECT SQL_CALC_FOUND_ROWS ',@_date_field,',',_column_names,' FROM orders o RIGHT JOIN order_detail od USING (order_id)
            LEFT JOIN order_refund_chargeback orc ON orc.order_detail_id = od.order_detail_id 
            left join user_detail ud on ud.user_id = o.assigned_to 
            left join customer_detail cd on cd.customer_id= o.customer_id
            LEFT JOIN master_product mp ON mp.product_id = od.product_id
            LEFT JOIN master_campaign mc ON mc.campaign_id = cd.campaign_id
            LEFT JOIN master_country mco ON mco.country_id = cd.country' , ' ',@_where_clause,' ',@_group_by,' ',@_order_by);
    -- select @_query;

IF _year IS NOT NULL AND _year != '' AND _year != ' ' AND _year != 'None' AND _group_by = '0' THEN
-- if year wise report then join with all the months by creating temprary table first
    SET @_query := CONCAT('CREATE TEMPORARY TABLE IF NOT EXISTS tmp_result AS (',@_query,')');
--   select @_query;
    PREPARE stmt FROM @_query;
    EXECUTE stmt;

--  select _column_names;

    SET _column_names:= LOWER(_column_names);

    SET _column_names := REPLACE(_column_names,LOWER('SUM(od.current_status_id=1) AS sales'),'ifnull(sales,0) as sales');
    SET _column_names := REPLACE(_column_names,LOWER('SUM(od.current_status_id=2) AS refunds'),'IFNULL(refunds,0) as refunds');
    SET _column_names := REPLACE(_column_names,LOWER('SUM(od.current_status_id=3) AS partially_refunded'),'IFNULL(partially_refunded,0) as partially_refunded');
    SET _column_names := REPLACE(_column_names,LOWER('SUM(od.current_status_id=4) AS `pending`'),'ifnull(pending,0) as pending');
    SET _column_names := REPLACE(_column_names,LOWER('IFNULL(SUM(CASE WHEN od.current_status_id=4 THEN od.price-IFNULL(od.discount,0)+IFNULL(od.additional_charges,0) END),0) AS pending_revenue'),'ifnull(pending_revenue,0) as pending_revenue');
    SET _column_names := REPLACE(_column_names,LOWER('IFNULL(SUM(CASE WHEN od.current_status_id=1 THEN od.price-IFNULL(od.discount,0)+IFNULL(od.additional_charges,0) END),0) AS gross_revenue'),'ifnull(gross_revenue,0) as gross_revenue');
    SET _column_names := REPLACE(_column_names,LOWER('IFNULL(SUM(CASE WHEN od.current_status_id=2 OR od.current_status_id=3 THEN orc.amount END),0) AS total_outflow'),'IFNULL(total_outflow,0) AS total_outflow');
    SET _column_names := REPLACE(_column_names,LOWER('(IFNULL(SUM(CASE WHEN od.current_status_id=4 THEN od.price-IFNULL(od.discount,0)+IFNULL(od.additional_charges,0) END),0) + IFNULL(SUM(CASE WHEN od.current_status_id=1 THEN od.price-IFNULL(od.discount,0)+IFNULL(od.additional_charges,0) END),0)) AS net_revenue'),'IFNULL(net_revenue,0) AS net_revenue');
    SET _column_names := REPLACE(_column_names,LOWER('IFNULL((SUM(od.current_status_id=2) / SUM(CASE WHEN od.current_status_id THEN 1 END)*100),0) AS refund_percentage'),'IFNULL(refund_percentage,0) AS refund_percentage');
    SET _column_names := REPLACE(_column_names,LOWER('IFNULL((SUM(od.current_status_id=3)/SUM(CASE WHEN od.current_status_id THEN 1 END)*100),0) AS partially_refund_percentage'),'IFNULL(partially_refund_percentage,0) AS partially_refund_percentage');
    SET _column_names := REPLACE(_column_names,LOWER('IFNULL((SUM(od.current_status_id=4)/SUM(CASE WHEN od.current_status_id THEN 1 END)*100),0) AS pending_percentage'),'IFNULL(pending_percentage,0) AS pending_percentage');
    SET _column_names := REPLACE(_column_names,LOWER('IFNULL((SUM(CASE WHEN od.current_status_id IN (2,3,4) THEN 1 END )/SUM(CASE WHEN od.current_status_id THEN 1 END)*100),0) AS overall_outflow_percentage'),'IFNULL(overall_outflow_percentage,0) AS overall_outflow_percentage');
    SET _column_names := REPLACE(_column_names,LOWER('ifnull((SELECT GROUP_CONCAT(CONCAT(user_first_name," ",user_last_name)) FROM user_detail WHERE user_id IN (SELECT manager_id FROM `user_org_map` WHERE user_id = o.assigned_to)),"") AS supervisor'),'IFNULL(supervisor,0) AS supervisor');

    SET _column_names := REPLACE(_column_names,LOWER('IFNULL(mp.product_name,"") AS product'),'IFNULL(product,"") AS product');
    SET _column_names := REPLACE(_column_names,LOWER('IFNULL(mc.campaign_name,"") AS campaign'),'IFNULL(campaign,"") AS campaign');
    SET _column_names := REPLACE(_column_names,LOWER('IFNULL(ud.site_location,"") AS agent_location'),'IFNULL(agent_location,"") AS agent_location');
    SET _column_names := REPLACE(_column_names,LOWER('IFNULL(mco.country_name,"") AS country'),'IFNULL(country,"") AS country');

    IF _sort_by = 0 THEN -- that is desc order
        SET @_order_by := 'ORDER BY mo.month_id';
        IF _sort_order = 0 THEN -- that is desc order
            SET @_order_by := CONCAT(@_order_by,' DESC');
        ELSE
            SET @_order_by := CONCAT(@_order_by,' ASC');

        END IF;
    END IF;

    IF _count !=0 THEN
    SET @_limit_offset := ((_page_no - 1) * _count);
    SET @_limit := CONCAT(' LIMIT ',@_limit_offset,',',_count);
    ELSE 
        SET @_limit := '';
    END IF;
    SET @_query := CONCAT('SELECT SQL_CALC_FOUND_ROWS mo.month_name as date,',_column_names,' FROM master_months mo LEFT JOIN tmp_result ON  mo.month_name = `date`',' ',@_order_by,@_limit);

    PREPARE stmt FROM @_query;
    EXECUTE stmt;

ELSE 
--  SELECT @_query;
    IF _count !=0 THEN
    SET @_limit_offset := ((_page_no - 1) * _count);
    SET @_limit := CONCAT(' LIMIT ',@_limit_offset,',',_count);
    ELSE 
        SET @_limit := '';
    END IF;
--  SELECT @_query;
    SET @_query := CONCAT(@_query,@_limit);

--  select @_query;

    PREPARE stmt FROM @_query;
    EXECUTE stmt;
END IF;
-- SELECT @_query;
UPDATE session_token SET `last_refresh_time`=(SELECT NOW()) WHERE token=_token; 
END$$

DELIMITER ;

对于第一个过程,最终查询是

SELECT SQL_CALC_FOUND_ROWS mo.month_name as date,ifnull(sales,0) as sales,IFNULL(refunds,0) as refunds,IFNULL(partially_refunded,0) as partially_refunded,ifnull(pending,0) as pending,ifnull(pending_revenue,0) as pending_revenue,ifnull(gross_revenue,0) as gross_revenue,IFNULL(total_outflow,0) AS total_outflow,IFNULL(net_revenue,0) AS net_revenue,IFNULL(refund_percentage,0) AS refund_percentage,IFNULL(partially_refund_percentage,0) AS partially_refund_percentage,IFNULL(pending_percentage,0) AS pending_percentage,IFNULL(overall_outflow_percentage,0) AS overall_outflow_percentage,IFNULL(supervisor,0) AS supervisor,IFNULL(product,"") AS product,IFNULL(campaign,"") AS campaign,IFNULL(agent_location,"") AS agent_location,IFNULL(country,"") AS country FROM master_months mo LEFT JOIN tmp_result ON  mo.month_name = `date` ORDER BY mo.month_id ASC LIMIT 0,5

现在当我开火时

select FOUND_ROWS();

经过上述过程,它返回 5,但总记录为 110。

在第二个过程中,最终的查询是

select SQL_CALC_FOUND_ROWS * from customer_detail cd
left join user_detail ud on cd.created_by = ud.user_id order by ud.user_id limit 1,6

现在当我开火时

select FOUND_ROWS()

在此过程之后并返回实际计数 1015。

如果我直接运行这两个查询,则 found_rows() 返回实际的总记录。两个查询之间的唯一区别是,第一个查询是在对 count 等查询进行操作之后进行的,limit 是通过过程参数进行 concat() 的。

第一个程序的问题是什么?

【问题讨论】:

第一个程序的内容是什么? @rlanvin 编辑了我的问题,添加了程序 【参考方案1】:

就我而言,我使用的是 mysql 的 NOW() 函数。我不知道那有什么问题。但是当我评论这行时

UPDATE session_token SET `last_refresh_time`=(SELECT NOW()) WHERE token=_token;

这对我有用。

【讨论】:

以上是关于SQL_CALC_FOUND_ROWS 在 mysql 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

MySQL中SQL_CALC_FOUND_ROWS的用法

Mysql SQL_CALC_FOUND_ROWS 和分页

SQL Server 中是不是有等效的 SQL_CALC_FOUND_ROWS?

黄聪:mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高

哪个最快? SELECT SQL_CALC_FOUND_ROWS FROM `table`,或 SELECT COUNT(*)

使用limit查询的同时取得总的记录数:SQL_CALC_FOUND_ROWS和FOUND_ROWS()