Weird result in MySQL query - mysql

I have this query:
SELECT COUNT(1), name, (#i := #i + 1) AS counter FROM mytbl, (SELECT #i := 0) tmp_tbl GROUP BY counter
For this query, the counter column increases its value with 2.
But if I remove COUNT(1), such as:
SELECT name, (#i := #i + 1) AS counter FROM mytbl, (SELECT #i := 0) tmp_tbl GROUP BY counter
counter column increases its value with 1.
Can anyone explain why this behavior?
Table would be:
create table mytbl (name VARCHAR(20));
With data:
INSERT INTO mytbl VALUES
('a1'),
('a2'),
('a3');

As mentioned in MySQL document, we should not assign a value to a user variable and read the value within the same statement. We might get the expected results, but this is not guaranteed. Changing the statement (for example, by adding a GROUP BY, HAVING, or ORDER BY clause) may cause MySQL to select an execution plan with a different order of evaluation.
In your query, counter field will be evaluated in SELECT statement and then be used in GROUP BY statement. Seem when we add an aggregation function to SELECT statement, the field that be used in GROUP BY statement will be evaluated 2 times.
I've create a demo, you could check it. In the demo, I've this query
SELECT Count(1),
name,
( #i := #i + 1 ) AS counter,
( #j := #j + 1 ) AS group_field
FROM (SELECT 'A' AS name
UNION
SELECT 'B' AS name
UNION
SELECT 'C' AS name) mytable,
(SELECT #i := 0) tmp_tbl,
(SELECT #j := 0) tmp_tbl1
GROUP BY group_field;
In the execution result, counter field only be increased by 1 and group_field be increased by 2.
To make the counter field only increasing by 1, you could try this
SELECT Count(1),
name,
counter
FROM (SELECT name,
( #i := #i + 1 ) AS counter
FROM mytbl,
(SELECT #i := 0) tmp_tbl) data
GROUP BY counter;

Related

A view with internal variables

I have a query where I want to fetch the top x for each value of another column. For doing this I have the following query
SELECT *,
(#num := IF(#job = job_id, #num + 1, IF(#job := job_id, 1, 1))) row_number
FROM job_user_rank t
CROSS JOIN (SELECT #num := 0, #job := null) c
where is_match = 1
ORDER BY job_id, is_match DESC, rank DESC
I then wrap this query and add a where row_number <= ?, however I want to make that inner query into a view instead, but I get the following error [HY000][1351] View's SELECT contains a variable or parameter, how can I get around that?

MySQL: Limiting result for WHERE IN list

Let's say there are millions of records in my_table.
Here is my query to extract rows with a specific name from list:
SELECT * FROM my_table WHERE Name IN ('name1','name2','name3','name4')
How do I limit the returned result per name1, name2, etc?
The following query would limit the whole result (to 100).
SELECT * FROM my_table WHERE Name IN ('name1','name2','name3','name4') LIMIT 100
I need to limit to 100 for each name.
This is a bit of a pain in MySQL, but the best method is probably variables:
select t.*
from (select t.*,
(#rn := if(#n = name, #rn + 1,
if(#n := name, 1, 1)
)
) as rn
from my_table t cross join
(select #n := '', #rn := 0) params
order by name
) t
where rn <= 100;
If you want to limit this to a subset of the names, then add the where clause to the subquery.
Note: If you want to pick certain rows -- such as the oldest or newest or biggest or tallest -- just add a second key to the order by in the subquery.
Try
SELECT * FROM my_table WHERE Name IN ('name1','name2','name3','name4') FETCH FIRST 100 ROWS ONLY

MySQL Loop to execute query that uses incrementing variable

I have a query that uses a variable in its where clause:
SET #id = 1;
SELECT
id,
value
FROM myTable
WHERE id = #id;
I would like to run the query for #id values 1 through 100, and then union (or somehow combine) all the loop results into one result set. Is this possible in MySQL, and if so, what is a good approach?
Why would use use a variable for this? Just use a simple where clause:
select id, value
from myTable
where id between 1 and 100;
If, instead, you really want the first 100 rows by id, then use order by and limit:
select id, value
from myTable
order by id
limit 100;
Just use a subquery to get the variable.
And put the where outside
SELECT *
FROM
(
SELECT
#rownumber := if(#rownumber, #rownumber + 1, #rownumber + 1) AS id,
value
FROM myTable
CROSS JOIN (select #rownumber := 0) r
) as T
WHERE id < 100;

Resetting a variable within subquery

If I can increment a variable within a query to append a rank column as such:
SET #i = 0;
SELECT *, #i:=#i+1 AS rank FROM table WHERE column="value" ORDER BY time;
How can I perform this as a sub-query for all unique column values? I believe the real issue is resetting the variable.
If you want to an incremental number for each column (in the fashion of row_number() in most other databases), you can still use variables:
SELECT t.*,
(#i := if(#c = column, #i + 1,
if(#c := column, 1, 1)
)
) as rank
FROM table t CROSS JOIN
(SELECT #i := 0, #c := '') params
ORDER BY column, time;

generate serial number which resets for a particular condition using mysql query

I have a table named browsekot in mysql database.This table contains menu items that have been ordered from different outlets(restaurants) along with their quantites and price during dine-in. I need to generate a report.
On using below query:
rec.Open "select Outlet,ItemName,id,sum(Quantity) as Quantity, sum(Value) as Value,#i:= #i + 1 as result from (SELECT #i := 0) h , browsekot group by ItemName,Outlet order by #i ", adoconn
gives my this Output:
Sr.No.....Outlet.....Name
1.............Taj...........x
2.............Taj...........y
3.............Mez..........t
4.............Mez..........z
But i want to reset the count #i for each outlet and want my output to be:
Sr.No.....Outlet.....Name
1.............Taj...........x
2.............Taj...........y
1.............Mez..........t
2.............Mez..........z
I want to reset the count in the above query itself as i will be using this query later with SHAPE Command for displaying in datareport. how do i change the above query to reset the count for each outlet?
Use the following SQL:
select Outlet,ItemName,id, Quantity, `Value`,
#i:= IF(Outlet = #last_outlet, #i + 1, 1) as result,
#last_outlet := Outlet
from (SELECT #i := 0, #last_outlet := NULL) h
JOIN (SELECT Outlet, ItemName, id, SUM(Quantity) AS Quantity, SUM(`Value`) as `Value`
FROM browsekot
GROUP BY ItemName,Outlet
ORDER BY Outlet) i
FIDDLE