行在视图中表示为列

时间:2013-05-05 19:15:30

标签: mysql

对于我的感觉,我有一种创造性的方法来保存用户数据。让我解释一下:

我不知道将在此数据库中保存哪些数据。例如,有人想保存他的icq号码,之前我不知道,在哪里可以写入?他动态创建一个新字段,在后台有fields中的插入和user_fields中的插入,其中存储了新选项的新值。

user

id  username
1   rauchmelder

fields

id  name
1   firstname
2   lastname

user_fields :(存储旧值以及当前,只应使用最年轻的条目)

id  user_id  fields_id  value        date
1   1        1          Chris        1.Mai
1   1        2          Rauch        1.Mai
1   1        1          Christopher  2.Mai

结果应该是一个视图:

user.id  user.username   fields.firstname  fields.lastname
1        rauchmelder     Christopher       Rauch

首先,它有意义吗?

其次,我应该在MySQL中还是在应用程序中解决它?

三,如何在MySQL中解决这个问题?

1 个答案:

答案 0 :(得分:3)

为了将数据放入列中,您可以使用带有CASE表达式的聚合函数将行数据转换为列。

如果您的fields提前知道,那么您可以对查询中的值进行硬编码:

select u.id,
  u.username,
  max(case when f.name = 'firstname' then uf.value end) firstname,
  max(case when f.name = 'lastname' then uf.value end) lastname
from user u
left join
(
  select uf1.*
  from user_fields uf1
  inner join
  (
    select max(date) maxDate, user_id, fields_id
    from user_fields
    group by user_id, fields_id
  ) uf2
    on uf1.date = uf2.maxdate
    and uf1.user_id = uf2.user_id
    and uf1.fields_id = uf2.fields_id
) uf
  on u.id = uf.user_id
left join fields f
  on uf.fields_id = f.id
group by u.id, u.username;

请参阅SQL Fiddle with Demo

但是由于您将拥有未知字段,因此您需要使用prepared statement来生成要执行的动态SQL。语法类似于:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(CASE WHEN f.name = ''',
      name,
      ''' THEN uf.value END) AS `',
      name, '`'
    )
  ) INTO @sql
FROM fields;


SET @sql 
  = CONCAT('SELECT u.id,
            u.username, ', @sql, ' 
           from user u
           left join
           (
             select uf1.*
             from user_fields uf1
             inner join
             (
               select max(date) maxDate, user_id, fields_id
               from user_fields
               group by user_id, fields_id
             ) uf2
               on uf1.date = uf2.maxdate
               and uf1.user_id = uf2.user_id
               and uf1.fields_id = uf2.fields_id
           ) uf
             on u.id = uf.user_id
           left join fields f
             on uf.fields_id = f.id
           group by u.id, u.username');

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

请参阅SQL Fiddle with Demo