1

我希望这是一个相对简单的问题。我在数据库表中有一个事务列表,我想将一个枚举值 (y/n) 提取到该表中存在的每个摩托车制造商的列中。

我尝试了以下查询:

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

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

虽然这对于快速返回来说似乎是一个非常合乎逻辑的解决方案,但主表包含超过 48,000 行,因此执行时间在几分钟内。

我确实尝试在一个临时表上使用连接,但是当按客户帐户代码分组时,它只返回一个制造商。

当然我可以尝试 group_concat 但这不是我真正想要实现的。

如果有人对我如何实现这一目标有任何想法,那就太好了。

一如既往地提前感谢。

干杯格雷厄姆

4

4 回答 4

2

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<>''). 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.

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

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

That query is likely to benefit from a covering index on accCode and vehichleManufacturer.

(That's an odd spelling in that vehichleManufacturer column name.)


The MySQL-specific IF() function could be replaced with an equivalent ANSI CASE expression, e.g.:

  , MAX(CASE WHEN vehichleManufacturer='HON' THEN 'y' ELSE 'n' END)
于 2013-06-06T15:23:51.387 回答
2

如果您选择布尔值 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

话虽这么说,你的代码和我展示的删节修改是按 accCode 分组的,这就是你所说的你想要的,但我不确定这对你有多大价值,除非你想要构建一个查找表或类似的东西,在这种情况下,您可以简单地获取一个不同的 accCode 列表,然后手动或在 excel 中完成其余的工作,就像编写 sql 一样快。

于 2013-06-06T15:06:19.833 回答
0

尝试:

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
于 2013-06-06T15:11:31.797 回答
0

非常感谢斯蒂芬在这方面的帮助。为了解释数据被导出到 CSV 文件以供外部使用,因此它被导入的系统只需要一个平面文件。

我已经稍微修改了您的查询,嘿,它可以工作:

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

非常感谢格雷厄姆

于 2013-06-06T15:18:02.143 回答