简体   繁体   中英

How to make this SQL query work with mysql 8

The following query works with mysql 5.x but errors out on mysql 8.0.x:

SET @num := 0, @website_id_host := 0;

SELECT website_id_host, url, date_inserted, row_number
FROM (
    SELECT website_id_host, url, date_inserted, @num := if(@website_id_host = website_id_host, @num+1, 1) as row_number, @website_id_host := website_id_host as dummy1
    FROM (
        SELECT website_id_host, url, date_inserted
        FROM records
        WHERE date_inserted between '2019-11-14 00:00:00' and '2019-11-14 23:59:59' and website_id_host is not null
        ORDER BY website_id_host, date_inserted desc
    ) intermediate
) final
where row_number <=100;

The error I get is:

Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL 
server version for the right syntax to use near 'from (  SELECT website_id_host, url, date_inserted, @num := if(@website_id_host ' 
at line 2

The error isn't very clear about what is wrong. Can anybody help figure out why it's now failing?

Just rename row_number . It is now a function:

SELECT website_id_host, url, date_inserted, seqnum
FROM (SELECT website_id_host, url, date_inserted,
              @num := if(@website_id_host = website_id_host, @num+1, 1) as seqnum,
              @website_id_host := website_id_host as dummy1
    FROM (SELECT website_id_host, url, date_inserted
          FROM records
          WHERE date_inserted between '2019-11-14 00:00:00' and '2019-11-14 23:59:59' and website_id_host is not null
          ORDER BY website_id_host, date_inserted desc
         ) intermediate
     ) final
where seqnum <= 100;

This code has a hidden bug and may not always work. As explained in the documentation :

The order of evaluation for expressions involving user variables is undefined. For example, there is no guarantee that SELECT @a, @a:=@a+1 evaluates @a first and then performs the assignment.

Your code assigns a variable and using it in the same SELECT -- and depending on the order of evaluation. That is specifically documented as not being reliable.

In addition, the use of variables is being phased out, as explained in the documentation :

Previous releases of MySQL made it possible to assign a value to a user variable in statements other than SET. This functionality is supported in MySQL 8.0 for backward compatibility but is subject to removal in a future release of MySQL.

So, the right way to write this in MySQL 8+ is to use row_number() :

SELECT r.*
FROM (SELECT website_id_host, url, date_inserted,
             ROW_NUMBER() OVER (PARTITION BY website_id_host ORDER BY date_inserted DESC) as seqnum
      FROM records r
      WHERE date_inserted >= '2019-11-14' and
            date_inserted < '2019-11-15' and
            website_id_host is not null
     ) r
WHERE seqnum <= 100

Note that I also simplified the date comparisons.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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