MySQL 加入后按字段名提取值的子查询
MySQL subquery to pull values by fieldname after join
我正在尝试在 MySQL 中创建一个连接,它将根据字段名从另一个 table 中提取值。我有这 2 tables:
TABLE_MAIN:
ID
EVENTID
FIELDNAME
1
1
FIELD1
2
1
FIELD2
3
1
FIELD3
4
2
FIELD1
5
3
FIELD2
TABLE_FIELDS:
EVENTID
FIELD1
FIELD2
FIELD3
1
Some value
text
value
2
foo
bar
text
3
differentValue
more
text
我正在尝试创建类似下面的东西,我显然不能用普通的连接来做:
ID
EVENTID
FIELDNAME
VALUE
1
1
FIELD1
Some value
2
1
FIELD2
text
3
1
FIELD3
value
4
2
FIELD1
foo
5
3
FIELD2
more
我开始像这样进行简单的连接:
SELECT * FROM TABLE MAIN LEFT JOIN TABLE_FIELDS ON TABLE_MAIN.EVENTID = TABLE_FIELDS.EVENTID
然而,这会引入完整的 table,我如何才能只引入在字段名中指定的字段?
谢谢!
罗伯特
您需要 case
表达式以及 join
:
select m.*,
(case when m.fieldname = 'FIELD1' then f.field1
when m.fieldname = 'FIELD2' then f.field2
when m.fieldname = 'FIELD3' then f.field3
end) as value
from table_main m left join
table_fields f
on m.eventid = f.eventid;
您真的应该修复数据模型,以便可以使用联接。如果第二个字段的每个值都在单独的 行 中,您可以只使用常规联接。
有一种 运行 动态 SQL 的方法,但除非万不得已,否则我绝对不会推荐它。我会采纳 Linoff 先生的建议,即重新设计数据库结构,以便避免这种情况。但是,您可以通过以下方式动态生成 Linoff 先生的查询:
SELECT CONCAT(
"select m.*, (case ",
group_concat(distinct CONCAT("WHEN m.fieldname = '", FIELDNAME, "' then f.", FIELDNAME) SEPARATOR " "),
" end) as value ",
" from TABLE_MAIN m left join "
" TABLE_FIELDS f "
" on m.eventid = f.eventid; "
) INTO @stmt
FROM TABLE_MAIN;
SELECT @stmt;
PREPARE stmt FROM @stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
我无法提供 SQL fiddle 来演示,因为我不知道允许动态 sql 执行的 fiddle。我确实使用您的样本数据在本地对其进行了测试,结果如下:
再次强调,不要这样做。有时这是不可避免的,但我认为你可能比处理动态 SQL 更容易调整你的结构。我意识到这不是一个好的解决方案,我不推荐它。
我正在尝试在 MySQL 中创建一个连接,它将根据字段名从另一个 table 中提取值。我有这 2 tables:
TABLE_MAIN:
ID | EVENTID | FIELDNAME |
---|---|---|
1 | 1 | FIELD1 |
2 | 1 | FIELD2 |
3 | 1 | FIELD3 |
4 | 2 | FIELD1 |
5 | 3 | FIELD2 |
TABLE_FIELDS:
EVENTID | FIELD1 | FIELD2 | FIELD3 |
---|---|---|---|
1 | Some value | text | value |
2 | foo | bar | text |
3 | differentValue | more | text |
我正在尝试创建类似下面的东西,我显然不能用普通的连接来做:
ID | EVENTID | FIELDNAME | VALUE |
---|---|---|---|
1 | 1 | FIELD1 | Some value |
2 | 1 | FIELD2 | text |
3 | 1 | FIELD3 | value |
4 | 2 | FIELD1 | foo |
5 | 3 | FIELD2 | more |
我开始像这样进行简单的连接:
SELECT * FROM TABLE MAIN LEFT JOIN TABLE_FIELDS ON TABLE_MAIN.EVENTID = TABLE_FIELDS.EVENTID
然而,这会引入完整的 table,我如何才能只引入在字段名中指定的字段? 谢谢! 罗伯特
您需要 case
表达式以及 join
:
select m.*,
(case when m.fieldname = 'FIELD1' then f.field1
when m.fieldname = 'FIELD2' then f.field2
when m.fieldname = 'FIELD3' then f.field3
end) as value
from table_main m left join
table_fields f
on m.eventid = f.eventid;
您真的应该修复数据模型,以便可以使用联接。如果第二个字段的每个值都在单独的 行 中,您可以只使用常规联接。
有一种 运行 动态 SQL 的方法,但除非万不得已,否则我绝对不会推荐它。我会采纳 Linoff 先生的建议,即重新设计数据库结构,以便避免这种情况。但是,您可以通过以下方式动态生成 Linoff 先生的查询:
SELECT CONCAT(
"select m.*, (case ",
group_concat(distinct CONCAT("WHEN m.fieldname = '", FIELDNAME, "' then f.", FIELDNAME) SEPARATOR " "),
" end) as value ",
" from TABLE_MAIN m left join "
" TABLE_FIELDS f "
" on m.eventid = f.eventid; "
) INTO @stmt
FROM TABLE_MAIN;
SELECT @stmt;
PREPARE stmt FROM @stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
我无法提供 SQL fiddle 来演示,因为我不知道允许动态 sql 执行的 fiddle。我确实使用您的样本数据在本地对其进行了测试,结果如下:
再次强调,不要这样做。有时这是不可避免的,但我认为你可能比处理动态 SQL 更容易调整你的结构。我意识到这不是一个好的解决方案,我不推荐它。