【问题标题】:Grab content from 2 tables?从 2 个表格中获取内容?
【发布时间】:2011-11-05 17:14:40
【问题描述】:

我想要一个查询从特定用户添加了行的 2 个不同表中获取结果。所以我的 2 个表如下所示:

地址

  • 身份证
  • 地址
  • user_id

电子邮件

  • 身份证
  • 电子邮件
  • user_id

所以,我想从 user_id 行等于 1 的两个表中提取内容。对于上下文,假设每个用户可以向站点添加多个地址和电子邮件,我想将它们全部抓取并显示在他们的个人资料页面上。

所以我尝试了这个:

SELECT *  
  FROM addresses
  JOIN emails USING (user_id) 
 WHERE user_id = '1'

但这不起作用 - 它要么从第一个表中返回每行的 2 个,要么什么都不返回。 我也试过这个:

SELECT * 
  FROM addresses, 
       emails 
 WHERE user_id = '1'

但这也不会返回任何内容。

【问题讨论】:

  • 应该是关于不明确的列引用的错误,因为user_id 存在于两个表中。第二个查询是笛卡尔积,而不是 JOIN...user_id 的数据类型是什么?
  • 抱歉,这不是 INNER JOINS 的重点吗?让两个表中都存在行?如果两个表中都不存在,我怎么能在一个列上加入 2 个表?
  • user_id 的数据类型也是 INT。
  • 笛卡尔积!= 加入 - 请参阅:codinghorror.com/blog/2007/10/…
  • 感谢您的链接。不过还是有点迷茫。可以使用内部联接完成我想做的事情吗?我觉得第一个查询是合乎逻辑的。似乎从 2 个表中抓取一列等于特定内容的表应该不会非常困难。

标签: php mysql sql


【解决方案1】:

试试

"SELECT * FROM table1 INNER JOIN table2 USING (user_id) WHERE user_id = '1'"

那就试试这个

SELECT address.table1 , email.table2 FROM table1 INNER JOIN table2 ON id.table1 ='1'

【讨论】:

  • 抱歉忘记了在我的原始代码中(将编辑),1 在撇号中,但它不会改变结果。
  • 第二个查询也不返回任何内容。我对此感到非常困惑。
  • 试试这个 :) SELECT address.table1 , email.table2 FROM table1 INNER JOIN table2 ON id.table1 = id.table2 WHERE id.table1 ='1'
  • 不幸的是仍然没有返回:/
【解决方案2】:
SELECT table1.*,table2.*
FROM table1 INNER JOIN 
     table2 ON table1.user_ID = table2.user_id
Where table1.user_id = 1

来自输入

table1:                        table2

id  user_id  address           id    user_id   email
----------------------         ----------------------
1   1        Add1              1       1       Email1
2   1        Add2              2       1       Email2
3   2        Add3              3       2       Email3
4   2        Add4              4       3       Email4

预期输出

id  user_id address    id      user_id email
----------------------------------------------
1   1       Add1       1       1       Email1
2   1       Add2       1       1       Email1
1   1       Add1       2       1       Email2
2   1       Add2       2       1       Email2

【讨论】:

  • 由于某种原因,这会将 Table1 中的每一行返回两次。
  • 它是否返回任何表 2 信息?表1和表2是一一对应的关系吗?
  • @John:table1 重复是因为 table2 中有 2+ 记录与 table1 记录相关联。这就是在父级关联多个子级记录的情况下使用 JOIN 的现实。
  • @JohnP 不,不返回任何 table2 信息。每个表共享的唯一内容是同一个用户可以为每个表添加多行。虽然,每个中的 user_id 列都引用了一个单独的“用户”表,其中包含用户名等。所以我不相信它在技术上是一对一的。
  • @OMGPonies 是的,我绝对意识到它正在返回 table1 行的重复。但我想不出一种可行的方法。
【解决方案3】:

这是一个使用笛卡尔积的查询

SELECT A.*,B.* FROM
(SELECT address FROM addresses WHERE user_id = 1) A,
(SELECT email FROM emails WHERE user_id = 1) B;

这是一个使用 INNER JOIN 的查询

SELECT A.*,B.* FROM
(SELECT address FROM addresses WHERE user_id = 1) A
INNER JOIN
(SELECT email FROM emails WHERE user_id = 1) B
USING (user_id);

对这两个查询都进行了重构,以分别引入一行。在搜索 user_id 1 之前无需将整个数据集放在一起。

需要注意的一点:请让用户 user_id 在两个表中都有索引:

ALTER TABLE addresses ADD INDEX (user_id);
ALTER TABLE emails    ADD INDEX (user_id);

这里是别的东西:如果 user_id 1 有多个地址和/或多个电子邮件,这两个查询应该是这样的:

多个地址/多个电子邮件的笛卡尔积

SELECT A.*,B.* FROM
(SELECT GROUP_CONCAT(address) AddressList FROM addresses WHERE user_id = 1) A,
(SELECT GROUP_CONCAT(email) EmailList FROM emails WHERE user_id = 1) B;

多个地址/多个电子邮件的 INNER JOIN

SELECT A.*,B.* FROM
(SELECT GROUP_CONCAT(address) AddressList FROM addresses WHERE user_id = 1) A
INNER JOIN
(SELECT GROUP_CONCAT(email) EmailList FROM emails WHERE user_id = 1) B
USING (user_id);

试试看!!!

更新 2011-08-29 11:52 EDT

因为不能保证 user_id 会同时具有地址和电子邮件地址。您必须执行 LEFT JOIN 而不是 INNER JOIN,因为 LEFT JOIN 必须支持至少一个现有的实体,而不是 INNER JOIN 强制一个具有两个实体的 user_id。尝试以下方法之一:

SELECT
    A.ListOfAddresses AddressList,
    IFNULL(B.ListOfEmails,'<No Email Address>') EmailList
FROM
    (SELECT GROUP_CONCAT(address) ListOfAddresses FROM addresses WHERE user_id = 1) A
    LEFT JOIN
    (SELECT GROUP_CONCAT(email) ListOfEmails FROM emails WHERE user_id = 1) B
USING (user_id);

SELECT
    IFNULL(B.ListOfAddresses,'<No Address>') AddressList,
    A.ListOfEmails EmailList
FROM
    (SELECT GROUP_CONCAT(email) ListOfEmails FROM emails WHERE user_id = 1) A
    LEFT JOIN
    (SELECT GROUP_CONCAT(address) ListOfAddresses FROM addresses WHERE user_id = 1) B
USING (user_id);

【讨论】:

  • 谢谢,但不幸的是,最后两个都没有给我任何回报。
【解决方案4】:

根据问题下方的 cmets,问题实际上似乎是关于根据共同标准对不同表中的行进行排序。

除了拥有单独的 SELECT 并在客户端执行排序之外,数据库服务器还可以为您执行排序,大致如下:

SELECT *
FROM (
    SELECT
        id addresses_id,
        address address_addresses,
        NULL emails_id,
        NULL emails_email,
        time
    FROM
        addresses
    WHERE
        user_id = 1
    UNION ALL
    SELECT
        NULL addresses_id,
        NULL address_addresses,
        id emails_id,
        email emails_email,
        time
    FROM
        emails
    WHERE
        user_id = 1
)
ORDER BY
    time -- Column not mentioned in question.

注意:一些返回的行的末尾会有 NULL(这些来自 addresses 表)和一些在前面(这些来自emails)。

这个 UNION 相当丑陋,但每张新表都会变得更丑...

【讨论】:

  • 啊哈奇怪的是这段代码破坏了我的页面(服务器错误)。可能是因为每个表中的行数不相等?
  • 其实没关系,它不会破坏页面,但它也不会返回任何东西。
  • @John,请独立于 PHP 测试 SQL,这样可以更容易地隔离问题。顺便说一句,这个查询适用于 Oracle,但它是非常标准的 SQL,所以我想也应该适用于 MySQL。无论特定的语法是什么,总体思路都应该是合理的......
  • 对,对不起。在 mysql 中,我收到“每个派生表必须有自己的别名”错误。奇数必须查一查。
  • @John,尝试在外部 SELECT 中明确指定列名(请参阅编辑后的答案)。
【解决方案5】:

简单联合版:

Select user_id, address as details from addresses
where user_ID = 1
UNION 
Select user_id, email as details from emails
where user_ID = 1

这里有一些关于联合的快速阅读: http://www.tizag.com/sqlTutorial/sqlunion.php

来自输入

table1:                        table2

id  user_id  address           id    user_id   email
----------------------         ----------------------
1   1        Add1              1       1       Email1
2   1        Add2              2       1       Email2
3   2        Add3              3       2       Email3
4   2        Add4              4       3       Email4

结果会是

user_id     details
-----------------------
1           Add1
1           Add2
1           Email1
1           Email2

【讨论】:

  • 没有返回任何奇怪的东西。不确定代码的“详细信息”部分是什么意思?
  • MySQL 给了我这个错误:"The used SELECT statements have a different number of columns"
  • "details" 是一个列别名,我添加了“as”关键字,我使用了它,所以列是相同的。现在每个查询中都有 2 列。鉴于到目前为止遇到的其他问题,我会检查每个表中 user_ID 列的数据类型是否相同
  • 天哪,这确实有效。但是,只有当我指定了我想要选择的所有列时(我不能使用 *)。这有什么原因吗?
  • 是的,联合中所有查询之间的列需要匹配。这就是为什么我将列别名用于电子邮件和地址
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-02
  • 1970-01-01
  • 2016-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-17
相关资源
最近更新 更多