mysql - 将表行连接到列中,列标题来自原始行

标签 mysql stored-procedures dynamic-sql

我有三个简化的 MYSQL 表,带有以下列:

ModuleEntries (MDE_ID)
ModuleFields (MDF_ID, MDF_Label)
ModuleEntryFieldValues (MFV_ID, MFV_MDE_ID, MFV_MDF_ID, MFV_Value)

正如您从简化的列列表中看到的,ModuleEntryFieldValues 是一个表格,其中规定“对于一个条目,此字段具有此值”。

现在,我想在一个“平面”记录集中检索此信息。我已经设法让事情正常运转,但并不完全达到我想要的效果。

在另一篇 SO 文章的帮助下,我成功地通过使用游标使动态、可变数量的列发挥作用。

  declare finish int default 0;
  declare fldid int;
  declare str varchar(10000) default 'SELECT *,';
  declare curs cursor for select MDF_ID from ModuleFields group by MDF_ID;
  declare continue handler for not found set finish = 1;
  open curs;
  my_loop:loop
    fetch curs into fldid;
    if finish = 1 then
      leave my_loop;
    end if;
    set str = concat(str, 'max(case when MFV_MDF_ID = ',fldid,' then MFV_Value else null end) as field_',fldid,',');
  end loop;
  close curs;
  set str = substr(str,1,char_length(str)-1);
  set @str = concat(str, ' from ModuleEntries LEFT join ModuleEntryFieldValues ON MDE_ID = MDF_MDE_ID GROUP BY MDE_ID');
  prepare stmt from @str;
  execute stmt;
  deallocate prepare stmt;
此代码做的是允许我将MDF_Label 的列值作为行的实际列标题。现在,上面的代码给了我“field_1,field_2,...”

是否可以连接这三个表,并将 MDF_Label 作为现在作为连接表中的列的行的列标题?

我想要这个...

ModuleEntries  |   ModuleFields         |   ModuleEntryFieldValues
-------------  |   ------------------   |   -----------------------------------
MDE_ID         |   MDF_ID - MDF_Label   |   MFV_MDE_ID - MFV_MDF_ID - MFV_Value
1              |   1      - Height      |   1          - 1          - 120cms
               |   2      - Width       |   1          - 2          - 30cms
               |   3      - Weight      |   

进入此

Recordset
---------
MDE_ID - Height - Width - Weight
1      - 120cms - 30cms - null

我希望我的问题足够清楚。如果没有,请发表评论,如果可以的话,我会在需要时提供更多信息。

最佳答案

我只想使用 GROUP_CONCAT()而不是游标来生成准备好的语句:

SELECT CONCAT(
 ' SELECT MDE_ID,'

,  GROUP_CONCAT(
     't', MDF_ID, '.MFV_Value AS `', REPLACE(MDF_Label, '`', '``'), '`'
   )

,' FROM ModuleEntries '

, GROUP_CONCAT(
    'LEFT JOIN ModuleEntryFieldValues AS t', MDF_ID, '
       ON t', MDF_ID, '.MFV_MDE_ID = ModuleEntries.MDE_ID
      AND t', MDF_ID, '.MFV_MDF_ID = ', MDF_ID
  SEPARATOR ' ')

) INTO @qry FROM ModuleFields;

保存空白编辑以使其更具可读性,示例数据@qry将包含:

SELECT MDE_ID,
       t1.MFV_Value AS `Height`,
       t2.MFV_Value AS `Width`,
       t3.MFV_Value AS `Weight`
FROM   ModuleEntries
  LEFT JOIN ModuleEntryFieldValues AS t1
         ON t1.MFV_MDE_ID = ModuleEntries.MDE_ID AND t1.MFV_MDF_ID = 1
  LEFT JOIN ModuleEntryFieldValues AS t2
         ON t2.MFV_MDE_ID = ModuleEntries.MDE_ID AND t2.MFV_MDF_ID = 2
  LEFT JOIN ModuleEntryFieldValues AS t3
         ON t3.MFV_MDE_ID = ModuleEntries.MDE_ID AND t3.MFV_MDF_ID = 3

然后可以准备并执行该语句:

PREPARE stmt FROM @qry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @qry = NULL;

这会产生以下结果:

MDE_ID    Height    Width    Weight
     1    120cms    30cms    (null)

查看 sqlfiddle .

关于mysql - 将表行连接到列中,列标题来自原始行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10677700/

相关文章:

sql - pgplsql 存储过程的性能?

sql-server - 如何编辑存储过程?

sql-server - 嵌入在选择查询中的动态 SQL

mysql - Rails 2.3.8 has_many :through

mysql - MVC 在 Razor DropdownlistFor 中设置默认值,该值绑定(bind)到数据库

mysql - Laravel 选择位置/计数查询

MySql 存储过程 else if 和多查询

mysql - 使用 MAX() 优化 MySQL 查询

sql-server - 使用动态查询在 openquery 中转义单引号

sql-server - 使用params在另一个数据库中执行存储过程