如何避免笛卡尔积查询?

时间:2013-01-30 02:45:57

标签: mysql sql cartesian

我正在构建一个分类广告的网络应用程序(这是我的第一个专业的PHP应用程序)。我有一个包含广告的表格,另一个包含每个广告的图片。每个广告最多可包含4张图片。这一切都很好,而我每个广告只添加一个图像。现在,当我在广告中重复广告时,每个广告都会展示多个图片(每个图片都有一次)。这是我正在使用的SQL:

SELECT 
sun_classified_ads.ad_id, 
sun_classified_ads.insertion_datetime, 
sun_classified_ads.title,                
sun_classified_ads.description, 
sun_classified_ads.maker, 
sun_classified_ads.model, 
sun_classified_ads.location, 
sun_classified_ads.price, 
sun_classified_ads_images.filename_mini, 
sun_classified_ads_images.size_attr_mini, 
sun_classified_ads_images.description AS image_description
FROM sun_classified_ads
INNER JOIN sun_classified_ads_images ON sun_classified_ads.ad_id =       sun_classified_ads_images.ad_id

我怎么能这样做呢?它只使用sun_classified_ads_images表中该广告的第一张图片?

3 个答案:

答案 0 :(得分:2)

MySQL有一个名为隐藏列的“功能”。您可以使用以下内容为每个广告获取一张图片:

SELECT 
sun_classified_ads.ad_id, 
sun_classified_ads.insertion_datetime, 
sun_classified_ads.title,                
sun_classified_ads.description, 
sun_classified_ads.maker, 
sun_classified_ads.model, 
sun_classified_ads.location, 
sun_classified_ads.price, 
sun_classified_ads_images.filename_mini, 
sun_classified_ads_images.size_attr_mini, 
sun_classified_ads_images.description AS image_description
FROM sun_classified_ads
INNER JOIN sun_classified_ads_images ON sun_classified_ads.ad_id =       sun_classified_ads_images.ad_id
group by sun_classified_ads.ad_id

请注意。无法保证这会返回第一个广告。不保证图像中的三个字段实际上来自同一记录(尽管实际上它们也是如此)。但是,这可能是获得所需内容的最简单方法。

以下查询可以执行您想要的操作,但需要更多工作:

SELECT 
sun_classified_ads.ad_id, 
sun_classified_ads.insertion_datetime, 
sun_classified_ads.title,                
sun_classified_ads.description, 
sun_classified_ads.maker, 
sun_classified_ads.model, 
sun_classified_ads.location, 
sun_classified_ads.price, 
substring_index(group_concat(sun_classified_ads_images.filename_mini order by ad_image_id), ',', 1), 
substring_index(group_concat(sun_classified_ads_images.size_attr_mini order by ad_image_id), ',', 1), 
substring_index(group_concat(sun_classified_ads_images.description order by ad_image_id), ',', 1) AS image_description
FROM sun_classified_ads
INNER JOIN sun_classified_ads_images ON sun_classified_ads.ad_id =       sun_classified_ads_images.ad_id
group by sun_classified_ads.ad_id

这假定ad_image_id是一个可用于定义图像排序的字段。

答案 1 :(得分:1)

您没有说明您的表格是否datetime表示添加image的时间。如果是,那么您可以更改以下查询以返回每个广告的min()日期。

如果没有,那么您可能仍然可以使用以下内容:

SELECT 
  a.ad_id, 
  a.insertion_datetime, 
  a.title,                
  a.description, 
  a.maker, 
  a.model, 
  a.location, 
  a.price, 
  i.filename_mini, 
  i.size_attr_mini, 
  i.description AS image_description
FROM sun_classified_ads a
INNER JOIN
(
  select min(ad_id) Min_Ad_id, ad_id
  from sun_classified_ads_images i
  group by ad_id
) i
  ON a.ad_id = i.ad_id
INNER JOIN sun_classified_ads_images i2
  ON a.ad_id = i2.ad_id
  and i.Min_Ad_id = i2.ad_id

如果图像表中有datetime,则可以使用:

INNER JOIN
(
  select min(ad_date) Min_Ad_Date, ad_id
  from sun_classified_ads_images i
  group by ad_id
) i
  ON a.ad_id = i.ad_id
INNER JOIN sun_classified_ads_images i2
  ON a.ad_id = i2.ad_id
  and i.Min_Ad_Date = i2.ad_date

答案 2 :(得分:0)

简短的回答是“你不能”。您编写的查询将返回所有匹配数据的所有行。每个图像的数据匹配一次。您需要执行两个查询 - 一个用于获取所有广告,然后一个用于查询所有图片。这是最直接的方式。