【问题标题】:MySQL Query INNER JOIN with aliasesMySQL 使用别名查询 INNER JOIN
【发布时间】:2016-06-26 20:34:07
【问题描述】:

我有两张桌子:usersusers_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            |
+----+----------+-------+----+--------+----------+---------------+

显然我不需要users_info 结果的id,我希望每个info_key 都是“别名”(或列名),每个info_val 都是那个“别名”的值”。

【问题讨论】:

  • 您不能编写一个可以动态生成不同列数的 SQL 语句。您需要创建一个程序来查找任何给定父级的可用 info_key,然后动态生成 SQL 语句以根据您的喜好格式化数据。您的问题之前已提出 - search for dynamic EAV
  • 向我们展示您的期望,更正您的查询会更容易。只需创建另一个数组
  • MySQL - Rows to Columns的可能重复
  • 我可以在你调用的存储过程中做到这一点,比如call uspGetStuff('kris@kris.com'); ... 1 行输出,你想要的水平。尽我所能。

标签: mysql join inner-join entity-attribute-value


【解决方案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

SQLFiddle DEMO HERE

如果你有一个动态的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;

SQLFiddle DEMO HERE

【讨论】:

    【解决方案2】:

    这利用架构中的更改来支持返回数据的转换。它取决于存储过程的使用。

    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 调用,数据将以其本机预期数据类型返回。这意味着您可以直接处理它。

    【讨论】:

      猜你喜欢
      • 2012-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-02
      • 2013-12-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多