1390 Prepared statement contains too many placeholders using Laravel 5.6 - mysql

Getting following error
SQLSTATE[HY000]: General error: 1390 Prepared statement contains too many placeholders
My query has become due to data in the table recently
SELECT
*
FROM
table
WHERE col1 = 'some-val'
AND col2 NOT IN ('va1', 'val2', 80k values... )
I am using Laravel 5.6
$data_will_be_skipped = OtherModel::select('code')
->where('col1', 0)
->orWhere('col2', 1)
->groupBy('col3')
->pluck('col3')->toArray();
$data_will_be_skipped is now approx 80k arrays
Model::where('col1', 'some-val')->whereNotIn('col2', $data_will_be_skipped)->get();

MySQL has a limit of 65,535 parameters in prepared statements.
Use a subquery instead:
$data_will_be_skipped = OtherModel::select('col3')
->where('col1', 0)
->orWhere('col2', 1);
Model::where('col1', 'some-val')
->whereNotIn('col2', $data_will_be_skipped)
->get();

No matter how many items u have in array to check in wherein
the simple way to do it
$data = model::whereRaw("id not in (".implode(',',$data_will_be_skipped).")")->get();

Related

Update and select in single query . Sql syntax error in Scala

I am trying to query the database using the below query. It works fine when I run the query in mysql server. But when I run the same query in scala it throws error.
I want to get a single row in db whose cid_status is "unreserved" and cid_curprocess is 'process1'and update the same cid_status to "reserved" and get back the cid_issueid of that row
Below is the query.
val query = "SET #LastUpdateID := 0; UPDATE table_details INNER JOIN
(SELECT cid_issueid FROM cen_issue_details WHERE
cid_curprocess='process1' AND cid_status='unreserved' LIMIT 1) AS
final ON cen_issue_details.cid_issueid=final.cid_issueid SET
cen_issue_details.cid_status ='reserved',cen_issue_details.cid_issueid
= (SELECT #LastUpdateID := cen_issue_details.cid_issueid);SELECT #LastUpdateID AS LastUpdateID;
val rs = statement.executeUpdate(query)
I get the below error:
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: 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 'UPDATE table_details INNER JOIN (SELECT cid_issueid FROM cen_issue_details W' at line 1
Also I am not sure whether to use executeUpdate or executeQuery since the query does both SELECT and UPDATE.
Statement.executeupdate(String) accepts only a single statement, but you have provided two.
See the docs at https://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#executeUpdate(java.lang.String)
This question discusses the options for doing multiple statements in a single roundtrip with JDBC: Two different prepared statements in one single batch

MySQL phpmyadmin - SELECT FOR UPDATE not recognised

I'm writing a PHP program and wanna to implement row-level locking to avoid concurrent user update/delete for the same record.
But I hit error "Unrecognised keyword" when using SELECT FOR UPDATE. Table type is innoDB.
Am i missing any setup for my database?
SELECT * FROM companyTable
WHERE companyId = "0000001"
FOR UPDATE;
Error
Static analysis:
1 errors were found during analysis.
Unrecognized keyword. (near "FOR" at position 57)
SQL query: Documentation
SELECT * FROM companyTable WHERE companyId = "0000001" FOR LIMIT 0, 30
MySQL said: Documentation
#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 'LIMIT 0, 30' at line 3
There Is an Syntax Error Try this:
Its Select All Records From 1 - 30
SELECT * FROM companyTable WHERE companyId = "0000001" ORDER BY id LIMIT 30;
First problem seems to be, that in your SQL query is missing keyword UPDATE
SELECT * FROM companyTable WHERE companyId = "0000001" FOR LIMIT 0, 30
And the second issue can be, that syntax SELECT ... FOR UPDATE in MySQL doesn't support LIMIT.
So your SQL query should be:
SELECT * FROM companyTable WHERE companyId = "0000001" FOR UPDATE
In phpmyadmin, it is difficult to remove auto added LIMIT clause - try another MySQL client.
PhpMyAdmin is not build to handle(Test) transaction control, use Mysql Console or php session instead
and use "begin" to start the Transaction before the code
begin;
select * from `tblx` where `idx`=1 for update;
update `tblx` set `field`='xx' where `idx`=1;
commit;

Delete entry with lowest ID

I just want to delete the row with the lowest ID.
I'm trying this:
$query = 'DELETE FROM PATH\TO\ENTITY ORDER BY id ASC LIMIT 1';
$query = $this->entityManager->createQuery($query);
$query->execute();
And getting this error:
[Syntax Error] line 0, col 53: Error: Expected end of string, got 'BY'
Maybe I'm using the wrong approach.
Any suggestions how to delete the entry with the lowest id in one database call?
As Kwido said, you miss the entity alias. But the query will still not be able to execute.
First, DQL does not support LIMIT expression. It is MySQL-specific feature, is not an ANSI SQL. Other platform drivers have an own implementations of this behavior, all of them provided by common interface: setFirstResult()/setMaxResult() of Query object.
Second, DQL does not support DELETE with ORDER BY clause (see language EBNF). It is non-standard feature too, but can not be implemented for other drivers, so Doctrine does not allow it.
If you need to execute this query, you will have to use a native SQL.
Define an alias for your entity as you use DQL. See: Doctrine - By DQL
$query = $this->entityManager->createQuery('SELECT e FROM MyEntity e ORDER BY e.id ASC');
$query->setMaxResults(1); // LIMITS 1
$entities = $query->getResult();
if (count($entities) > 0) {
$query = $this->entityManager->createQuery('DELETE FROM MyEntity e WHERE e.id = :identifier');
$query->setParameter("identifier", $entities[0]->getId());
$query->execute();
}
Replace entityAlias with the first letter of your entity classname, which is the most common practice with Doctrine.
// Edit - as #Timurib stated DQL doesn't know the LIMIT. Should've used setMaxResults.
// Edit2 - As ORDER BY is not supported by the DELETE statement, but only the WHERE clause. We're now using another query to return the identifier before deleting. See DQL - Statements
$query = 'DELETE FROM table ORDER BY id ASC LIMIT 1';
$stmt = $this->entityManager->getConnection()->prepare($query);
$stmt->execute();
You cannot delete or update from entityManager. First you have to select/find the entity from Repository and then remove it. My suggestion works for raw SQL query instead.

Is there such mysql syntax to end/limit mysql query?

Is there any mysql syntax to stop the query from being append by user input? If the query is
SELECT *
FROM `username`
WHERE `type` = 'client'
END / LIMIT / whatever syntax here;
the query should stop at 'client' so if user try to add his own query by adding OR such as this:
SELECT *
FROM `username`
WHERE `type` = 'client'
OR 1 = 1;
it will not work. Thanks in advance.
I will assume that you are using PHP and that 'client' is received as a parameter via $_POST from the user. In this scenario I think that what you want to do is prevent is SQL injection. If so you should solve it by using mysql_real_escape_string() to sanitize your input parameters:
// This could be supplied by a user, for example
$type = $POST['type'];
// Formulate Query
// This is the best way to perform an SQL query
// For more examples, see mysql_real_escape_string()
$query = sprintf("SELECT * FROM username
WHERE type='%s',
mysql_real_escape_string($type));
// Perform Query
$result = mysql_query($query);
...
I took this sample from the mysql-query reference and adapted it for your needs.

MySQL Syntax error message "Operand should contain 1 column(s)"

I tried running the following statement:
INSERT INTO VOUCHER (VOUCHER_NUMBER, BOOK_ID, DENOMINATION)
SELECT (a.number, b.ID, b.DENOMINATION)
FROM temp_cheques a, BOOK b
WHERE a.number BETWEEN b.START_NUMBER AND b.START_NUMBER+b.UNITS-1;
which, as I understand it, should insert into VOUCHER each record from temp_cheques with the ID and DENOMINATION fields corresponding to entries in the BOOK table (temp_cheques comes from a database backup, which I'm trying to recreate in a different format). However, when I run it, I get an error:
Error: Operand should contain 1 column(s)
SQLState: 21000
ErrorCode: 1241
I'm running this in SQuirrel and have not had issues with any other queries. Is there something wrong with the syntax of my query?
EDIT:
The structure of BOOK is:
ID int(11)
START_NUMBER int(11)
UNITS int(11)
DENOMINATION double(5,2)
The structure of temp_cheques is:
ID int(11)
number varchar(20)
Try removing the parenthesis from the SELECT clause. From Microsoft TechNet, the correct syntax for an INSERT statement using a SELECT clause is the following.
INSERT INTO MyTable (PriKey, Description)
SELECT ForeignKey, Description
FROM SomeView
The error you're getting, "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay.", is actually correct, assuming you have many rows in both BOOK and temp_cheques. You are trying to query all rows from both tables and make a cross-reference, resulting in an m*n size query. SQL Server is trying to warn you of this, before performing a potentially long operation.
Set SQL_BIG_SELECTS = 1 before running this statement, and try again. It should work, but note that this operation may take a long time.
Does B contain the UNITS column?
What is the table structure for temp_cheques and Book?
EDIT: As I said in comments, all the columns should be numeric when doing +/- and when comparing. Does the following simple SELECT work?
SELECT b.START_NUMBER+b.UNITS-1 FROM Books B
I don't have a MySQL instance handy, but my first guess is the WHERE clause:
WHERE a.number BETWEEN b.START_NUMBER AND b.START_NUMBER+b.UNITS-1;
I imagine that the MySQL parser may be interpreting that as:
WHERE number
(BETWEEN start_number AND start_number) + units - 1
Try wrapping everything in parentheses, ie:
WHERE a.number BETWEEN b.START_NUMBER AND (b.START_NUMBER + b.UNITS - 1);
The final version of the query is as follows:
Set SQL_BIG_SELECTS = 1;
INSERT INTO VOUCHER (VOUCHER_NUMBER, BOOK_ID, DENOMINATION)
SELECT a.number, b.ID, b.DENOMINATION
FROM temp_cheques a, BOOK b
WHERE a.number BETWEEN b.START_NUMBER AND (b.START_NUMBER+b.UNITS-1);
The parsing of the BETWEEN statement required parentheses, the SELECT did not, and because of the size of the two tables (215000 records in temp_cheques, 8000 in BOOK) I was breaking a limit on the select size, requiring me to set SQL_BIG_SELECTS = 1.
I ran into the same error when using Spring Repositories.
My repository contained a method like:
List<SomeEntity> findAllBySomeId(List<String> ids);
This is working fine when running integration tests against an in-memory database (h2). However against a stand alone database like MySql is was failing with the same error.
I've solved it by changing the method interface to:
List<someEntity findBySomeIdIn(List<String> ids);
Note: there is no difference between find and findAll. As described here: Spring Data JPA difference between findBy / findAllBy