Home > Software engineering >  MySQL 5.7 using JSON variable as counter to rank rows in Laravel 5.4
MySQL 5.7 using JSON variable as counter to rank rows in Laravel 5.4

Time:10-22

I am using MySQL 5.7 and trying to emulate rank(which is not available in 5.7) using JSON variable.

The problem is that in Laravel DB or PDO query below doesn't work correctly but works fine in TablePlus.

The idea of a query to count rows by groups and filter rows which have counter less than 250. Every group rows have it own counters in json variable.

The idea of this query:

select result.*
from (
    select 
        @extracted_counter:=JSON_EXTRACT(@row_number, CONCAT('game', t.game_id)) as extracted_counter,
        JSON_SET(@row_number, CONCAT('key', t.game_id), @extracted_counter   1) as counters,
        t.*
    from (@row_number := '{"game1": 0, "game27": 0}') as x,
        table_name as t
    where t.app_id = 16325
) as result
where result.extracted_counter < 250;

@json_variable build from another table. I made it as a string to simplify.

Again, the original query is working ok in TablePlus program but when it comes to Laravel 5.4 DB, @row_number can't perform addition more than 3, for instance: "{"game27718": 0,"game27398": 3,"game26592": 0,"game24042": 0,"game23957": 3}"

I thought that Laravel uses specific PDO settings but couldn't find anything. Also, I've tried to use CAST but it didn't help really since addition is working for first three records.

Not really sure how is different settings for TablePlus and PDO Laravel. I've tried to google settings of TablePlus but I can't imagine how can I google it correctly to not bump into interface docs.

I would appreciate any help.

The original query I am trying to use looks like this:

SELECT temp.*
FROM (
    SELECT
    @extracted_counter:=CAST(JSON_EXTRACT(@row_number, CONCAT('$.game', sao.game_id)) AS UNSIGNED) AS extracted_rank,
    if(
        @extracted_counter < @games_length,
        @row_number:=JSON_SET(
            @row_number,
            CONCAT('$.game', sao.game_id),
            @extracted_counter   1
        ),
        @const_length
    ) AS rnk,
    sao.email, sao.name,
    sao.game_id, sao.order_total_price,
    sao.device_type, sao.coupon_id,
    sao.coupon_code, sao.browser,
    sao.city, sao.country,
    sao.order_id, sao.created_at
    FROM (SELECT @row_number := (
        SELECT concat('{', group_concat(concat('"game', s.game_id, '"'), ': 0'), '}') AS str_json
        FROM (
            SELECT g.id AS game_id
            FROM users AS u
            LEFT JOIN games AS g ON u.id = g.user_id
            WHERE u.app_id = 16325
                AND g.deleted_at IS NULL
        ) AS s
    )) AS x,
    (SELECT @games_length := 250) AS games_length,
    (SELECT @const_length := @games_length   100) AS const_length,
    shopify_app_orders as sao
    WHERE sao.app_id = 16325
        AND sao.coupon_id > 0
    ORDER BY sao.id DESC
) AS temp
LEFT JOIN coupons AS c ON c.id = temp.coupon_id
WHERE temp.extracted_rank < @games_length

UPDATE

I've discovered with user_variables_by_thread that there is variables that is still in MySQL before I am querying database.

Variables before query execute:

array:5 [
  0 => {#1171
     "THREAD_ID": "2314"
     "VARIABLE_NAME": "extracted_counter"
     "VARIABLE_VALUE": null
  }
  1 => {#1172
     "THREAD_ID": "2314"
     "VARIABLE_NAME": "const_length"
     "VARIABLE_VALUE": "350"
  }
  2 => {#1173
     "THREAD_ID": "2314"
     "VARIABLE_NAME": "games_length"
     "VARIABLE_VALUE": "250"
  }
  3 => {#1174
     "THREAD_ID": "2314"
     "VARIABLE_NAME": "parse"
     "VARIABLE_VALUE": "{"game27718": 0,"game27398": 0,"game26592": 0,"game24042": 0,"game23957": 0}"
  }
  4 => {#1175
     "THREAD_ID": "2314"
     "VARIABLE_NAME": "row_number"
     "VARIABLE_VALUE": "{"game23957": 250.0, "game24042": 250.0, "game26592": 250.0, "game27398": 250.0, "game27718": 250.0}"
  }
]

Variables after query were executed:

array:9 [
  0 => {#1178
     "THREAD_ID": "2419"
     "VARIABLE_NAME": "extracted_counter"
     "VARIABLE_VALUE": null
  }
  1 => {#1176
     "THREAD_ID": "2419"
     "VARIABLE_NAME": "const_length"
     "VARIABLE_VALUE": "350"
  }
  2 => {#1179
     "THREAD_ID": "2419"
     "VARIABLE_NAME": "games_length"
     "VARIABLE_VALUE": "250"
  }
  3 => {#1180
     "THREAD_ID": "2419"
     "VARIABLE_NAME": "row_number"
     "VARIABLE_VALUE": "{"game23957": 3, "game24042": 3, "game26592": 3, "game27398": 3, "game27718": 3}"
  }
  4 => {#1181
     "THREAD_ID": "2314"
     "VARIABLE_NAME": "extracted_counter"
     "VARIABLE_VALUE": null
  }
  5 => {#1182
     "THREAD_ID": "2314"
     "VARIABLE_NAME": "const_length"
     "VARIABLE_VALUE": "350"
  }
  6 => {#1183
     "THREAD_ID": "2314"
     "VARIABLE_NAME": "games_length"
     "VARIABLE_VALUE": "250"
  }
  7 => {#1184
     "THREAD_ID": "2314"
     "VARIABLE_NAME": "parse"
     "VARIABLE_VALUE": "{"game27718": 0,"game27398": 0,"game26592": 0,"game24042": 0,"game23957": 0}"
  }
  8 => {#1177
     "THREAD_ID": "2314"
     "VARIABLE_NAME": "row_number"
     "VARIABLE_VALUE": "{"game23957": 250.0, "game24042": 250.0, "game26592": 250.0, "game27398": 250.0, "game27718": 250.0}"
  }
]

There is at least tow row_number variables within different thread_id. Not really sure what to do with existed variables. Is it possible to clear performance_schema.user_variables_by_thread? Will it break mysql?

UPDATE 2

I've closed TablePlus connection with database and variables before query disappeared. After query is finished duplicated variables disappeared:

array:4 [
  0 => {#1184
     "THREAD_ID": "2422"
     "VARIABLE_NAME": "extracted_counter"
     "VARIABLE_VALUE": null
  }
  1 => {#1183
     "THREAD_ID": "2422"
     "VARIABLE_NAME": "const_length"
     "VARIABLE_VALUE": "350"
  }
  2 => {#1182
     "THREAD_ID": "2422"
     "VARIABLE_NAME": "games_length"
     "VARIABLE_VALUE": "250"
  }
  3 => {#1181
     "THREAD_ID": "2422"
     "VARIABLE_NAME": "row_number"
     "VARIABLE_VALUE": "{"game23957": 3, "game24042": 3, "game26592": 3, "game27398": 3, "game27718": 3}"
  }
]

Not really sure why but extracted_counter is null though it should have value.

CodePudding user response:

I am not really sure what to do with that opened post and if somebody will ended up with the same issue at all but I found where was the issue.

For some reasons type auto cast is worked in TablePlus and it didn't work for PDO, so this:

CAST(@extracted_counter:=CAST(JSON_EXTRACT(@row_number, CONCAT('$.game', sao.game_id)) AS UNSIGNED) AS UNSIGNED) AS extracted_rank

and this

@extracted_counter:=CAST(JSON_EXTRACT(@row_number, CONCAT('$.game', sao.game_id)) AS UNSIGNED) AS extracted_rank

are not the same.

First one will produce the integer, second one will give you a string.

By the way, next two statements is not the same either:

@extracted_counter < @games_length
@extracted_counter < CAST(@games_length AS UNSIGNED)

even though @games_length where declared like:

(SELECT @games_length := 250) AS games_length,
  • Related