MySQL 使用别名查询 INNER JOIN
MySQL Query INNER JOIN with aliases
我有两个表: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'
- 和 -
return 所有 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')
它 return 是这个结果:
+----+----------+-------+----+--------+----------+---------------+
| 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 |
+----+----------+-------+----+--------+----------+---------------+
显然我不需要 users_info
结果的 id
并且我希望每个 info_key
是 "alias" (或列名)并且每个 info_val
成为 "alias".
的值
对于这种情况,您可以这样做;) 只是一个简单的 table 枢轴。
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;
这利用架构中的更改来支持转换 返回的数据。它取决于存储过程的使用。
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 (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
-- (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 |
+----+------+------+-----+------------+-------------------+-----------+
由于 cast
调用嵌入在 select 中,数据将返回其原始的预期数据类型。这意味着您可以直接处理它。
我有两个表: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'
- 和 -
return 所有 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')
它 return 是这个结果:
+----+----------+-------+----+--------+----------+---------------+
| 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 |
+----+----------+-------+----+--------+----------+---------------+
显然我不需要 users_info
结果的 id
并且我希望每个 info_key
是 "alias" (或列名)并且每个 info_val
成为 "alias".
对于这种情况,您可以这样做;) 只是一个简单的 table 枢轴。
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;
这利用架构中的更改来支持转换 返回的数据。它取决于存储过程的使用。
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 (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
-- (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 |
+----+------+------+-----+------------+-------------------+-----------+
由于 cast
调用嵌入在 select 中,数据将返回其原始的预期数据类型。这意味着您可以直接处理它。