【问题标题】:SQL SELECT showing records only if the number of records is greater than N仅当记录数大于 N 时 SQL SELECT 才显示记录
【发布时间】:2021-04-01 02:21:54
【问题描述】:

我有一个这样定义的表(MySQL 5.1):

CREATE TABLE mysql_test_a ( 
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, 
firstname VARCHAR(30) NOT NULL, 
lastname VARCHAR(30) NOT NULL,  
email VARCHAR(50), 
reg_date TIMESTAMP 
); 

样本数据集:

INSERT INTO `mysql_test_a` (`id`, `firstname`, `lastname`, `email`, `reg_date`) VALUES ('1', 'Marcello', 'Santucci', 'marcello@tux.net', CURRENT_TIMESTAMP); 
INSERT INTO `mysql_test_a` (`id`, `firstname`, `lastname`, `email`, `reg_date`) VALUES ('2', 'Mike', 'Santucci', 'mike@tux.net', CURRENT_TIMESTAMP); 
INSERT INTO `mysql_test_a` (`id`, `firstname`, `lastname`, `email`, `reg_date`) VALUES ('3', 'Anna Maria', 'Gabriele', 'anna.maria@gabriele.net', CURRENT_TIMESTAMP); 
INSERT INTO `mysql_test_a` (`id`, `firstname`, `lastname`, `email`, `reg_date`) VALUES ('4', 'Matilde Josefa', 'Santucci', 'matilde.josefa@tux.net', CURRENT_TIMESTAMP); 
INSERT INTO `mysql_test_a` (`id`, `firstname`, `lastname`, `email`, `reg_date`) VALUES ('5', 'Milena', 'Santucci', 'mile@tux.net', CURRENT_TIMESTAMP); 
INSERT INTO `mysql_test_a` (`id`, `firstname`, `lastname`, `email`, `reg_date`) VALUES ('6', 'Luca', 'Pensa', 'luca@pensa.net', CURRENT_TIMESTAMP); 
INSERT INTO `mysql_test_a` (`id`, `firstname`, `lastname`, `email`, `reg_date`) VALUES ('7', 'Lorenzo', 'Pensa', 'lo@pensa.net', CURRENT_TIMESTAMP); 

仅当记录数大于某个定义的限制(假设为 2)时,我才需要显示符合特定条件的记录(假设 lastname = 'Santucci')。 我尝试了各种方式但没有成功,最有希望的形式是:

SELECT
    id,
    firstname,
    lastname
FROM
    mysql_test_a
WHERE
    lastname = 'Santucci'
HAVING COUNT(*) > 2

它只返回第一条记录。

我更喜欢使用这种形式,因为 HAVING 子句可以使用参数。

--- 最新更新 ---

我必须更具体地说明解决方案:我正在寻找不涉及内部 SELECT 的东西,更具体地说是它的 WHERE 子句,因为正如我所指出的那样,所提供的那个是相当假的(即它可能与此完全不同,而且要复杂得多)。当然,我很感激任何其他提示。

【问题讨论】:

  • 让我解释一下您的查询出了什么问题:您正在使用没有 GROUP BY 的聚合函数 (COUNT)。这意味着您将数据聚合到单个结果行中。由于可以有多个“Santucci”,这意味着多个 id 和 firstname。因此,您应该无法选择一个 ID 和名字。查询无效,MySQL 应该引发异常,但不会(由于不幸的 ONLY_FULL_GROUP_BY 设置)。它从行中任意选择一个 id 和 firstname。

标签: mysql sql count subquery mysql-5.1


【解决方案1】:

您可以在查询中使用子查询,如下所示:

SELECT id, firstname, lastname
FROM mysql_test_a a
WHERE lastname = 'Santucci'
  and (select count(1) from mysql_test_a b where b.lastname  = a.lastname) > 2

【讨论】:

  • 外部查询中的条件和内部查询中的条件是否绑定?在实际情况下,条件并不是那么简单......
  • 是的,是相关查询。
【解决方案2】:

我猜你的结果是

1 Marcello Santucci

但你想要这样的东西:

1   Marcello        Santucci
2   Mike            Santucci
4   Matilde Josefa  Santucci
5   Milena          Santucci

在这种情况下,你可以使用这个查询,类似于@Popeye 建议的:

SELECT id, firstname, lastname
FROM mysql_test_a tbl
WHERE (SELECT count(*) FROM mysql_test_a sbq WHERE sbq.lastname  = tbl.lastname) > 2

或者这个,基于'in'操作符的使用

SELECT * from mysql_test_a
WHERE lastname IN (
    SELECT lastname
    FROM mysql_test_a
    GROUP BY lastname
    HAVING COUNT(lastname) >2
)

您可以添加“WHERE”子句以将结果限制为“Santucci”,但我认为您会感兴趣更通用的答案。

我还准备了一个小小提琴,你可以和http://sqlfiddle.com/#!9/b1a727/16一起玩

【讨论】:

  • 看起来不错,但是如果我需要更改 WHERE 子句并引用不同的字段怎么办?在实际情况下,WHERE 子句比这复杂得多。有一种方法可以计算内部 SELECT 的结果并在它们适合时返回它们,而无需处理内部查询本身?
  • @weirdgyn 视情况而定,两者都是通用解决方案,但您需要调整它们。作为不同的解决方案,您还可以使用视图,并且可以计算视图中的结果。我现在无法想象查询的复杂性是什么。此外,当我写答案时,问题没有更新。该解决方案适用于旧版本的 MySQL。如果你愿意,你可以创建一个新问题,添加更多细节,我会尽力回答。在那之前,如果我的回答对你的问题足够好,你可以接受。
【解决方案3】:

您可能正在寻找这个:

SELECT 
 *
 FROM
    (SELECT 
        id, 
        firstname, 
        lastname
    FROM
        mysql_test_a
    WHERE
        lastname = 'Santucci') a,
    (SELECT 
        id, 
        firstname, 
        lastname
    FROM
        mysql_test_a
    WHERE
        lastname = 'Santucci'
    HAVING COUNT(*) > 2) b
WHERE
    a.lastname = b.lastname

【讨论】:

    【解决方案4】:

    如果您运行的是 MySQL 8.0,我会推荐一个窗口计数:

    select id, firstname, lastname
    from (
        select t.*, count(*) over() as cnt
        from mysql_test_a a
        where lastname = 'Santucci'
    ) t
    where cnt > 2
    

    我们可以将其概括为一次处理多个姓氏:

    select id, firstname, lastname
    from (
        select t.*, count(*) over(partition by lastname) as cnt
        from mysql_test_a a
    ) t
    where cnt > 2
    order by lastname
    

    【讨论】:

    • 我更喜欢第一个公式,因为在实际情况下,我需要一个更复杂的 WHERE 子句
    • 您提供的查询在 mysql 8.0 上运行良好,但不幸的是我无法将我的服务器更新到此版本(它运行 MySQL 5.6)。顺便说一句,在您放置SELECT t.* 的内部选择中有一个小错字,它应该是SELECT a.*
    【解决方案5】:

    最有效的方法可能是exists

    select t.*
    from mysql_test_a t
    where lastname = 'Santucci' and
          exists (select 1
                  from mysql_test_a t2 
                  where t2.lastname = t.lastname and
                        t2.id <> t.id
                 );
    

    为了提高性能,您需要在mysql_test_a(lastname) 上建立索引。

    【讨论】:

    • 如果我需要更改 WHERE 子句并引用不同的字段怎么办?
    • @weirdgyn 。 . .你可以这样做,但这将是另一个问题的答案。
    • 我正在寻找一个不太具体的解决方案,例如 GMB 提供的窗口计数。
    • @weirdgyn 。 . . (1) 这在 MySQL 5.1 中不起作用。 (2) 这回答了您提出的问题。
    • 我需要检查 MySQL 服务器是否可以更新到 8.0 ......正如我在我的问题中指出的那样 WHERE 子句是假设的......当然我本可以更干净(这就是为什么我添加了最新更新)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多