我有以下结构:
CREATE TABLE person {
id INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30) NOT NULL,
email VARCHAR(30) NOT NULL UNIQUE
}
CREATE TABLE field {
id INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30) NOT NULL
}
CREATE TABLE fieldPerson {
id INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
fieldId INT(11) UNSIGNED,
personId INT(11) UNSIGNED,
value VARCHAR(30) NOT NULL,
FOREIGN KEY (fieldId) REFERENCES field(id),
FOREIGN KEY (personId) REFERENCES person(id)
}
总结如此。基本上我们有默认字段name
和email
,我们可以选择创建自定义字段,例如telephone
,address
等。
我们可以有 n 字段。我试图找出一种方法来执行SELECT
查询,该查询返回所有字段而不使用子查询或数据库外的额外工作(但是可以使用连接)。
示例(电话是自定义字段):
TABLE person:
id name email
1 Test 1 test1@gmail.com
----
TABLE field:
id name
1 telephone
2 address
----
TABLE fieldPerson:
id fieldId personId value
1 1 1 +1 555 555 555
2 2 1 First St.
----
RESULTING QUERY
personId name email telephone Address
1 Test 1 test1@gmail.com +1 555 555 555 First St.
这可能吗?
感谢。
编辑:
如果不可能,您可以建议使用子查询的最佳解决方案,但只能使用SQL。
答案 0 :(得分:3)
因此,根据您对查询生成的控制程度,如果您可以按照与SELECT
PRIMARY KEY
相同的顺序生成field
列,则可以尝试以下。我想象你知道field
中有2个键的内容,以及它们之前的内容(来自之前的查询?)。
SELECT fp.personId,p.name,p.email,fp.value as telephone,fp2.value as Address
FROM fieldPerson fp INNER JOIN person p ON p.id = fp.personId
INNER JOIN field f ON f.id = fp.fieldId
INNER JOIN fieldPerson fp2
WHERE fp.fieldId = 1 and fp2.fieldId = 2;
考虑到问题中的样本数据,这给了我结果:
personId | name | email | telephone | Address |
1 | Test 1 | test1@gmail.com | +1 555 555 555 | First St. |
这取决于您通过先前进行初始查询以了解fields
表中定义的任意字段来避免子查询的概念。你没有说明这个表的动态程度,所以这可能不是一个不合理的简化假设。
除此之外,您可以尝试以下方式:
SELECT fp.personId,p.name,p.email,fp.value as telephone,fp2.value as Address
FROM fieldPerson fp INNER JOIN person p ON p.id = fp.personId
INNER JOIN field f ON f.id = fp.fieldId
INNER JOIN fieldPerson fp2
WHERE fp.fieldId != fp2.fieldId LIMIT 1,1;
这给了我相同的输出而不必知道字段id号,但我确实需要知道字段的名称来生成列名。我同意,LIMIT
可以删除其中一个JOIN
产品,并且有一种明显不圣洁的感觉。我觉得接近2并没有太大的优势,因为你必须知道列名。
我同意@Mojtaba,但是,如果您不能使用预先查询来了解动态字段名称和ID,那么我相信您将不得不放置子其中的SELECT
语句可以在查询时提取这些语句。
答案 1 :(得分:2)
SELECT p.*
, group_concat(CASE f.name WHEN 'telephone' THEN fp.value END) telephone
, group_concat(CASE f.name WHEN 'address' THEN fp.value END) address
FROM person p
JOIN field f
LEFT JOIN fieldPerson fp
ON fp.personId = p.id
AND fp.fieldId = f.id
GROUP BY p.id