Si j'ai une table MySQL qui ressemble à ceci:
company_name action pagecount ------------------------------- Société A IMPRIMER 3 Entreprise A IMPRIMER 2 Entreprise A IMPRIMER 3 Entreprise B EMAIL Entreprise B IMPRIMER 2 Entreprise B IMPRIMER 2 Société B IMPRIMER 1 Société A IMPRIMER 3
Est-il possible d'exécuter une requête MySQL pour obtenir une sortie comme celle-ci:
company_name E-MAIL IMPRIMER 1 pages IMPRIMER 2 pages IMPRIMER 3 pages ----------------------------- -------------------------------- SociétéA 0 0 1 3 SociétéB 1 1 2 0
L'idée est que pagecount
peut varier, de sorte que le montant de la colonne de sortie doit refléter cela, une colonne pour chaque paire action
/pagecount
, puis le nombre de hits par company_name
. Je ne sais pas si cela s'appelle un tableau croisé dynamique, mais quelqu'un a suggéré cela?
Ceci est un tableau croisé dynamique.
Un tutoriel de Nice sur la façon de réaliser ceci peut être trouvé ici: http://www.artfulsoftware.com/infotree/qrytip.php?id=78
Je conseille de lire cet article et d’adapter cette solution à vos besoins.
Mettre à jour
Après que le lien ci-dessus ne soit plus disponible, je me sens obligé de fournir quelques informations supplémentaires à tous ceux qui recherchent des réponses pivot mysql ici. Il contenait vraiment une grande quantité d'informations, et je ne mettrai pas tout en détail ici (encore plus car je ne veux pas copier leur vaste savoir), mais je vais vous donner quelques conseils sur la façon de traiter le pivot table généralement à la manière de SQL avec l'exemple de peku qui a posé la question en premier lieu.
Peut-être que le lien reviendra bientôt, je vais garder un œil dessus.
La méthode de la feuille de calcul ...
Beaucoup de gens utilisent simplement un outil comme MSExcel, OpenOffice ou d’autres outils de tableur à cette fin. Ceci est une solution valable, copiez simplement les données là-bas et utilisez les outils proposés par l'interface graphique pour résoudre ce problème.
Mais… ce n’était pas la question, et cela pourrait même entraîner des inconvénients, tels que la manière d’obtenir les données dans le tableur, la mise à l’échelle problématique, etc.
La méthode SQL ...
Compte tenu de sa table ressemble à quelque chose comme ça:
CREATE TABLE `test_pivot` (
`pid` bigint(20) NOT NULL AUTO_INCREMENT,
`company_name` varchar(32) DEFAULT NULL,
`action` varchar(16) DEFAULT NULL,
`pagecount` bigint(20) DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=MyISAM;
Maintenant, regarde dans sa table désirée:
company_name EMAIL PRINT 1 pages PRINT 2 pages PRINT 3 pages
-------------------------------------------------------------
CompanyA 0 0 1 3
CompanyB 1 1 2 0
Les lignes (EMAIL
, PRINT x pages
) ressemblent à des conditions. Le groupement principal est constitué de company_name
.
Afin de définir les conditions, cela crie plutôt à l’utilisation de l’instruction CASE
-. Pour grouper par quelque chose, bien, utilisez ... GROUP BY
.
Le SQL de base fournissant ce pivot peut ressembler à ceci:
SELECT P.`company_name`,
COUNT(
CASE
WHEN P.`action`='EMAIL'
THEN 1
ELSE NULL
END
) AS 'EMAIL',
COUNT(
CASE
WHEN P.`action`='PRINT' AND P.`pagecount` = '1'
THEN P.`pagecount`
ELSE NULL
END
) AS 'PRINT 1 pages',
COUNT(
CASE
WHEN P.`action`='PRINT' AND P.`pagecount` = '2'
THEN P.`pagecount`
ELSE NULL
END
) AS 'PRINT 2 pages',
COUNT(
CASE
WHEN P.`action`='PRINT' AND P.`pagecount` = '3'
THEN P.`pagecount`
ELSE NULL
END
) AS 'PRINT 3 pages'
FROM test_pivot P
GROUP BY P.`company_name`;
Cela devrait fournir le résultat souhaité très rapidement. L'inconvénient majeur de cette approche est que plus vous avez de lignes dans votre tableau croisé dynamique, plus vous avez de conditions à définir dans votre instruction SQL.
Cela peut être traité aussi, donc les gens ont tendance à utiliser des déclarations préparées, des routines, des compteurs, etc.
Quelques liens supplémentaires sur ce sujet:
Ma solution est dans T-SQL sans pivots:
SELECT
CompanyName,
SUM(CASE WHEN (action='EMAIL') THEN 1 ELSE 0 END) AS Email,
SUM(CASE WHEN (action='PRINT' AND pagecount=1) THEN 1 ELSE 0 END) AS Print1Pages,
SUM(CASE WHEN (action='PRINT' AND pagecount=2) THEN 1 ELSE 0 END) AS Print2Pages,
SUM(CASE WHEN (action='PRINT' AND pagecount=3) THEN 1 ELSE 0 END) AS Print3Pages
FROM
Company
GROUP BY
CompanyName
Pour MySQL, vous pouvez directement mettre des conditions dans la fonction SUM()
. Elle sera évaluée comme étant booléenne 0
ou 1
. compter en fonction de vos critères sans utiliser les instructions IF/CASE
SELECT
company_name,
SUM(action = 'EMAIL')AS Email,
SUM(action = 'PRINT' AND pagecount = 1)AS Print1Pages,
SUM(action = 'PRINT' AND pagecount = 2)AS Print2Pages,
SUM(action = 'PRINT' AND pagecount = 3)AS Print3Pages
FROM t
GROUP BY company_name
DEMO
Pour un pivot dynamique, utilisez GROUP_CONCAT
avec CONCAT
. La fonction GROUP_CONCAT concatène les chaînes d'un groupe en une chaîne avec diverses options.
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'SUM(CASE WHEN action = "',
action,'" AND ',
(CASE WHEN pagecount IS NOT NULL
THEN CONCAT("pagecount = ",pagecount)
ELSE pagecount IS NULL END),
' THEN 1 ELSE 0 end) AS ',
action, IFNULL(pagecount,'')
)
)
INTO @sql
FROM
t;
SET @sql = CONCAT('SELECT company_name, ', @sql, '
FROM t
GROUP BY company_name');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Une version de stardard-SQL utilisant logique booléenne :
SELECT company_name
, COUNT(action = 'EMAIL' OR NULL) AS "Email"
, COUNT(action = 'PRINT' AND pagecount = 1 OR NULL) AS "Print 1 pages"
, COUNT(action = 'PRINT' AND pagecount = 2 OR NULL) AS "Print 2 pages"
, COUNT(action = 'PRINT' AND pagecount = 3 OR NULL) AS "Print 3 pages"
FROM tbl
GROUP BY company_name;
Comment?
TRUE OR NULL
donne TRUE
.FALSE OR NULL
donne NULL
.NULL OR NULL
donne NULL
.
Et COUNT
ne compte que les valeurs non nulles. Voila.
Il existe un outil appelé générateur de tableaux croisés dynamiques MySQL, il peut vous aider à créer un tableau croisé dynamique basé sur le Web que vous pourrez ensuite exporter vers Excel (si vous le souhaitez). cela peut fonctionner si vos données se trouvent dans une seule table ou dans plusieurs tables.
Tout ce que vous avez à faire est de spécifier la source de données des colonnes (elle supporte les colonnes dynamiques), les lignes, les valeurs dans le corps de la table et la relation entre les tables (le cas échéant).
La page d'accueil de cet outil est http://mysqlpivottable.net
La réponse correcte est:
select table_record_id,
group_concat(if(value_name='note', value_text, NULL)) as note
,group_concat(if(value_name='hire_date', value_text, NULL)) as hire_date
,group_concat(if(value_name='termination_date', value_text, NULL)) as termination_date
,group_concat(if(value_name='department', value_text, NULL)) as department
,group_concat(if(value_name='reporting_to', value_text, NULL)) as reporting_to
,group_concat(if(value_name='shift_start_time', value_text, NULL)) as shift_start_time
,group_concat(if(value_name='shift_end_time', value_text, NULL)) as shift_end_time
from other_value
where table_name = 'employee'
and is_active = 'y'
and is_deleted = 'n'
GROUP BY table_record_id
select t3.name, sum(t3.prod_A) as Prod_A, sum(t3.prod_B) as Prod_B, sum(t3.prod_C) as Prod_C, sum(t3.prod_D) as Prod_D, sum(t3.prod_E) as Prod_E
from
(select t2.name as name,
case when t2.prodid = 1 then t2.counts
else 0 end prod_A,
case when t2.prodid = 2 then t2.counts
else 0 end prod_B,
case when t2.prodid = 3 then t2.counts
else 0 end prod_C,
case when t2.prodid = 4 then t2.counts
else 0 end prod_D,
case when t2.prodid = "5" then t2.counts
else 0 end prod_E
from
(SELECT partners.name as name, sales.products_id as prodid, count(products.name) as counts
FROM test.sales left outer join test.partners on sales.partners_id = partners.id
left outer join test.products on sales.products_id = products.id
where sales.partners_id = partners.id and sales.products_id = products.id group by partners.name, prodid) t2) t3
group by t3.name ;