Php MySQL:如何对每个WHERE过滤器进行限制查询

Php MySQL:如何对每个WHERE过滤器进行限制查询,php,mysql,sql,Php,Mysql,Sql,我需要做一个按ID过滤的查询,但我需要限制每个ID的结果。我不知道如何在一个查询中做到这一点,我只能用PHP循环每个ID,为每个迭代执行一个查询,然后将结果合并在一起: $allResults = []; $ids = [1, 2, 3, 4, 5]; foreach ($ids as $id) { $db->query(" SELECT * FROM example_table WHERE example_id = $id

我需要做一个按ID过滤的查询,但我需要限制每个ID的结果。我不知道如何在一个查询中做到这一点,我只能用PHP循环每个ID,为每个迭代执行一个查询,然后将结果合并在一起:

$allResults = [];
$ids = [1, 2, 3, 4, 5];

foreach ($ids as $id) {

    $db->query("
        SELECT *
        FROM example_table
        WHERE example_id = $id
        ORDER BY rating DESC
        LIMIT 2
    ");
    $results = $db->getResults();

    $allResults = array_merge($allResults, $results);
}
上面的内容满足了我的需要,但是如何在一个查询中实现这一点,而不是在一个由5个查询组成的循环中实现这一点呢

我在找这样的东西:

    SELECT *
    FROM example_table
    WHERE 
        example_id = 1 LIMIT 2 OR
        example_id = 2 LIMIT 2 OR
        example_id = 3 LIMIT 2 OR
        example_id = 4 LIMIT 2 OR
        example_id = 5 LIMIT 2
    ORDER BY rating DESC

很明显where子句中的限制抛出了一个错误,但是您可以看到我试图实现的目标。非常感谢您的帮助。

这比我想象的要复杂一些,但是您应该能够非常轻松地用PHP编程创建查询。您甚至不能对联合进行直接限制,但您可以有效地对最低级别的限制进行选择。这是否比执行5个单独的查询更有效还不得而知

SELECT *
      FROM (SELECT *
            FROM example_table
            WHERE id = 1
            LIMIT 2) AS id1
      UNION
      SELECT *
      FROM (SELECT *
            FROM example_table
            WHERE id = 2
            LIMIT 2) AS id2
      UNION
      SELECT *
      FROM (SELECT *
            FROM example_table
            WHERE id = 3
            LIMIT 2) AS id3
      .... more UNIONS ....;

这比我想象的要复杂一点,但是您应该能够相当容易地用PHP编程创建查询。您甚至不能对联合进行直接限制,但您可以有效地对最低级别的限制进行选择。这是否比执行5个单独的查询更有效还不得而知

SELECT *
      FROM (SELECT *
            FROM example_table
            WHERE id = 1
            LIMIT 2) AS id1
      UNION
      SELECT *
      FROM (SELECT *
            FROM example_table
            WHERE id = 2
            LIMIT 2) AS id2
      UNION
      SELECT *
      FROM (SELECT *
            FROM example_table
            WHERE id = 3
            LIMIT 2) AS id3
      .... more UNIONS ....;

正如@草莓所提到的,如果没有可验证的示例和数据,很难给出正确的答案,但这就是查询的样子,因为mysql还不支持组秩函数

SELECT * FROM
(SELECT *, 
    @f_rank := IF(@f_rating = rating AND @f_id = id, @f_rank + 1, 1) AS rank, 
    @f_rating := rating,
    @f_id := id
FROM   example_table 
WHERE id IN (1, 2, 3, 4, 5)
ORDER  BY id, rating DESC) tmp_table
WHERE tmp_table.rank <= 2

您需要在这里对每个id的所有评分从1到n进行排序,然后选择前两个id

正如@草莓提到的,如果没有可验证的示例和数据,很难给出正确的答案,但这就是查询的样子,因为mysql还不支持组秩函数

SELECT * FROM
(SELECT *, 
    @f_rank := IF(@f_rating = rating AND @f_id = id, @f_rank + 1, 1) AS rank, 
    @f_rating := rating,
    @f_id := id
FROM   example_table 
WHERE id IN (1, 2, 3, 4, 5)
ORDER  BY id, rating DESC) tmp_table
WHERE tmp_table.rank <= 2

您需要在这里对每个id的所有评分从1到n进行排序,然后选择前两个id

您可以使用以下联合查询:

(SELECT * FROM example_table WHERE id = 1 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 2 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 3 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 4 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 5 ORDER BY rating DESC LIMIT 2)
以下是如何在PHP中创建它的一种方法:

$ids = [1, 2, 3, 4, 5];

$sqlArray = array_map(function($id){
    $id = (int)$id;
    return "(SELECT * FROM example_table WHERE id = $id ORDER BY rating DESC LIMIT 2)";
}, $ids);

$sql = implode("\nUNION ALL\n", $sqlArray);
演示:

您还应该考虑用占位符准备查询并绑定IDS。因为我不知道$db的类,这里是PDO方法:

$ids = [1, 2, 3, 4, 5];

$sqlArray = array_map(function($id){
    return "(SELECT * FROM example_table WHERE id = ? ORDER BY rating DESC LIMIT 2)";
}, $ids);

$sql = implode("\nUNION ALL\n", $sqlArray);

$stmt = $db->prepare($sql);
$stmt->execute($ids);
$allResults = $stmt->fetchAll(PDO::FETCH_ASSOC);

您可以使用以下联合查询:

(SELECT * FROM example_table WHERE id = 1 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 2 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 3 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 4 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 5 ORDER BY rating DESC LIMIT 2)
以下是如何在PHP中创建它的一种方法:

$ids = [1, 2, 3, 4, 5];

$sqlArray = array_map(function($id){
    $id = (int)$id;
    return "(SELECT * FROM example_table WHERE id = $id ORDER BY rating DESC LIMIT 2)";
}, $ids);

$sql = implode("\nUNION ALL\n", $sqlArray);
演示:

您还应该考虑用占位符准备查询并绑定IDS。因为我不知道$db的类,这里是PDO方法:

$ids = [1, 2, 3, 4, 5];

$sqlArray = array_map(function($id){
    return "(SELECT * FROM example_table WHERE id = ? ORDER BY rating DESC LIMIT 2)";
}, $ids);

$sql = implode("\nUNION ALL\n", $sqlArray);

$stmt = $db->prepare($sql);
$stmt->execute($ids);
$allResults = $stmt->fetchAll(PDO::FETCH_ASSOC);

您有一个名为id的属性,它不是唯一的,这有点令人困惑

基于联合的方法都意味着在查询中硬编码example_id的值,并且不能很好地扩展到大量example_id

当只查看值的子集时,这将有助于实现相对高效的查询

这里有另一种方法

SELECT *
FROM
(
SELECT id, max(rating) as scndrt
FROM example_table scnd
INNER JOIN (
   SELECT id, max(rating) maxrt
   FROM example_table
   GROUP BY id) AS first
 ON scnd.id=first.id
 WHERE scnd.rating<first.maxrt
 ) AS rts
 INNER JOIN example_table thrd
 ON rts.id=thrd.id
 AND thrd.rating IN (rts.maxrt, rts.scndrt)
它不会返回只有一条记录的id,如果一个id的最高评级出现两次,它将返回2条以上的记录。它还需要多次通过数据

我认为也可以使用查询中的变量来解决原始问题,比如

 SELECT @rank:=1+IF(id=@previd, @rank, 0) as ranking,
 @previd=id AS currentid,
 FROM (
   SELECT *
   FROM example_table
   ORDER BY id, rating DESC
 ) AS src
 HAVING ranking<3

我没有使用像这样的变量进行测试,因此您可能需要使用将上面的select展开到一个过程中,并将匹配的行写入一个临时表。

有一点让人困惑的是,您有一个名为id的属性,它不是唯一的

基于联合的方法都意味着在查询中硬编码example_id的值,并且不能很好地扩展到大量example_id

当只查看值的子集时,这将有助于实现相对高效的查询

这里有另一种方法

SELECT *
FROM
(
SELECT id, max(rating) as scndrt
FROM example_table scnd
INNER JOIN (
   SELECT id, max(rating) maxrt
   FROM example_table
   GROUP BY id) AS first
 ON scnd.id=first.id
 WHERE scnd.rating<first.maxrt
 ) AS rts
 INNER JOIN example_table thrd
 ON rts.id=thrd.id
 AND thrd.rating IN (rts.maxrt, rts.scndrt)
它不会返回只有一条记录的id,如果一个id的最高评级出现两次,它将返回2条以上的记录。它还需要多次通过数据

我认为也可以使用查询中的变量来解决原始问题,比如

 SELECT @rank:=1+IF(id=@previd, @rank, 0) as ranking,
 @previd=id AS currentid,
 FROM (
   SELECT *
   FROM example_table
   ORDER BY id, rating DESC
 ) AS src
 HAVING ranking<3

我没有使用这样的变量进行测试,因此您可能需要使用将上面的select展开到一个过程中,并将匹配的行写入一个临时表。

Easy。但是你可以使用秩和秩函数的限制来实现这一点。从中得到提示,然后您可以根据id选择排名,最后选择排名稍微偏离主题的项目,但您正在使用}而不是.Easy关闭$db->query函数。但是你可以使用秩和秩函数的限制来实现这一点。从中得到提示,然后您可以根据id选择排名,最后选择排名稍微偏离主题的项目,但您正在使用}而不是a关闭$db->查询函数。您不需要外部选择。@PaulSpiegel您是对的。我第一次尝试写这篇文章时,它没有编译,我想就是这样。我正在编辑答案。你不需要外部选择。你是对的。我第一次
我写了这篇文章,它没有编译,我想就是这样。我正在编辑答案。UNION ALL方法与ID数成线性关系。不,当查询大于最大数据包大小时,它会中断,并且生成计划的成本会随着ID数的增加而非线性增加。即使是线性增加,也需要对同一数据执行多次传递。虽然您的php生成器帮助UNION ALL方法与ID数成线性关系,但对于大量ID来说,这也是一个需要维护的问题。不,当查询大于最大数据包大小时,它会中断,并且生成计划的成本会随着ID数目的增加而非线性增加。即使是线性增加,也需要对同一数据执行多次传递。尽管php生成器有帮助,但它还是需要大量ID来维护