简体   繁体   English

Mysql行到列查询

[英]Mysql rows to columns query

I am hoping this is a relatively simple question to answer. 我希望这是一个相对简单的问题来回答。 I have a list of transactions in a database table and I want to extract into columns an enum value (y/n) to each motorcycle manufacturer that exists in that table. 我有一个数据库表中的事务列表,我想向列中提取枚举值(y / n)给该表中存在的每个摩托车制造商。

I have tried the following query: 我尝试了以下查询:

SELECT
accCode,
rnFuncBool(accCode,'HON') purchasedHonda,
rnFuncBool(accCode,'YAM') purchasedYamaha,
rnFuncBool(accCode,'KAW') purchasedKawsaki,
rnFuncBool(accCode,'SUZ') purchasedSuzuki,
rnFuncBool(accCode,'DUC') purchasedDucati,
rnFuncBool(accCode,'KTM') purchasedKTM,
rnFuncBool(accCode,'SYM') purchasedSym,
rnFuncBool(accCode,'VIC') purchasedVictory
FROM _emarsys_vehiclessold WHERE accCode<>'' GROUP BY accCode

and the function rnFuncBool is as follows: 函数rnFuncBool如下:

DELIMITER $$
USE `phcontacts`$$
DROP FUNCTION IF EXISTS `rnFuncBool`$$
CREATE DEFINER=`root`@`localhost` FUNCTION `rnFuncBool`(
fnAccCode VARCHAR(6),
fnAccMan VARCHAR(3)
) RETURNS VARCHAR(1) CHARSET utf8
BEGIN
IF (SELECT COUNT(*) FROM _emarsys_vehiclessold WHERE accCode=fnAccCode COLLATE utf8_unicode_ci AND vehichleManufacturer=fnAccMan COLLATE utf8_unicode_ci )>0 THEN
    RETURN 'y';
ELSE
    RETURN 'n';
END IF;
END$$

DELIMITER ;

Whilst this seems a really logical solution for a quick return the main table contains over 48,000 rows and so the execution time is in the minutes. 虽然这对于快速返回来说似乎是一个非常合理的解决方案,但主表包含超过48,000行,因此执行时间以分钟为单位。

I did try working with a join on a temporary table but that only returned one manufacturer when grouped by the customer account code. 我确实尝试在临时表上使用联接,但只有在按客户帐户代码分组时才返回一个制造商。

Of course I could try group_concat but that is not what I really want to achieve. 当然我可以尝试group_concat,但这不是我真正想要实现的。

If anybody has any thoughts on how I can achieve this that would be brilliant. 如果有人对如何实现这一点有任何想法,那就太棒了。

As always many thanks in advance. 一如既往地提前感谢。

Cheers Graham 干杯格雷厄姆

If you go for boolean 1/0 instead of y/n then you can greatly simplify things for yourself and do a cross-tab problem query which'll be way more efficient... 如果你选择布尔值1/0而不是y / n,那么你可以大大简化自己的事情,并做一个交叉表问题查询,这将更有效...

SELECT
accCode,
SUM(CASE WHEN accCode ='HON' THEN 1 ELSE 0 END) purchasedHonda,
SUM(CASE WHEN accCode='YAM' THEN 1 ELSE 0 END)  purchasedYamaha,
...
SUM(CASE WHEN accCode='VIC' THEN 1 ELSE 0 END)  purchasedVictory
FROM _emarsys_vehiclessold WHERE accCode<>'' 
GROUP BY accCode

That being said, your code and what I've shown an abridged amendment to is grouping by accCode, which is what you've said you want, but I'm not sure how much value there is for you unless you're looking to construct a lookup table or something similar in which case you could simply get a list of distinct accCode and do the rest by hand or in excel just as quickly as writing sql to do it. 话虽这么说,你的代码和我所显示的简要修正是按照accCode进行分组,这就是你所说的你想要的,但我不确定你有多大价值,除非你想要构建一个查找表或类似的东西,在这种情况下你可以简单地得到一个不同的accCode列表,并在手写或在excel中完成其余操作,就像编写sql一样快。

Whenever you get "looping" like this in a design, there is frequently a much more efficient design. 每当你在设计中像这样“循环”时,通常会有更高效的设计。

It's hard to figure out why you would need a udf, and why that queries the same table, and why that query needs to be performed 8 times for every row in the table (or, more precisely every row where accCode<>''). 很难弄清楚为什么你需要一个udf,以及为什么查询同一个表,以及为什么该查询需要为表中的每一行执行8次(或者更准确地说,每个行都是accCode <>'') 。 If 48,000 rows match the criteria in that outer query, that's going to be 384,000 calls to the function, which is going to be a total 384,001 queries executed against the database. 如果48,000行与该外部查询中的条件匹配,那么将对该函数进行384,000次调用,这将是对数据库执行的总共384,001个查询。

I just can't fathom why you would need to do that, to get the specified resultset. 我无法理解为什么你需要这样做,以获得指定的结果集。

It would be much more efficient to get the information in just one pass through the table, with a query something like this: 只需一次通过表就可以获得更有效的信息,查询类似于:

SELECT accCode
     , MAX(IF(vehichleManufacturer='HON','y','n')) AS purchasedHonda
     , MAX(IF(vehichleManufacturer='YAM','y','n')) AS purchasedYamaha
     , MAX(IF(vehichleManufacturer='KAW','y','n')) AS purchasedKawasaki
     , ...
  FROM _emarsys_vehiclessold
 WHERE accCode<>''
 GROUP
    BY accCode

Your function includes a specification that the comparison should be done case insensitive collation. 您的功能包括一个规范,比较应该是不区分大小写的排序规则。 If you need to specify that, it can be done in the SQL 如果需要指定,可以在SQL中完成

  , MAX(IF(vehichleManufacturer='HON' COLLATE utf8_unicode_ci,'y','n'))

That query is likely to benefit from a covering index on accCode and vehichleManufacturer . 该查询可能会受益于accCodevehichleManufacturer的覆盖索引。

(That's an odd spelling in that vehichleManufacturer column name.) (这是vehichleManufacturer列名称中的一个奇怪的拼写。)


The MySQL-specific IF() function could be replaced with an equivalent ANSI CASE expression, eg: MySQL特定的IF()函数可以替换为等效的ANSI CASE表达式,例如:

  , MAX(CASE WHEN vehichleManufacturer='HON' THEN 'y' ELSE 'n' END)

Try: 尝试:

SELECT accCode,
       case sum(CASE accCode WHEN 'HON' THEN 1 ELSE 0 END)
            when 0 then 'n' else 'y' 
       end purchasedHonda,
       case sum(CASE accCode WHEN 'YAM' THEN 1 ELSE 0 END)
            when 0 then 'n' else 'y' 
       end purchasedYamaha,
       case sum(CASE accCode WHEN 'KAW' THEN 1 ELSE 0 END)
            when 0 then 'n' else 'y' 
       end purchasedKawsaki,
       case sum(CASE accCode WHEN 'SUZ' THEN 1 ELSE 0 END)
            when 0 then 'n' else 'y' 
       end purchasedSuzuki,
       case sum(CASE accCode WHEN 'DUC' THEN 1 ELSE 0 END)
            when 0 then 'n' else 'y' 
       end purchasedDucati,
       case sum(CASE accCode WHEN 'KTM' THEN 1 ELSE 0 END)
            when 0 then 'n' else 'y' 
       end purchasedKTM,
       case sum(CASE accCode WHEN 'SYM' THEN 1 ELSE 0 END)
            when 0 then 'n' else 'y' 
       end purchasedSym,
       case sum(CASE accCode WHEN 'VIC' THEN 1 ELSE 0 END)
            when 0 then 'n' else 'y' 
       end purchasedVictory
FROM _emarsys_vehiclessold WHERE accCode<>'' GROUP BY accCode

Many thanks to Steph for your help on this. 非常感谢Steph对此的帮助。 To explain the data is being exported to a CSV file for external use and so the system it is being imported into needs a flat file only. 要说明数据正在导出到CSV文件以供外部使用,因此导入的系统只需要一个平面文件。

I have modified your query slightly and hey presto it works: 我稍微修改了你的查询,嘿它presto它的工作原理:

SELECT accCode,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='HON' THEN 1 ELSE 0 END)>0,'y','n')) purchasedHonda,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='KAW' THEN 1 ELSE 0 END)>0,'y','n')) purchasedKawasaki,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='SUZ' THEN 1 ELSE 0 END)>0,'y','n')) purchasedSuzuki,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='DUC' THEN 1 ELSE 0 END)>0,'y','n')) purchasedDucati,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='KTM' THEN 1 ELSE 0 END)>0,'y','n')) purchasedKTM,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='SYM' THEN 1 ELSE 0 END)>0,'y','n')) purchasedSym,
(IF (SUM(CASE WHEN `vehichleManufacturer`='YAM' THEN 1 ELSE 0 END)>0,'y','n'))  purchasedYamaha,
(IF (SUM(CASE WHEN `vehichleManufacturer`='VIC' THEN 1 ELSE 0 END)>0,'y','n'))  purchasedVictory
FROM _emarsys_vehiclessold WHERE accCode<>'' 
GROUP BY accCode

Many thanks Graham 非常感谢格雷厄姆

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM