2013-01-11 1 views
1

je le schéma comme ce qui suit:table MySQL orthogonale tour

CREATE TABLE prop_set (
     id INT UNSIGNED NOT NULL AUTO_INCREMENT, 
     name varchar(255), 
     PRIMARY KEY (id) 
); 
CREATE TABLE users_props (
     user_id int UNSIGNED NOT NULL, 
     prop_id int UNSIGNED NOT NULL, 
     value text, 
     PRIMARY KEY (user_id,prop_id) 
); 
CREATE TABLE user (
     id INT UNSIGNED NOT NULL AUTO_INCREMENT, 
     name varchar(255), 
     PRIMARY KEY (id) 
); 

INSERT INTO prop_set SET name="prop1"; 
INSERT INTO prop_set SET name="prop2"; 
INSERT INTO prop_set SET name="prop3"; 


INSERT INTO user SET name="user1"; 
INSERT INTO user SET name="user2"; 

INSERT INTO users_props set user_id=1,prop_id=1,value="prop1 user1"; 
INSERT INTO users_props set user_id=1,prop_id=2,value="prop2 user1"; 
INSERT INTO users_props set user_id=1,prop_id=3,value="prop3 user1"; 

INSERT INTO users_props set user_id=2,prop_id=1,value="prop1 user2"; 
INSERT INTO users_props set user_id=2,prop_id=2,value="prop2 user2"; 
INSERT INTO users_props set user_id=2,prop_id=3,value="prop3 user2"; 

maintenant je lance le select comme suit:

SELECT u.name,ps.name AS prop,up.value 
     FROM USER u 
     JOIN users_props up ON u.id=up.user_id 
     JOIN prop_set ps ON ps.id=up.prop_id; 

et obtenir une sortie:

| NAME | PROP |  VALUE | 
------------------------------- 
| user1 | prop1 | prop1 user1 | 
| user2 | prop1 | prop1 user2 | 
| user1 | prop2 | prop2 user1 | 
| user2 | prop2 | prop2 user2 | 
| user1 | prop3 | prop3 user1 | 
| user2 | prop3 | prop3 user2 | 

fiddle Est-il possible de faire mysql pour retourner la sortie suivante?

| NAME | prop1  |  prop2 | prop3 | 
--------------------------------------------------- 
| user1 | prop1 user1 | prop2 user1 | prop3 user1 | 
| user2 | prop1 user2 | prop2 user2 | prop3 user2 | 

Je cherche la solution mysql-only.

+0

Les données d'échantillon pour 'prop3' ne correspond pas au résultat souhaité final - les valeurs sont différentes. Est-ce une faute de frappe? – Taryn

+0

typo dans la requête, va corriger maintenant –

Répondre

3

Le pivot syntaxe de MySQL utilise une fonction d'agrégation avec une instruction CASE semblable à ceci:

SELECT u.name, 
    max(case when ps.name = 'prop1' then up.value else null end) Prop1, 
    max(case when ps.name = 'prop2' then up.value else null end) Prop2, 
    max(case when ps.name = 'prop3' then up.value else null end) Prop3 
FROM user u 
JOIN users_props up 
    ON u.id=up.user_id 
JOIN prop_set ps 
    on ps.id=up.prop_id 
GROUP BY u.name; 

Voir SQL Fiddle with Demo

Les travaux ci-dessus Si vous avez des valeurs connues pour transposer en colonnes, mais si les valeurs sont inconnues, alors vous voudrez regarder à l'aide d'un prepared statement pour générer le SQL dynamique:

SET @sql = NULL; 
SELECT 
    GROUP_CONCAT(DISTINCT 
    CONCAT(
     'max(case when ps.name = ''', 
     name, 
     ''' then up.value else null end) AS ''', 
     name, '''' 
    ) 
) INTO @sql 
FROM prop_set; 

SET @sql = CONCAT('SELECT u.name, ', @sql, ' 
        FROM user u 
        JOIN users_props up 
        ON u.id=up.user_id 
        JOIN prop_set ps 
        on ps.id=up.prop_id 
        GROUP BY u.name'); 

PREPARE stmt FROM @sql; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 

Voir SQL Fiddle with Demo

Le résultat est le même avec les deux versions:

| NAME |  PROP1 |  PROP2 |  PROP3 | 
--------------------------------------------------- 
| user1 | prop1 user1 | prop2 user1 | prop3 user1 | 
| user2 | prop1 user2 | prop2 user2 | prop3 user2 | 
+0

Il est possible de ne pas utiliser Prop1, Prop2, Prop3, etc dans la requête? prop_set peut gérer 10-20 propriétés dans une application réelle. Et l'idée n'est pas de les garder en dur. –

+1

Je travaille sur une version dynamique à ce stade. :) – Taryn

+1

@eicto voir mon édition montrant une version dynamique en utilisant des instructions préparées. – Taryn