mysql列转行可以通过concat,先分组然后连接。
show VARIABLES like '%group%' set @@group_concat_max_len = 10240 select @@group_concat_max_len SELECT GROUP_CONCAT(goods_id),1 as lzh FROM ts_goods WHERE ts_goods.cat_id_1 = 336 OR ts_goods.cat_id_2 = 336 OR ts_goods.cat_id_3 = 336 group by lzh
这里默认的限制是1024字节,可以通过set调整一下。
想到这个的原因是mysql在执行in操作的时候,有时候外层表的数据量巨大,使用in子查询之后不是用外层索引,但是直接的使用字符串拼接会使用索引。
这里还有一个问题,就是in的子查询的where语句没有索引与有索引差别也挺大,使用exlpain extended查看的时候不添加索引会全表扫描外层表。
SELECT DISTINCT order_id FROM ts_order_goods WHERE goods_id in ( SELECT goods_id FROM ts_goods WHERE ts_goods.cat_id_1 = 336 OR ts_goods.cat_id_2 = 336 OR ts_goods.cat_id_3 = 336 )
这里cat_id_1,cat_id_2,cat_id_3,没有索引的话ts_order_goods会all扫描100w行,如果有索引会使用index_marge,只有2k行。
而且上面的语句只是一个大查询的一个子查询,而且大查询的其他条件对这个子查询的优化结果也不同,mysql内部的优化机制挺复杂的,会根据整个执行的语句优化,根据结果集做优化判断。
上面的方法可以用到存储过程里面,这样就不用php去外层查询两次数据库,并拼接了。
CREATE PROCEDURE GetUsersDynamic(WhereCondition varchar(500),OrderByExpress varchar(100)) begin declare stmt varchar(2000); if LENGTH(OrderbyExpress)>0 then begin set @sqlstr=concat('select id,name,password,age,getdate(adddate) as AddDate from users where ',WhereCondition,' order by ',OrderByExpress); end; else begin set @sqlstr=concat('select id,name,password,age,getdate(adddate) as AddDate from users where ',WhereCondition); end; end if; prepare stmt from @sqlstr; execute stmt; end;
注意,mysql里面varchar的长度是有限制的,所以不能拼接过长的数据。mysql的in可以转为join,或者exist。
求乘集的方法是临时想的,主要是通过log与power,因为logA+logB = logAB。
SELECT pow(2, sum(log2(b))) from (select 2 as b union select 3 union select 4) as t
这样可以得到2*3*4=24