php - MySQL连接查询在输出中重复用户

标签 php mysql pivot entity-attribute-value

我有下表

ea_users


ID
名字

电子邮件
密码
id_roles


ea_user_cfields


ID
c_id =自定义字段ID
u_id =用户ID
数据


ea_customfields


ID
名称=自定义字段的名称
描述


我想获得具有特定角色的所有用户,但我也想检索每个用户的所有自定义字段。这是我的软件后端,应显示所有ea_users和自定义字段。

我尝试了以下操作,但是对于每个自定义字段,它都会复制同一用户

    $this->db->join('(SELECT GROUP_CONCAT(data) AS custom_data, id AS dataid, u_id, c_id
     FROM ea_user_cfields userc
     GROUP BY id) AS tt', 'tt.u_id = ea.id','left');
    $this->db->join('(SELECT GROUP_CONCAT(name) AS custom_name, id AS customid
     FROM ea_customfields AS cf
     GROUP BY id) AS te', 'tt.c_id = te.customid','left');
    $this->db->where('id_roles', $customers_role_id);


    return $this->db->get('ea_users ea')->result_array();

最佳答案

您不正确理解联接如何工作的问题。
可以,当您与一对多关系时,您在选择中有重复项。

简而言之,您的情况是:引擎尝试从表“ A”(ea_users)中获取数据,然后根据条件联接另一个表“ B”(ea_customfields)。如果您在表之间具有一对多关系(这意味着表“ A”中的一条记录(假设我们在此表A1中具有记录)可以包含表“ B”中的几个相关行,则将它们称为B1.1) ,B1.2,B1.3和B1.4),在这种情况下,它将联接此记录并将联接结果放入内存中。所以在记忆中,您会看到类似

| FromTable A | FromTableB |
| A1        | B1.1       |
| A1        | B1.2       |
| A1        | B1.3       |
| A1        | B1.4       |


如果您在表“ B”中有10条记录,这些记录与表“ A”相关,则它将在获取期间将表“ A”的数据副本存储10次。然后将其呈现给您。

根据联接类型的行,缺少相关记录,可以完全跳过(INNER JOIN),也可以用NULL填充(LEFT JOIN或RIGHT JOIN),等等。

当您考虑加入时,试着想象自己,当您尝试加入纸上的几张大桌子时。 U总是需要以某种方式标记哪个数据来自哪个表,以便以后可以对其进行操作,因此从逻辑上讲,您需要从表“ A”写入行“ A1”的次数是您需要填满空白空间的次数当您在表“ B”中找到适当的记录时。否则,您将在您的纸上有以下内容:

| FromTable A | FromTableB |
| A1        | B1.1       |
|           | B1.2       |
|           | B1.3       |
|           | B1.4       |


是的,即使“ FromTable A”列包含空数据,当您有5-10条记录并且您可以轻松地对其进行操作时,它也看起来不错(例如,您可以将其排序在您的脑中-您只需要想象应该是什么) ,但是为此,您需要记住所有时间顺序,您是如何在纸上写数据的)。但是,假设您有100-1000条记录。如果您仍然可以轻松地对它进行排序,则可以使事情变得更复杂,并告诉它们表“ A”中的值可以为空,等等。这就是为什么mysql引擎更容易重复表中的数据多次。

基本上,当您尝试想象自己将如何在纸上加入巨大的表格,或尝试从该表格中选择某些内容,然后在其中进行排序或其他操作,以及如何查看这些表格时,我总是坚持使用示例。

GROUP_CONCAT,分组

然后,下一个错误是,您不了解GROUP_CONCAT的工作方式:
问题在于,mysqlEngine首先使用所有where条件将第一步结构取入内存,评估子查询+追加所有联接。加载结构时,它尝试执行GROUPING。这意味着它将从临时表中选择与“ A1”相关的所有行。然后将尝试将聚合功能应用于所选数据。 GROUP_CONCAT函数意味着我们要在所选组上应用串联,因此我们将看到类似“ B1.1,B1.2,B1.3,B1.4”的内容。简而言之,但我希望它对理解它有所帮助。

我用谷歌表结构,以便您可以在那里写一些查询。
http://www.mysqltutorial.org/tryit/query/mysql-left-join/#1

这是GROUP_CONCAT工作原理的示例,尝试执行那里的查询:

SELECT 
    c.customerNumber, c.customerName, GROUP_CONCAT(orderNumber) AS allOrders
FROM customers c
LEFT JOIN orders o ON (c.customerNumber = o.customerNumber)
GROUP BY 1,2
;


可以与上一个结果进行比较。

GROUP在您可以使用的聚合函数中的强大功能。例如,您可以使用“ COUNT()”,“ MAX()”,“ GROUP_CONCAT()”或许多其他方法。

或获取计数(尝试执行计数)的示例:

SELECT c.customerName, count(*) AS ordersCount
FROM customers AS c
LEFT JOIN orders AS o ON (c.customerNumber = o.customerNumber)
GROUP BY 1
;


所以我的意见:

提取后,更简单,更好地在客户端或后端解决此问题。因为就mysql引擎而言,列中重复的响应是绝对正确的。但是,当然,您也可以使用带连接的分组来解决它。但我觉得对于您的任务来说,逻辑过于复杂

PS。
“ GROUP BY 1”-表示我想使用列1进行分组,因此在将数据选择到内存中后,mySql将尝试使用第一列对所有数据进行分组,最好不要使用这种在prod上编写的格式。它与“ GROUP BY c.customerNumber”相同。

PPS。我也阅读了诸如“使用DISTINCT”之类的评论。
要使用DISTINCT或定单功能,您需要了解其工作原理,由于使用不正确,它可能会从您的选择中删除某些数据(与GRO​​UP或INNER JOINS等相同)。乍一看,您的代码可能工作正常,但可能会导致逻辑错误,这是以后发现最复杂的问题。
此外,当您具有一对多关系(在您的特定情况下)时,DISTINCT不会帮助您。您可以尝试执行查询:

SELECT 
    c.customerName, orderNumber AS nr
FROM customers c
INNER JOIN orders o ON (c.customerNumber = o.customerNumber)
WHERE c.customerName='Alpha Cognac'
;
SELECT 
    DISTINCT(c.customerName), orderNumber AS nr
FROM customers c
INNER JOIN orders o ON (c.customerNumber = o.customerNumber)
WHERE c.customerName='Alpha Cognac'
;


结果应该是相同的。客户名称列和订单号中重复。

以及示例如何使用错误的查询来丢失数据;):

SELECT 
    c.customerName, orderNumber AS nr
FROM customers c
INNER JOIN orders o ON (c.customerNumber = o.customerNumber)
WHERE c.customerName='Alpha Cognac'
GROUP BY 1
;

关于php - MySQL连接查询在输出中重复用户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39455654/

相关文章:

nginx - 使用 php-fpm + nginx 时无法获取错误堆栈跟踪或错误日志

python - 计算唯一对并将计数存储在矩阵中

MySQL子查询一行列出信息

SQL。如何从一列中获取值并将其传递给另一列

php - MySQL:具有重复任务的传输规划器

php - 需要帮助显示数据库中的数据

php - 这在 HTML 和 PHP 中是否可能或有效?

mysql - 在同一个 sql 查询中使用别名

php - 删除 codeigniter 中的数据库条目

mysql - 隐藏SSRS表中的一行