【问题标题】:limiting results without using a subquery在不使用子查询的情况下限制结果
【发布时间】:2012-08-09 23:39:17
【问题描述】:

我有 2 张桌子:

  • 企业(ID、名称)
  • 类别(id,name,business_id)

如何输出数据库中的所有类别,每个类别有 5 个商家?

例如,如果数据库中有 3 个类别,那么我想要:

category 1
--------------
business 1
business 2
business 3
business 4
business 5

category 2
---------------
business 6
business 7
business 8
business 9
business 10

category 3
------------------
business 11
business 12
business 13
business 14
business 15

我知道如何做到这一点的唯一方法是从 db 中获取所有类别,然后以编程方式遍历每个类别并触发另一个查询以获取每个类别中的所有企业。

还有其他方法吗?

【问题讨论】:

  • 您是要求仅包含 5 个类别的所有类别,还是仅显示每个类别的前 5 个类别?
  • 我想显示所有类别和每个类别下的前 5 个商家。
  • 企业是如何排序的?
  • 我认为使用子查询是不可能的。你为什么不想呢?

标签: mysql sql database


【解决方案1】:

您可以使用排名方法,但这涉及子查询。

 select id,business_name,cat_name,cat_id from
(SELECT *,@i := CASE WHEN ( @temp_bid <> m.id ) THEN 1                      
            ELSE     @i+1      
            END AS rank ,
            @temp_bid:=m.id as dlset 
 FROM 
 ( Select a.id as id,a.name as business_name,b.name as cat_name,b.id as cat_id
   from business a left outer join categories b on a.id=b.business_id ) m)k,
 (SELECT @i:=0)i,(SELECT @i2:=0)i2
where rank<=5
 ORDER BY business_name,rank desc;

SQL FIDDLE HERE.

【讨论】:

  • 感谢您的详细而有帮助的回答。我非常感谢您花时间编写查询并将其放在 SQL fiddle 上。
  • @WarDoGG 想要每个类别和前 5 个企业。您显示每个业务以及前 5 个类别,因此您的结果是倒退的。这是可以理解的,因为定义的模式似乎需要它。 stackoverflow.com/a/11876349/1432614 提供了正确的答案,但添加了一个 cat_bus 关系表来完成它。
【解决方案2】:

您可以使用 WHERE 子句中的相关子查询来做到这一点:

select b.name, c.id
from categories c join
     business b
     on c.business_id = b.id
where c.id in (select c2.id
               from categories c2
               where c2.business_id = c.business_id
               order by rand()
               limit 5
              )

在其他支持排名功能的数据库中,这要简单得多。

如果此子查询不支持限制,则必须使用自联接来完成。呸呸呸呸:

with bc as (
     select b.name, c.id
     from categories c join
          business b
          on c.business_id = b.id
   )
select bc.name, bc.id
from bc join
     bc bcprev
     on bc.name = bcprev.name and
        bcprev.id <= bc.id
group by bc.name, bc.id
having count(*) <= 5

这不会得到 5 个随机类别。相反,它会获取 id 最低的五个。

罗斯·史密斯编辑:

上述查询在 MySQL 5.5.25 中返回错误,但以下方法有效:

select bc.name, bc.id
from
  (
     select b.name, c.id
     from categories c join
          business b
          on c.business_id = b.id
   ) bc join
   (
     select b.name, c.id
     from categories c join
          business b
          on c.business_id = b.id
   ) bcprev
     on bc.name = bcprev.name and
        bcprev.id <= bc.id
group by bc.name, bc.id
having count(*) <= 5

并且似乎返回了这个预期的结果。

http://sqlfiddle.com/#!2/ea78a/9

【讨论】:

  • 在 MySQL 5.5.16 上,此查询产生此错误:此版本的 MySQL 尚不支持 'LIMIT & IN/ALL/ANY/SOME 子查询'
  • 编辑后的查询返回此错误:您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以获取正确的语法,以便在第 1 行的 'bc as ( select b.name, c.id from categories c join business '附近使用:with bc as ( select b.name, c. id from categories c join business b on c.business_id = b.id ) select name, id from bc join bc bcprev on bc.name = bcprev.name and bcprev.id
【解决方案3】:

如果您将类别-业务关系存储在单独的表中不是更好吗?如果是这样,那么您可以使用此查询:

SELECT
    c_name,
    b_name
FROM
(
    SELECT
        c.name AS c_name,
        b.name AS b_name,
        (@row := IF(@last = cat_id, @row + 1, 1)) AS row,
        @last := cat_id
    FROM
        (SELECT @row := 0, @last = '') a,
        cat_bus cb
    INNER JOIN
        cat c ON c.id = cb.cat_id
    INNER JOIN
        bus b ON b.id = cb.bus_id
    ORDER BY
        c.name,
        b.name
) d 
WHERE
    d.row <= 5
ORDER BY
    c_name,
    b_name  

结果见sqlfiddle.com

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多