【问题标题】:从一个表中获取多行到另一个表的每一行
【发布时间】:2022-01-04 03:53:51
【问题描述】:

我这里有一个问题,我想知道是否可以只在一个查询中执行此操作,而不是让服务器执行多个查询。

所以事情就是这样,我想要的是,在每个类别中,在 24 家商店的限制内搜索属于该类别的所有商店。也就是说,假设我注册了 5 个类别,我将搜索属于该类别的 24 家商店,得出的结论是,我将在查询结果中总共有 120 家商店。

以下代码是一个示例,但这只会获取任何类别的前 24 个商店,而不会遍历每个类别。

SELECT *
FROM categories c
    LEFT JOIN (SELECT * FROM stores_categories LIMIT 24 OFFSET 0) sc ON sc.id_category = c.id
WHERE type = 'STORE' OR type = 'ALL';

有人给我发了这个,它与我的问题非常相似,How to SELECT the newest four items per category?,有点像那样,但我希望能够限制和偏移来制作页面,而不仅仅是前 24 个最近的在每个类别中。

我得到的链接中的示例代码:

SELECT sc1.*
FROM stores_categories sc1
    LEFT OUTER JOIN stores_categories sc2 ON (sc1.id_category = sc2.id_category AND sc1.id_store < sc2.id_store)
GROUP BY sc1.id_store
HAVING COUNT(*) < 24
ORDER BY sc1.id_category;

我的数据库服务器是5.5.64-MariaDB版本。一个小提琴示例,可以使用我的数据库中的相同值进行测试。 https://www.db-fiddle.com/f/jcowJL9S4FQXqKg2yMa8kf/0

【问题讨论】:

  • 示例数据必须以文本 CREATE TABLE + INSERT INTO 脚本或在线小提琴的形式提供。它们必须随附此源数据的所需输出和详细说明。 我使用的是 5.6 版的 MariaDB。 显示 SELECT VERSION(); 输出。
  • 感谢您的建议,已编辑。
  • 在我添加的标签中查找更多示例。
  • 感谢您的建议。

标签: mysql sql mariadb greatest-n-per-group


【解决方案1】:

它可以使用每个类别的计算 row_number

--
-- Emulated row_number via variables
-- 
SELECT sc.id, id_store
, cat.name AS cat_name
, cat.type AS cat_type
, rn
FROM
(
  SELECT sc.*
  , @rn := CASE 
           WHEN @cat_id = sc.id_category
           THEN @rn + 1 ELSE 1
           END AS rn
  , @cat_id := sc.id_category as cat_id
  FROM stores_categories sc
  CROSS JOIN (SELECT @cat_id:=0, @rn:=0) vars
  ORDER BY sc.id_category, sc.id_store DESC, sc.id DESC
) sc
LEFT JOIN categories cat 
  ON cat.id = sc.id_category
WHERE rn BETWEEN 1 AND 24
ORDER BY sc.id_category, sc.id_store DESC, sc.id DESC

或者

--
-- Grouped self-join
-- 
SELECT sc.id, sc.id_store
, cat.name AS cat_name
, cat.type AS cat_type
, COUNT(sc2.id_store) AS cnt
FROM stores_categories sc
LEFT JOIN stores_categories sc2
  ON sc2.id_category = sc.id_category 
 AND sc2.id_store >= sc.id_store
LEFT JOIN categories cat 
  ON cat.id = sc.id_category
GROUP BY sc.id
HAVING cnt BETWEEN 1 AND 24
ORDER BY sc.id_category, sc.id_store DESC;

或者

--
-- Correlated sub-query
-- 
SELECT sc.id, id_store
, cat.name AS cat_name
, cat.type AS cat_type
, ( select count(*)
    from stores_categories sc2
    where sc2.id_category = sc.id_category 
      and sc2.id_store >= sc.id_store
  ) as rn
FROM stores_categories AS sc
LEFT JOIN categories cat 
  ON cat.id = sc.id_category
HAVING rn BETWEEN 1 AND 24
ORDER BY sc.id_category, sc.id_store DESC;

dbfiddle here

上的演示

【讨论】:

  • 那我该怎么做分页呢?我做了一个计算,得到页码并将其乘以 24,然后在“HAVING cnt/rn BETWEEN X + 1 AND Y”的部分进行更改?
  • 不知道分页的最佳实践。所以只是猜测。像rn BETWEEN 1+(@page*24) AND (@page+1)*24 这样的东西。变量从 0 开始。或计算 2 个变量。然后rn BETWEEN @startnum AND @endnum
  • 是的,这就是我所做的,显然它似乎工作正常。感谢您的帮助!
  • 好的!顺便说一句,你觉得这三种方法中哪一种最快?我猜是方法 1,但我无法针对大量数据进行测试。
  • 我选择了“Grouped Self-Join”(第二个选项),因为它在视觉上更干净,看起来最正确。无论如何,我还是对它进行了基准测试,结果是这些,我总共有 629 个条目,它们的运行时间是:第一个选项:1s 390ms 第二个选项:1s 281ms 第三个选项:1s 556ms
猜你喜欢
  • 2012-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多