Using arithmetic operators and/or brackets in a LIMIT clause - mysql

I have the following small subquery in query in stored procedure.
(select f_cnt from results limit (i-1)*10,i*10)
But there is the syntax error:
"(" is not valid at this position, expecting an identifier
So, the question is: do I have a possibility to use brackets and/or arithmetic operators in LIMIT clause?
Documentation says I can use local variables in LIMIT clause within stored procedure. Do I really need to declare and set different variables for this case?
Just in case, link for the code of stored procedure.

You can't do arithmetic at that point
So do instead
SET #sql := CONCAT("SELECT * FROM TEsttable WHERE id In(select f_cnt from results limit ",(i-1) * 10,",",i*10,")");
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Which will produce
SELECT * FROM TEsttable WHERE id In(select f_cnt from results limit 90,100)

Related

Syntax for Branching SQL Query Based on a Parameter

I would love to do a MySQL query like this. I know the syntax is incorrect and I can't use an "if" at the beginning of a query like this. This is for Tableau custom SQL query, by the way. I'd like to have a negative value for AccountID mean displaying all Accounts, and a positive value mean displaying either the account associated with the positive value, or displaying nothing if there is no account associated with the positive value.
if <Parameters.AccID> < 0
select * from Accounts
else
select * from Accounts where id = <Parameters.AccID>
Can someone help me do this with correct syntax?
Since I must use Tableau Desktop as the platform for this, I only have access to query syntax.
You can run such a multi query, if you need it.
SELECT if (Parameters.AccID < 0, #q := 'select * from Accounts',#q := CONCAT('select * from Accounts where id = ',Parameters.AccID));
PREPARE stmt from #q;
EXECUTE stmt;
DEALLOCATE PREPARE stmt

how to set the value of LIMIT using select count(id) from another table |MySQL

I have a scenario where the result must be limited depends on counting ids in another table.
Suppose i have these two tables counter and dispanser,
i want to select the last records in the table counter and limit the selection by counting the number of records in dispanser table.
something like this
select * from counter limit (select count(dispID) from dispanser)
You can't do this without using prepared statements or a stored procedure. From the manual:
LIMIT takes one or two numeric arguments, which must both be nonnegative integer constants
In a stored procedure you could do something like this. COUNT(dispID) is stored into cnt and that variable is then used as the parameter to LIMIT. This is the exception to the above-mentioned rule.
DELIMITER //
CREATE PROCEDURE select_counter()
BEGIN
DECLARE cnt INT;
SELECT COUNT(dispID) INTO cnt FROM dispanser;
SELECT * FROM counter LIMIT cnt;
END //
DELIMITER ;
DBFiddle
Based on conversations in the comments, it sounds like what you're trying to do is get the count from counter for each record in dispanser - if this is wrong, please comment, and I can adjust my response. The best way to accomplish what you're looking for is through joining a subquery with the GROUP BY syntax. Something like this might could work, depending on your schema:
SELECT
d.*,
c.total
FROM
dispanser as d
INNER JOIN (
SELECT
COUNT(*) as 'total',
dispID
FROM
counter
GROUP BY
dispID
) as c
ON c.dispID = d.id
You can try to use dynamic SQL.
Set a variable #num to get an amount from dispanser table.
prepared your SQL statement CONCAT('select * from counter limit ', #num ).
Final use EXECUTE to execute SQL dynamically.
SET #sql = CONCAT('select * from counter order by counterID desc limit ', (SELECT count(dispID) from dispanser));
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
sqlfiddle

Issue with using MAX()

I was answering a question on SO that encountered this issue.
Why I can't use MAX() within a LIMIT?
SELECT *
FROM table
ORDER BY id DESC
LIMIT 0, MAX(id)
Or
SELECT *, MAX(id) AS m
FROM table
ORDER BY id DESC
LIMIT 0, m
Both give a similar syntax error:
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 'MAX(id)' at line 4
Wanted query:
SELECT *
FROM table
ORDER BY id DESC
LIMIT 0, MAX(id)-5
MAX() is an aggregate function over the result rows, but LIMIT is a clause that constrains the number of result rows. In short, you cannot use a function that depends on the result rows while you are still determining which rows will be in the result -- that simply doesn't make any sense.
According to the documentation, LIMIT arguments must either be integer constants or parameters of a prepared query (emphasis mine):
LIMIT takes one or two numeric arguments, which must both be nonnegative integer constants (except when using prepared statements).
The syntax specification simply does not allow a column or function to be used. You would have to pre-compute the value and then use it in a prepared query (or by string substitution, though I would avoid that).
Based on the query you gave in your question:
SELECT *
FROM table
ORDER BY id DESC
LIMIT 0, MAX(id)-5
I suspect that this is the query you actually want:
SELECT *
FROM table
WHERE id <= (SELECT MAX(id) FROM table) - 5
ORDER BY id DESC
Even if it were valid, the first query you gave will not do what you expect if there are gaps in the sequence of the id column (for example, if a row was deleted).
An alternative if you want to get your desired result is to create a dynamic sql.
SET #maxID = (SELECT MAX(ID) FROM tableName);
SET #sql = CONCAT('SELECT *
FROM tableName
ORDER BY ID DESC
LIMIT 0,', #maxID);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
The function MAX cannot be used on the limit.
Here is the documentation:
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_max
The count argument in the limit should be a value so you cannot execute that in one step. Here is the select documentation:
http://dev.mysql.com/doc/refman/5.0/en/select.html
You can do is:
SET #a=(SELECT MAX(ID) FROM table);
PREPARE STMT FROM 'SELECT * FROM table ORDER BY id DESC LIMIT 0, ?';
EXECUTE STMT USING #a;
So it is a tree step here. Get max in a variable. Prepare a statement and than execute it applying the variable to the statement.
You can use the HAVING clause with MAX(id) to obtain your desired result
SELECT *
FROM table1
HAVING id<((SELECT Max(id) FROM table1)-5)
ORDER BY id DESC
Fiddle http://sqlfiddle.com/#!2/16e50/3
ISSUE IS WIth your query::
Select
*
from
myTable,
(SELECT MAX(id) as n
FROM table) temp
ORDER BY id DESC
LIMIT 0, temp.n

Fetching RAND() rows without ORDER BY RAND() in just one query

Using RAND() in MySQL to get a single random row out of a huge table is very slow:
SELECT quote FROM quotes ORDER BY RAND() LIMIT 1
Here is an article about this issue and why this is the case.
Their solution is to use two queries:
SELECT COUNT(*) AS cnt FROM quotes
- Use result to generate a number between 0 and COUNT(*)
SELECT quote FROM quotes LIMIT $generated_number, 1
I was wondering, whether this would be possible in just one query.
So my approach was:
SELECT * FROM quotes
LIMIT (
ROUND(
(SELECT COUNT(*) FROM quotes) * RAND()
)
), 1
But it seams MySQL does not allow any logic within Limit.
Though I can not find any information about this topic, whether this is true.
So my Questions:
How can I use RAND() within LIMIT?
Do you know of any other way to
solve this with just one query?
Is there a reason why a stored procedure cannot be used to create a prepared statement?
DELIMITER //
DROP PROCEDURE IF EXISTS rand_quote//
CREATE PROCEDURE rand_quote()
BEGIN
SET #rand := ROUND((SELECT COUNT(*) FROM quotes) * RAND());
SET #sql := CONCAT('SELECT * FROM quotes LIMIT ', #rand, ', 1');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END;
//
DELIMITER ;
I just figgured this one, that seams like a solution:
SELECT * FROM quotes
WHERE quotes_id = ROUND(
(SELECT COUNT(*) FROM quotes) * RAND()
)
LIMIT 1
But it will work only if quotes_id has no gaps.
I solved the problem by checking max id. Then i made php loop of rand(0, max_id) which checks if object exists. Done.
Much faster then previous ordering by rand.

Where Clause Woes in Stored MySQL Query

What I'd like to do is execute a MySQL query containing a where clause ("result query") that is stored in a column in the database. This column, containing the query, is a result of another query ("original query").
The catches:
The result query's where clause can contain a variable value (or two)
I don't know what the result query will be when executing the original query, so I cannot pass along the variable's value
(The list of result queries as well as the variables in the where clauses will be defined by me, so I will will have a list of all the possible variables.)
Essentially, I need to be able to correlate that variable with any number of other values, one example: a user_id, within the database.
original_query_table | result_query_table
--------------------------------------------------------------
other_id result_query_id | result_query_id result_query
1 1 1 "SELECT ... WHERE user_id = :id "
I know how to do this with two separate queries, but the question is whether this is possible with only one query?
I would do something like this:
SELECT 'select * from table_a where col_a = ?' INTO #query, 1 into #param1 FROM dual;
PREPARE stmt FROM #query;
EXECUTE stmt USING #param1 ;
So converting that into your tables, I guess would look like:
SELECT a.result_query INTO #query, b.result_query_id INTO #param1 FROM result_query_table a, original_query_table b where a.result_query_id = b.result_query_id;
PREPARE stmt FROM #query;
EXECUTE stmt USING #param1 ;
Will you know how many parameters the where clause will need? If that's dynamic, then things could get a bit tricky.