简体   繁体   English

SQL-具有COUNT()不能按预期工作

[英]SQL - Having COUNT() doesn't work as expected

I joined few tables and filtered results using following code. 我加入了几个表,并使用以下代码过滤了结果。

SELECT jmeno, prijmeni, adresa, vozidlo.spz, snimek.timestamp
FROM majitel
INNER JOIN vozidlo ON majitel.id_majitel = vozidlo.id_majitel
INNER JOIN kat_kamera ON kat_kamera.id_kategorie = vozidlo.id_kategorie
INNER JOIN snimek ON kat_kamera.id_kamera = snimek.id_kamera
WHERE TIMESTAMP >= TIMESTAMP(NOW() - INTERVAL 2 DAY)

Here is the result. 这是结果。

jmeno   prijmeni    adresa  spz         timestamp
John    Doe         Prague  7A2 5109    17/05/2019 08:21
John    Doe         Prague  7A2 5109    17/05/2019 20:50
Vanessa Green       Pilsen  4P8 9370    17/05/2019 06:14
John    Doe         Prague  7A2 5109    17/05/2019 20:50
Vanessa Green       Pilsen  4P8 9370    17/05/2019 12:27
Vanessa Green       Pilsen  4P8 9370    17/05/2019 14:31
John    Doe         Prague  7A2 5109    18/05/2019 15:35

This works well so far. 到目前为止,效果很好。 The problem is, that I want to limit the results only to these, which appear 3 times or more. 问题是,我只想将结果限制为出现3次以上的结果。

So I modified the query like this. 所以我这样修改了查询。

SELECT jmeno, prijmeni, adresa, vozidlo.spz, snimek.timestamp
FROM majitel
INNER JOIN vozidlo ON majitel.id_majitel = vozidlo.id_majitel
INNER JOIN kat_kamera ON kat_kamera.id_kategorie = vozidlo.id_kategorie
INNER JOIN snimek ON kat_kamera.id_kamera = snimek.id_kamera
WHERE TIMESTAMP >= TIMESTAMP(NOW() - INTERVAL 2 DAY)
HAVING COUNT(jmeno) >= 3

But unfortunately this doesn't work. 但是不幸的是,这是行不通的。 As it returns just this. 正如它返回的那样。

jmeno   prijmeni    adresa  spz         timestamp
John    Doe         Prague  7A2 5109    17/05/2019 08:21

But there should be both John Doe and also Vanessa Green in the final result. 但最终结果中既应该有约翰·杜John Doe) ,也应该有凡妮莎·格林Vanessa Green)

Could you pls help me out to get the desired result? 您能帮我得到预期的结果吗?

You need a GROUP BY . 您需要GROUP BY MySQL allows a HAVING clause without a GROUP BY . MySQL允许没有GROUP BYHAVING子句。 The entire query is considered an aggregation query and returns exactly one row. 整个查询被视为聚合查询,并且仅返回一行。

If you only want the repeating parts: 如果只需要重复部分:

SELECT jmeno, prijmeni, adresa, v.spz
FROM majitel m INNER JOIN
     vozidlo v
     ON m.id_majitel = v.id_majitel INNER JOIN
     kat_kamera kk
     ON kk.id_kategorie = v.id_kategorie INNER JOIN
     snimek s
     ON kk.id_kamera = s.id_kamera
WHERE TIMESTAMP >= TIMESTAMP(NOW() - INTERVAL 2 DAY)
GROUP BY jmeno, prijmeni, adresa, v.spz
HAVING COUNT(*) >= 3;

(I encourage you to qualify all column names so it is clear what tables they come from.) (我鼓励您限定所有列名,以便清楚它们来自何表。)

The timestamp is trickier to include. 包含timestamp比较麻烦。 Perhaps concatenating them together one the same row would suffice: 也许在同一行中将它们串联在一起就足够了:

SELECT jmeno, prijmeni, adresa, v.spz,
       GROUP_CONCAT(timestamp) as timestamps
FROM majitel m INNER JOIN
     vozidlo v
     ON m.id_majitel = v.id_majitel INNER JOIN
     kat_kamera kk
     ON kk.id_kategorie = v.id_kategorie INNER JOIN
     snimek s
     ON kk.id_kamera = s.id_kamera
WHERE TIMESTAMP >= TIMESTAMP(NOW() - INTERVAL 2 DAY)
GROUP BY jmeno, prijmeni, adresa, v.spz
HAVING COUNT(*) >= 3;

If you want the individual rows, then in MySQL 8+, you can use window functions: 如果需要单独的行,则在MySQL 8+中,可以使用窗口函数:

SELECT x.*
FROM (SELECT jmeno, prijmeni, adresa, v.spz, timestamp,
             COUNT(*) OVER (jmeno, prijmeni, adresa, v.spz) as cnt
      FROM majitel m INNER JOIN
           vozidlo v
           ON m.id_majitel = v.id_majitel INNER JOIN
           kat_kamera kk
           ON kk.id_kategorie = v.id_kategorie INNER JOIN
           snimek s
           ON kk.id_kamera = s.id_kamera
      WHERE TIMESTAMP >= TIMESTAMP(NOW() - INTERVAL 2 DAY)
      GROUP BY jmeno, prijmeni, adresa, v.spz
     ) x
WHERE cnt >= 3;

You should use group by and count(*) 您应该使用分组依据和计数(*)

  SELECT jmeno, prijmeni, adresa, vozidlo.spz, min(snimek.timestamp)
  FROM majitel
  INNER JOIN vozidlo ON majitel.id_majitel = vozidlo.id_majitel
  INNER JOIN kat_kamera ON kat_kamera.id_kategorie = vozidlo.id_kategorie
  INNER JOIN snimek ON kat_kamera.id_kamera = snimek.id_kamera
  WHERE TIMESTAMP >= TIMESTAMP(NOW() - INTERVAL 2 DAY)
  group by jmeno, prijmeni, adresa, vozidlo.sp
  HAVING COUNT(*) >= 3

and use an aggregation function for reduce the timestamp values (eg: min()) 并使用聚合函数来减少时间戳记值(例如:min())

It can be done by employing ROW_NUMBER and EXISTS if don't want to lost information about each timestamp. 如果不想丢失有关每个时间戳的信息,可以通过使用ROW_NUMBEREXISTS来完成。 Try this: 尝试这个:

WITH CTE AS
(
    SELECT 
         jmeno
        ,prijmeni
        ,adresa
        ,vozidlo.spz
        ,snimek.timestamp
        ,ROW_NUMBER() OVER (PARTITION BY jmeno ORDER BY jmeno) as number
    FROM majitel
    INNER JOIN vozidlo ON majitel.id_majitel = vozidlo.id_majitel
    INNER JOIN kat_kamera ON kat_kamera.id_kategorie = vozidlo.id_kategorie
    INNER JOIN snimek ON kat_kamera.id_kamera = snimek.id_kamera
    WHERE TIMESTAMP >= TIMESTAMP(NOW() - INTERVAL 2 DAY)
)
SELECT
    *
FROM CTE
WHERE exists (
                SELECT 1
                FROM CTE
                where CTE.jmeno = jmeno
                and CTE.number >= 3
              )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM