【问题标题】:MySQL Join horizontal with vertical tableMySQL Join 水平与垂直表
【发布时间】:2017-07-04 16:41:39
【问题描述】:

我有以下结构:

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)
}

总结得很好。基本上我们有默认字段nameemail,我们可以选择创建自定义字段,例如telephoneaddress 等。 我们可以有 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。

【问题讨论】:

  • 但我猜JOIN是不可避免的。
  • 当然,JOIN 没问题,只是不想依赖子查询(SELECT ...) AS ...
  • 不,字段只有一个名称列。我需要收集它的值并用作列名。
  • 更新您的问题,添加真实的数据样本
  • @scaisEdge 刚刚更新。

标签: mysql sql join


【解决方案1】:

因此,根据您对查询生成的控制程度,如果您可以按照与fieldPRIMARY KEY 相同的顺序生成SELECT 列,您可以尝试以下操作。我正在设想一些事情,您知道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,那么我相信您将不得不放入 sub-SELECT 语句在那里在查询时提取那些。

【讨论】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-04
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 2010-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多