我有两张表:users
和users_info
users
看起来像这样:
+----+----------+-------+
| id | slug | name |
+----+----------+-------+
| 1 | theploki | Kris |
+----+----------+-------+
和users_info
看起来像这样:
+----+--------+----------+---------------+
| id | parent | info_key | info_val |
+----+--------+----------+---------------+
| 1 | 1 | email | kris@kris.com |
+----+--------+----------+---------------+
| 2 | 1 | age | 28 |
+----+--------+----------+---------------+
我想SELECT
user
user_info
发送电子邮件=' kris@kris.com'
- 和 -
返回所有user_info
值和users
值
这是我正在寻找的结果:
+----+----------+-------+---------------+-----+
| id | slug | name | email | age |
+----+----------+-------+---------------+-----+
| 1 | theploki | Kris | kris@kris.com | 28 |
+----+----------+-------+---------------+-----+
到目前为止,我最接近的是查询:
SELECT users.*, users_info.* FROM users
INNER JOIN users_info on users_info.parent = users.id
where users.id = (SELECT users_info.parent FROM users_info
WHERE users_info.parent = users.id
AND users_info.info_val = 'kris@kris.com')
并返回此结果:
+----+----------+-------+----+--------+----------+---------------+
| id | slug | name | id | parent | info_key | info_val |
+----+----------+-------+----+--------+----------+---------------+
| 1 | theploki | Kris | 1 | 1 | email | kris@kris.com |
+----+----------+-------+----+--------+----------+---------------+
| 1 | theploki | Kris | 2 | 1 | age | 28 |
+----+----------+-------+----+--------+----------+---------------+
显然,我不需要id
结果的users_info
,我希望每个info_key
成为"别名" (或列名称),并且每个info_val
都是"别名"的值。
答案 0 :(得分:1)
对于这种情况,您可以这样做;)只是一个简单的表格枢轴。
select
users.id,
users.slug,
users.name,
max(if(users_info.info_key = 'email', users_info.info_val, null)) as email,
max(if(users_info.info_key = 'age', users_info.info_val, null)) as age
from users
inner join users_info
on users.id = users_info.parent
group by users.id
如果你有动态info_key
,你需要一个动态的sql来做这个,在这里我给你一个样本。
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(if(users_info.info_key = ''',
users_info.info_key,
''', users_info.info_val, null)) as ',
users_info.info_key
)
) INTO @sql
FROM users
inner join users_info
on users.id = users_info.parent
;
SET @sql = CONCAT('select users.id, users.slug, users.name, ', @sql, ' FROM users
inner join users_info group by users.id having email = \'kris@kris.com\'');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
答案 1 :(得分:1)
这利用架构中的更改来支持投射返回的数据。它取决于存储过程的使用。
group_concat
的最大值取决于您对以下变量的设置(通常默认默认值较低,如1K):
set session group_concat_max_len = 20000;
将该通话嵌入BEGIN下存储过程的顶部。手册页为here。价值可能很大。例如,至少4GB。
drop table if exists users;
create table users
(
id int auto_increment primary key,
slug varchar(100) not null,
name varchar(100) not null
-- other indexes here like uniqueness, etc (btw none added)
);
drop table if exists users_info;
create table users_info
(
id int auto_increment primary key,
parent int not null,
info_key varchar(100) not null,
info_val varchar(100) not null,
datatype varchar(100) not null, -- see http://stackoverflow.com/a/8537070/ (DATA TYPES)
-- other indexes here (btw none added)
-- FK below:
foreign key `ui_2_users_9283` (parent) references users(id) -- I guess
);
加载测试数据;
-- delete from users; -- note truncate disallowed on parent with an FK (so delete !)
insert users(slug,name) values
('theploki','Kris'),
('Yoda','Yoda');
-- select * from users;
-- truncate table users_info;
insert users_info(parent,info_key,info_val,datatype) values
(1,'email','kris@kris.com','char(100)'),
(1,'age','28','unsigned'),
(2,'birthdate','1996-02-14','date'),
(2,'email','yoda@starwars.com','char(100)'),
(2,'networth','102504.12','decimal(12,2)'),
(2,'age','910','unsigned');
存储过程:
drop procedure if exists fetchInfoKeysByEmailAddr;
DELIMITER $$
create procedure fetchInfoKeysByEmailAddr(emailAddr varchar(100))
BEGIN
set @parentid=-1;
select parent into @parentid
from users_info
where info_key='email' and info_val=emailAddr;
if @parentid>0 then
-- http://stackoverflow.com/a/8537070/ (DATA TYPES)
SELECT GROUP_CONCAT(concat('cast("',info_val,'" as ',datatype,') as ',info_key)
ORDER BY info_key SEPARATOR ',') into @tail
FROM users_info
where parent=@parentid
GROUP BY parent;
set @final:=concat("select id,slug,name,",@tail,' from users where id=',@parentid);
PREPARE stmt1 FROM @final;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
end if;
END$$
DELIMITER ;
测试:
call fetchInfoKeysByEmailAddr('x');
-- user info does not exist, empty (todo: change accordingly)
call fetchInfoKeysByEmailAddr('kris@kris.com');
+----+----------+------+-----+---------------+
| id | slug | name | age | email |
+----+----------+------+-----+---------------+
| 1 | theploki | Kris | 28 | kris@kris.com |
+----+----------+------+-----+---------------+
call fetchInfoKeysByEmailAddr('yoda@starwars.com');
+----+------+------+-----+------------+-------------------+-----------+
| id | slug | name | age | birthdate | email | networth |
+----+------+------+-----+------------+-------------------+-----------+
| 2 | Yoda | Yoda | 910 | 1996-02-14 | yoda@starwars.com | 102504.12 |
+----+------+------+-----+------------+-------------------+-----------+
由于select中嵌入了cast
调用,数据将以其本机预期数据类型返回。这意味着你可以直接使用它。