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.

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.

Could you pls help me out to get the desired result?

3 Answers

1
Gordon Linoff On Best Solutions

You need a GROUP BY. MySQL allows a HAVING clause without a GROUP BY. 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. 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:

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;
0
scaisEdge On

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())

0
M. Kanarkowski On

It can be done by employing ROW_NUMBER and EXISTS if don't want to lost information about each timestamp. 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
              )