запрос mysql для динамического преобразования данных строк в столбцы

Я работаю над запросом сводной таблицы. Схема выглядит следующим образом

Сно, Название, Район

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

1 Mike CA
2 Mike CA
3 Proctor JB
4 Luke MN
5 Luke MN
6 Mike CA
7 Mike LP
8 Proctor MN
9 Proctor JB
10 Proctor MN
11 Luke MN

Как видите, у меня есть набор из 4 различных районов (CA, JB, MN, LP). Теперь я хотел создать для нее сводную таблицу, сопоставив имя с районами.

Name CA JB MN LP
Mike 3 0 0 1
Proctor 0 2 2 0
Luke 0 0 3 0

я написал следующий запрос для этого

select name,sum(if(District="CA",1,0)) as "CA",sum(if(District="JB",1,0)) as "JB",sum(if(District="MN",1,0)) as "MN",sum(if(District="LP",1,0)) as "LP" from district_details group by name

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

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

Я спрашиваю об этом, потому что вывод запроса «выбрать отдельные (районы) из района_детали» вернет мне один столбец с названием района в каждой строке, который я хотел бы перенести в столбец.


person Anirudh Goel    schedule 21.10.2009    source источник
comment
Взгляните на функцию MySQL GROUP_CONCAT().   -  person Corey Ballou    schedule 21.10.2009


Ответы (4)


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

SELECT DISTINCT District FROM district_details;

Это даст вам список районов, где есть детали. Затем вы создаете оператор SQL, повторяющий предыдущий результат (псевдокод).

statement = "SELECT name "

For each row returned in d = SELECT DISTINCT District FROM district_details 
    statement = statement & ", SUM(IF(District=""" & d.District & """,1 ,0)) AS """ & d.District & """" 

statement = statement & " FROM district_details GROUP BY name;"

И выполните этот запрос. Затем вам нужно будет обработать в своем коде обработку переменного количества столбцов

person Consultuning    schedule 22.10.2009

а) «Для каждого» не поддерживается в хранимых процедурах MySQL. б) Хранимые процедуры не могут выполнять подготовленные операторы из объединенных строк с использованием так называемых динамических операторов SQL, а также не могут возвращать результаты с более чем одной отдельной строкой. c) Сохраненные функции вообще не могут выполнять динамический SQL.

Это кошмар — отслеживать, как только у вас появилась хорошая идея, и все, кажется, развенчивают ее, прежде чем они думают: «Зачем кому-то хотеть ...»

Я надеюсь, что вы найдете свое решение, я все еще ищу свое. Закрытие, которое я получил, было

(извините за псевдокод)

-> в хранимую процедуру, создайте функцию, которая...

1) создать временную таблицу 2) загрузить данные во временную таблицу из столбцов, используя операторы if 3) загрузить временную таблицу в параметры INOUT или OUT в хранимой процедуре, как если бы вы вызывали таблицу... ЕСЛИ вы можете заставить ее вернуться более одной строки

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

Затем используйте;

подготовьте stmName из @yourqyersstring; выполнить stmName; освободить подготовить stmName;

(узнайте больше о хранимых процедурах на форуме mysql)

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

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

person Techie    schedule 29.03.2010
comment
б) Хранимые процедуры не могут выполнять подготовленные операторы из объединенных строк с использованием так называемых динамических операторов SQL, а также не могут возвращать результаты с более чем одной отдельной строкой. c) Сохраненные функции вообще не могут выполнять динамический SQL. Это неверно. Хранимые процедуры MySQL могут выполнять динамический SQL, также могут быть объединены и подготовлены, но не могут быть вложенными (т. е. не могут выполнять другой оператор PREPARE/EXECUTE с помощью EXECUTE). См.: dev.mysql.com/doc/ refman/5.0/ru/ - person Hendy Irawan; 20.10.2010
comment
а) Для каждого не поддерживается в хранимых процедурах MySQL. Хотя это правда, цикл поддерживается внутри MySQL SP с REPEAT-UNTIL/LOOP. См.: dev.mysql.com/doc/refman/5.0/ ru/repeat-statement.html - person Hendy Irawan; 20.10.2010
comment
Я должен сказать, что, несмотря на мои комментарии выше, я предвзят: я не верю в СП и осуждаю его использование. SP — это зло, если только оно не является строго необходимым, а все другие альтернативы (например, код + кэширование) оказались хуже. - person Hendy Irawan; 20.10.2010

Далее предполагается, что вам нужны совпадения различных пар (имя/район). т.е. Luke/CA и Duke/CA дадут два результата:

SELECT name, District, count(District) AS count
FROM district_details
GROUP BY District, name

Если это не так, просто удалите имя из предложения GROUP BY.

Наконец, обратите внимание, что я заменил sum() на count(), так как вы пытаетесь подсчитать все сгруппированные строки, а не получить сумму значений.

person Corey Ballou    schedule 21.10.2009
comment
спасибо за ваш вклад, однако это не то, что я хочу. Я хочу показать количество округов для всех имен во всех округах. Итак, если для Люка или Герцога я хочу получить их количество для каждого района, 0, если он не существует для этого района. Также сумма 1 n раз (что я делаю в запросе) сделает то же самое, что я считаю. - person Anirudh Goel; 21.10.2009

Из комментария @cballou выше я смог выполнить такую ​​​​функцию, которая не совсем то, о чем просил ОП, но подходит для моей аналогичной ситуации, поэтому я добавил ее сюда, чтобы помочь тем, кто придет после.

Обычный оператор выбора:

SELECT d.id ID,
       q.field field,
       q.quota quota
  FROM defaults d
  JOIN quotas q ON d.id=q.default_id

Вертикальные результаты:

ID field  quota
1  male   25
1  female 25
2  male   50

Выберите оператор, используя group_concat:

SELECT d.id ID,
       GROUP_CONCAT(q.fields SEPARATOR ",") fields,
       GROUP_CONCAT(q.quotas SEPARATOR ",") quotas
  FROM defaults d
  JOIN quotas q ON d.id=q.default_id

Затем я получаю разделенные запятыми поля «полей» и «квот», которые я могу затем легко обработать программно позже.

Горизонтальные результаты:

ID fields      quotas
1  male,female 25,25
2  male        50

Магия!

person Tamzin Blake    schedule 30.09.2011