简体   繁体   中英

SQL pivot query to get the result in a single row

I have a users table as

id  name  age 
1   a     20  
2   b     22  
3   c     23  

I have another user_custom_fields table as

id  user_id custom_field_id   value
1     1       1               ax   
2     1       2               ay   
3     1       3               az   
4     2       1               bx    
5     2       2               by   
6     2       3               bz   
7     3       1               cx   
8     3       2               cy   
9     3       3               cz   

and a third custom_fields table

id   field_name 
1     field1    
2     field2    
3     field3    

Here the problem is I need the result for each user in a single row with all the custom field_name as column header as

 user_id   name  age   field1  field2  field3 

 1         a     20     ax      ay     az     
 2         b     22     bx      by     bz     
 3         c     23     cx      cy     cz     

I have heard about pivot queries but I don't have much knowledge of SQL. Can anyone help me here how to do this

Update: I am using MySql Database

For DB SQL SERVER, you can try with this one

Select * from 
(Select c.user_id,u.name,u.age,c.value,f.field_name from users u
Inner join user_custom_fields c on u.id=c.user_id
inner join custom_fields f on f.id=c.custom_field_id) t
pivot(max(t.value) for t.field_name in([field1],[field2],[field3]) ) pv

If you require to use dynamic customer_field name, you can use below script

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(f.field_name) 
            FROM custom_fields f
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')        

set @query = 'Select * from 
(Select c.user_id,u.name,u.age,c.value,f.field_name from users u
Inner join user_custom_fields c on u.id=c.user_id
inner join custom_fields f on f.id=c.custom_field_id) t
pivot(max(t.value) for t.field_name in(' + @cols + ')) p '

execute(@query)

If you want same thing dynamic in MYSQL then you can use below query

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(      
    
       'Max(IF(custom_fields.field_name = ''',field_name,''', user_custom_fields.value, Null)) as ',field_name
    )
  ) INTO @sql
FROM custom_fields;

SET @sql = CONCAT('SELECT 
    u.id as user_id, 
    u.name, 
    u.age,', @SQL , 
    ' FROM Users u
    Inner Join user_custom_fields on user_custom_fields.user_id = u.id
    Inner Join custom_fields on custom_fields.id = user_custom_fields.custom_field_id
    Group by u.id
    order by u.id');
    
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

After a little more search I found one article where they have suggested alternative of pivot in mysql So the complete query will be

SELECT 
    u.id as user_id, 
    u.name, 
    u.age, 
    Max(IF(custom_fields.field_name = 'Field1', user_custom_fields.value, Null)) as 'Field 1',
    Max(IF(custom_fields.field_name = 'Field2',  user_custom_fields.value,Null)) as 'Field 2',
    Max(IF(custom_fields.field_name = 'Field3',  user_custom_fields.value,Null)) as 'Field 3'
    FROM user u
    Inner Join user_custom_fields on user_custom_fields.user_id = u.id
    Inner Join custom_fields on custom_fields.id = user_custom_fields.custom_field_id
    Group by u.id
    order by u.id

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM