MySql LEFT OUTER JOIN导致重复的行

时间:2016-04-20 04:34:49

标签: mysql join

我正在运行查询以获取前10个profiles (think of them as an article that shows when a shop opens and holds information about that shop)。我正在使用OUTER JOINselect * images that belong to the profile PK

我运行以下查询,我试图关注的主要部分是JOIN。我不会发布整个查询,因为它只是一大堆'table'.'colname' = 'table.colname'

但是这里是在我的外部加入期间发生魔术的地方。

LEFT JOIN `content_image` AS `image` ON `profile`.`content_ptr_id` = `image`.`content_id`

完整查询:

我的格式是这样的,所以每个人都可以看到查询而无需向右滚动。

select `profile`.`content_ptr_id` AS `profile.content_ptr_id`,
       `profile`.`body` AS `profile.body`,
       `profile`.`web_site` AS `profile.web_site`,
       `profile`.`email` AS `profile.email`,
       `profile`.`hours` AS `profile.hours`,
       `profile`.`price_range` AS `profile.price_range`,
       `profile`.`price_range_high` AS `profile.price_range_high`,
       `profile`.`primary_category_id` AS `profile.primary_category_id`,
       `profile`.`business_contact_email` AS `profile.business_contact_email`,
       `profile`.`business_contact_phone` AS `profile.business_contact_phone`,
       `profile`.`show_in_directory` AS `profile.show_in_directory`,
       `image`.`id` AS `image.id`,
       `image`.`content_id` AS `image.content_id`,
       `image`.`type` AS `image.type`,
       `image`.`order` AS `image.order`,
       `image`.`caption` AS `image.caption`,
       `image`.`author_id` AS `image.author_id`,
       `image`.`image` AS `image.image`,
       `image`.`link_url` AS `image.link_url`
FROM content_profile AS profile
LEFT JOIN `content_image` AS `image` ON `profile`.`content_ptr_id` = `image`.`content_id`
GROUP BY profile.content_ptr_id
LIMIT 10, 12

有没有办法可以根据个人资料对结果进行分组?例如,所有图像都会显示在一个配置文件结果中?因为我收到错误

,我无法使用分组
Error: ER_WRONG_FIELD_WITH_GROUP: Expression #12 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'broadsheet.image.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by]
  code: 'ER_WRONG_FIELD_WITH_GROUP',
  errno: 1055,
  sqlState: '42000',
  index: 0 }

是否有可能解决此group by错误或我可以运行的其他查询?

表:

content_image

+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| content_id | int(11)      | NO   | MUL | NULL    |                |
| type       | varchar(255) | NO   |     | NULL    |                |
| order      | int(11)      | NO   |     | NULL    |                |
| caption    | longtext     | NO   |     | NULL    |                |
| author_id  | int(11)      | YES  | MUL | NULL    |                |
| image      | varchar(255) | YES  |     | NULL    |                |
| link_url   | varchar(200) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

content_profile

+------------------------+----------------------+------+-----+---------+-------+
| Field                  | Type                 | Null | Key | Default | Extra |
+------------------------+----------------------+------+-----+---------+-------+
| content_ptr_id         | int(11)              | NO   | PRI | NULL    |       |
| body                   | longtext             | NO   |     | NULL    |       |
| web_site               | varchar(200)         | NO   |     | NULL    |       |
| email                  | varchar(75)          | NO   |     | NULL    |       |
| menu                   | longtext             | NO   |     | NULL    |       |
| hours                  | longtext             | NO   |     | NULL    |       |
| price_range            | smallint(5) unsigned | YES  | MUL | NULL    |       |
| price_range_high       | smallint(5) unsigned | YES  |     | NULL    |       |
| primary_category_id    | int(11)              | NO   |     | NULL    |       |
| business_contact_name  | varchar(255)         | NO   |     | NULL    |       |
| business_contact_email | varchar(75)          | NO   |     | NULL    |       |
| business_contact_phone | varchar(20)          | NO   |     | NULL    |       |
| show_in_directory      | tinyint(1)           | NO   |     | NULL    |       |
+------------------------+----------------------+------+-----+---------+-------+

2 个答案:

答案 0 :(得分:0)

删除GROUP BY子句。

我怀疑你不想做GROUP BY操作,因为group by中的表达式是content_profile表的PRIMARY KEY。

所有单引号怎么样?它们用于包含字符串文字,而不是标识符。

感谢我们从#34;无休止地滚动到右边"。

您是否知道SQL文本中可以包含空格和换行符,而不会改变语句的含义?解析器可以轻松处理额外的空格,添加额外的空格来格式化语句可以使人类读者更容易破译。

根本不清楚为什么声明跳过前十行,然后返回接下来的十二行。很奇怪。

SELECT p.content_ptr_id         AS `profile.content_ptr_id`
     , p.body                   AS `profile.body`
     , p.web_site               AS `profile.web_site`
     , p.email                  AS `profile.email`
     , p.hours                  AS `profile.hours`
     , p.price_range            AS `profile.price_range`
     , p.price_range_high       AS `profile.price_range_high`
     , p.primary_category_id    AS `profile.primary_category_id`
     , p.business_contact_email AS `profile.business_contact_email`
     , p.business_contact_phone AS `profile.business_contact_phone`
     , p.show_in_directory      AS `profile.show_in_directory`
     , i.id                     AS `image.id`
     , i.content_id             AS `image.content_id`
     , i.type                   AS `image.type`
     , i.order                  AS `image.order`
     , i.caption                AS `image.caption`
     , i.author_id              AS `image.author_id`
     , i.image                  AS `image.image`
     , i.link_url               AS `image.link_url`
  FROM `content_profile` p
  LEFT
  JOIN `content_image` i
    ON i.content_id = p.content_ptr_id
 ORDER
    BY p.content_ptr_id
     , i.id

由于content_id在content_image表中不是唯一的,因此content_profile中的重复行是预期的结果。

如果您的代码无法处理"重复"行,即标识刚刚获取的行与上一行具有相同的content_ptr_id值,那么您的SQL不应该执行创建重复值的连接操作。

答案 1 :(得分:0)

通过阅读你的问题,我认为你没有掌握GROUP BY子句的工作原理。

所以我的答案的简短摘要是:学习GROUP BY子句的基础知识。

我将只使用少量列来简化说明。

您的查询的第一个问题是您没有正确使用group by子句 - 使用group by子句时,所有选定的列必须位于group by子句中,或者使用聚合函数进行选择。 / p>

假设这些是您选择的唯一列: profile.content_ptr_id profile.body profile.web_site image.id image.content_id

查询看起来像这样:

SELECT `profile.content_ptr_id`, `profile.body`, `profile.web_site`, `image.id`, `image.content_id`
FROM ...
GROUP BY `profile.content_ptr_id`

此查询将出错,因为您未指定如何将多行合并到profile.bodyprofile.web_siteimage.idimage.content_id的一行。数据库不知道如何合并其他列,因为您可以分组,或使用聚合函数,如min(),max(),count()等。

因此,解决上述查询中引发的错误的一个解决方案如下:

SELECT `profile.content_ptr_id`, `profile.body`, `profile.web_site`, `image.id`, `image.content_id`
FROM ...
GROUP BY `profile.content_ptr_id`, `profile.body`, `profile.web_site`, `image.id`, `image.content_id`

在这里,我将所有列放在group by子句中,该子句生成查询组并选择profile.content_ptr_idprofile.bodyprofile.web_siteimage.id的所有唯一组合,image.content_id列。

以下是一个示例查询,它没有group by子句中包含的所有列:

让我们说,您想知道每个配置文件有多少图像。您可以使用如下查询:

SELECT `profile.content_ptr_id`, `profile.body`, `profile.web_site`, COUNT(`image.id`)
FROM ...
GROUP BY `profile.content_ptr_id`, `profile.body`, `profile.web_site`

通过此查询,您可以了解profile.content_ptr_idprofile.bodyprofile.web_site列的每个独特组合的图片数量。

请注意,在前两个示例中,所选的所有列都包含在group by子句中,或者使用聚合函数进行选择。这是使用group by子句时所有查询都需要遵循的规则,否则数据库将引发错误。

现在,让我们回答你的问题:

“我有没有办法按照个人资料对结果进行分组?例如,所有图片都会显示在一个个人资料结果中吗?”

我将使用以下模拟数据来解释:

profile
+----------------+--------------+---------------+
| content_ptr_id |     body     |   web_site    |
+----------------+--------------+---------------+
|      100       |     body1    |     web1      |
+----------------+--------------+---------------+

image
+--------+-------------+
|   id   |  content_id |
+--------+-------------+
|  iid1  |     100     |
|  iid2  |     100     |
+--------+-------------+

如果您不进行加入,结果会如下所示:

SELECT `profile.content_ptr_id`, `profile.body`, `profile.web_site`, `image.id`, `image.content_id`
FROM ...

+----------------+--------------+---------------+--------+-------------+
| content_ptr_id |     body     |   web_site    |   id   |  content_id |
+----------------+--------------+---------------+--------+-------------+
|      100       |     body1    |     web1      |  iid1  |     100     |
|      100       |     body1    |     web1      |  iid2  |     100     |
+----------------+--------------+---------------+--------+-------------+

通过按所有列进行分组,您无法实现按每个配置文件对结果进行分组(每个配置文件仅显示一行)的目标,因为结果将是相同的:

SELECT `profile.content_ptr_id`, `profile.body`, `profile.web_site`, `image.id`, `image.content_id`
FROM ...
GROUP BY `profile.content_ptr_id`, `profile.body`, `profile.web_site`, `image.id`, `image.content_id`

将返回

+----------------+--------------+---------------+--------+-------------+
| content_ptr_id |     body     |   web_site    |   id   |  content_id |
+----------------+--------------+---------------+--------+-------------+
|      100       |     body1    |     web1      |  iid1  |     100     |
|      100       |     body1    |     web1      |  iid2  |     100     |
+----------------+--------------+---------------+--------+-------------+

您需要回答的问题是如何显示要组合的非唯一列 - 在本例中为image.id。您可以使用计数,但这只会返回一个数字。如果要显示所有文本,可以使用GROUP_CONCAT(),它将默认连接逗号分隔的所有值。如果使用GROUP_CONCAT(),结果将如下所示:

SELECT `profile.content_ptr_id`, `profile.body`, `profile.web_site`, GROUP_CONCAT(`image.id`), GROUP_CONCAT(`image.content_id`)
FROM ...
GROUP BY `profile.content_ptr_id`, `profile.body`, `profile.web_site`

此查询将返回:

+----------------+--------------+---------------+--------------------+-------------+
| content_ptr_id |     body     |   web_site    |  GROUP_CONCAT(id)  |  content_id |
+----------------+--------------+---------------+--------------------+-------------+
|      100       |     body1    |     web1      |     iid1,iid2      |     100     |
+----------------+--------------+---------------+--------------------+-------------+

如果GROUP_CONCAT()是您要用于所有图像列的内容,那么请继续,但是对于合并多行的许多列执行此操作可能会使表格不太可读。但不管怎样,我建议你阅读一些文章来熟悉GROUP BY子句的工作原理。