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 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 中是不是有等效的 SQL_CALC_FOUND_ROWS?
黄聪:mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高
哪个最快? SELECT SQL_CALC_FOUND_ROWS FROM `table`,或 SELECT COUNT(*)