对于我的感觉,我有一种创造性的方法来保存用户数据。让我解释一下:
我不知道将在此数据库中保存哪些数据。例如,有人想保存他的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中解决这个问题?
答案 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;
但是由于您将拥有未知字段,因此您需要使用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;