如果有n种不同的产品,则从每种产品中选择1张图像,如果没有,则从每种产品中选择多于1张图像

时间:2013-07-29 11:56:10

标签: mysql sql select

在项目的设计架构中,一个product可能有很多image个。

现在我想从image s中选择n product s,情况如下:

  • 如果定义了n product,请从每个image中选择image
  • 从每个product限制n
  • 中选择更多product (id, title, ...) image (id, product_id, filename, ...) s

我们是否还需要PHP侧行动来实现目标?

架构符合预期:

SELECT * FROM image ..with..those..hard..conditions.. LIMIT n

我甚至无法想到这样的查询,这就是为什么我不幸地尝试过任何事情。

查询应如下所示:

{{1}}

2 个答案:

答案 0 :(得分:3)

如果我理解得很好 - 你需要n张图片。如果可能,从不同的产品。否则,来自同一产品的多个图像可作为后备。

从现在开始,我能想到的唯一解决方案是构建一个临时表,其中包含编号行,例如每个产品的“图像”位于“顶部” - 并与其余部分一起提交图像。

构建该表后,您的查询只是SELECT ... LIMIT n

这将表现得非常糟糕 - 如果你选择了灵感的解决方案 - 你应该离线或按时合并图像表。

请参阅http://sqlfiddle.com/#!2/81274/2

--
-- test values
--
create table P (id int, title char(20));
insert into P values
  (1, "product 1"),
  (2, "product 2"),
  (3, "product 3");

create table I (pid int, filename char(40));
insert into I values
   (1, "image p1-1"),
   (1, "image p1-2"),
   (3, "image p3-1"),
   (3, "image p3-2"),
   (3, "image p3-3");

--
-- "ordered" image table
--
create table T(n int primary key auto_increment not null,
                         filename char(20));


--
-- consolidate images (once in a while)
--
delete from T;
insert into T(filename)
    select filename from I group by pid;
insert into T(filename)
    select filename from I order by rand();

--
-- do the actual query
--
select * from T limit n;

编辑这是一个完全不同的想法。不使用合并表/视图 - 所以这可能会被视为更好:

http://sqlfiddle.com/#!2/57ea9/4

select distinct(filename) from
    (select 1 as p, filename from I group by pid
     union (select 2 as p, filename from I order by rand() limit 3)) as T
order by p limit 3

这里的关键点是我不必真正“编号”行。仅跟踪来自第一个SELECT的行。这就是p的目的。为简单起见,我将LIMIT子句设置为相同的值。我不认为你必须“优化”那部分,因为它的好处非常小 - ORDER BY RAND()太可怕了,你不必在这里考虑“表演”;)

请注意我没有对此解决方案进行全面测试。让我知道是否有一些不合作的案例(好吧...... 任何案例)。

答案 1 :(得分:1)

http://sqlfiddle.com/#!2/32198/2/0

create view T as select (select filename from I where pid = id order by filename limit 1) as singleImage from P having singleImage is not null;

select * from (
  select singleImage from T
  union all (select filename from I where filename not in
    (select singleImage from T) order by rand() limit 5)
  ) as MoreThanN limit 5;

如果您的N相当小,您可能会受益于my technique for selecting random rows from large tables:虽然它旨在选择单行,但可以相对轻松地选择一些随机行。

这是SQL与Sylvain Leroux的例子:

-- Test values
create table P (id int, title char(20));
insert into P values
  (1, "product 1"),
  (2, "product 2"),
  (3, "product 3");

create table I (pid int, filename char(40));
insert into I values
   (1, "image p1-1"),
   (1, "image p1-2"),
   (3, "image p3-1"),
   (3, "image p3-2"),
   (3, "image p3-3"),
   (3, "image p3-4"),
   (3, "image p3-5");

-- View to avoid repeating the query
create view T as select (select filename from I where pid = id order by filename limit 1) as singleImage from P having singleImage is not null;

-- Query
select * from (
  select singleImage from T
  union all (select filename from I where filename not in
    (select singleImage from T) order by rand() limit 5)
  ) as MoreThanN limit 5;