2013-06-06 4 views
1

Я надеюсь, что это относительно простой вопрос для ответа. У меня есть список транзакций в таблице базы данных, и я хочу извлечь в столбцы значение enum (y/n) для каждого производителя мотоциклов, который существует в этой таблице.Mysql строки для столбцов запрос

Я попытался следующий запрос:

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 ; 

Хотя это кажется очень логичным решением для быстрого возврата основной таблицы содержит более 48000 строк, и поэтому время выполнения находится в минутах.

Я попытался работать со сбором на временной таблице, но только один из них вернулся только сгруппированным по коду учетной записи клиента.

Конечно, я мог бы попробовать group_concat, но это не то, чего я действительно хочу достичь.

Если у кого-то есть мысли о том, как я могу достичь этого, это было бы блестящим.

Как всегда большое спасибо заранее.

Приветствие Graham

+0

Это FAQ, поиск «mysql pivot», и вы найдете много вопросов и ответов. – Barmar

+0

Данные примера плюс образец желаемого результата могут значительно увеличить ваши шансы получить ответ. Я лично не буду расшифровывать ваши запросы. – akostadinov

ответ

2

Если вы идете булеву 1/0 вместо г/п, то вы можете значительно упростить для себя и сделать запрос проблемы а-вкладка кросса which'll быть намного более эффективным ...

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 для этого.

+0

Использование булева 1/0 на самом деле не является ключом к улучшению; ключевым является устранение ненужного рекурсивного SQL с использованием агрегата в выражении. – spencer7593

0

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 
0

Огромное спасибо Steph за вашу помощь по этому вопросу. Объяснение того, что данные экспортируются в файл 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 

Большое спасибо Graham

+0

Вы можете использовать функцию «MAX» и сразу же возвращать «y» и «n» вместо «IF» и «SUM». (Нет необходимости вычислять SUM, вы можете вернуть «y», если есть хотя бы одна строка, которая удовлетворяет условию, и в противном случае возвращает «n».) – spencer7593

+0

Рад помочь! –

2

Всякий раз, когда вы получаете «зацикливания», как это в дизайне, есть часто гораздо более эффективным дизайн.

Трудно понять, почему вам понадобится udf, и почему это запрашивает одну и ту же таблицу и почему этот запрос нужно выполнить 8 раз для каждой строки таблицы (или, точнее, для каждой строки, где accCode < > ''). Если 48 000 строк соответствуют критериям в этом внешнем запросе, это будет 384 000 вызовов этой функции, и это будет всего 384 001 запросов, выполненных против базы данных.

Я просто не могу понять, зачем вам нужно это делать, чтобы получить указанный результирующий набор.

Было бы гораздо более эффективным, чтобы получить информацию только в одном проходе через стол, с чем-то запроса, как это:

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 

Ваша функция включает в себя спецификации, что сравнение должно быть сделано без учета регистра сверку , Если вам нужно указать, что это может быть сделано в SQL

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

Этот запрос, скорее всего, выиграет от индекса накрытия на accCode и vehichleManufacturer.

(Это странное написание в этом имени vehichleManufacturer колонке.)


для MySQL конкретных IF() функция может быть заменен эквивалентным выражением ANSI CASE, например:

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

Ницца! После трипсов с перечислениями и макс я думаю, что я заблокировал использование агрегатов на чем-либо текстовом, что является позором, потому что это аккуратный способ сделать это. :-) Хотя я предпочитаю CASE, потому что он более переносимый, чем IF –

+0

Хорошие баллы. В этом случае функция MAX применяется только к двум буквальным значениям, поэтому в этом случае нет ничего, что можно было бы отключить. Если вам нужно, чтобы SQL был переносимым, то да, выражение ANSI 'CASE' будет предпочтительнее функции' IF() 'MySQL. – spencer7593

+0

Привет Спенсер и Стеф, большое спасибо за вашу помощь в этом. Я действительно понимал, что это происходит совершенно неправильно и, конечно же, пока я получил результаты, которые мне нужны, я знаю, что это было неправильно. Моя проблема заключалась в том, что я ударил ментальную кирпичную стену и просто не мог понять, как ее обойти. @StephLocke предоставил мне хорошую отправную точку, которую я реализовал вчера, и ваше объяснение. Спенсер дал мне гораздо лучшее представление о том, как все работает, поэтому большое спасибо вам обоим. Мой обновленный ответ ниже, что касается написания, да, я знаю :-) – EvilKermitSaurus

Смежные вопросы