CakePHP 1.3 query method gives SQL 1064 error - php

I wrote a custom query to use in CakePHP 1.3 The query is as follows:
SELECT artists.id, artists.name, artists.image_id, genres.genre
FROM artists
LEFT JOIN coupling_artist_genre
ON artists.id = coupling_artist_genre.id_in
LEFT JOIN genres
ON coupling_artist_genre.id_out = genres.id
WHERE artists.name LIKE '%tee%'
AND genres.id IN (12,14)
ORDER BY artists.name ASC
LIMIT 0,25
When I call this like this:
$this -> Artist -> query ($sql);
I get this 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 '
However, when I copy the generated query and paste it into PHPMyAdmin it works fine. No warnings, no errors, and most importantly: the result I expect.
Does anyone know what could cause this difference between Cake and PMA?
Edit: This is how the query is generated:
$query = "SELECT artists.id, artists.name, artists.image_id";
if ($genres != ' ' && strlen ($genres) > 0)
{
$query .= ", genres.genre";
}
$query .= " FROM artists";
if ($genres != ' ' && strlen ($genres) > 0)
{
$query .= " LEFT JOIN coupling_artist_genre ON artists.id = coupling_artist_genre.id_in";
$query .= " LEFT JOIN genres ON coupling_artist_genre.id_out = genres.id";
}
$query .= " WHERE";
if ($searchString != '' && strlen ($searchString) > 0)
{
$searchString = $searchString == ' ' ? '' : $searchString;
$query .= " artists.name LIKE '%".$searchString."%'";
}
if ($searchString != ' ' && strlen ($searchString) > 0 && $genres != ' ' && strlen ($genres) > 0)
{
$query .= " AND";
}
if ($genres != ' ' && strlen ($genres) > 0)
{
$query .= " genres.id IN (".$genres.")";
}
$query .= " ORDER BY artists.name ASC LIMIT " . ($page - 1) * 25 . ",25";
$this -> set ('artists', $this -> Artist -> query ($query));

I think there are case when your queries end up like this:
" ...
WHERE
ORDER BY ... "
or
" ...
WHERE artists.name LIKE '%tee%'
AND
ORDER BY ... "
Try this:
$query .= " WHERE True ";
if ($searchString != '' && strlen ($searchString) > 0)
{
$searchString = $searchString == ' ' ? '' : $searchString;
$query .= " AND artists.name LIKE '%".$searchString."%'";
}
if ($genres != ' ' && strlen ($genres) > 0)
{
$query .= " AND genres.id IN (".$genres.")";
}
$query .= " ORDER BY artists.name ASC LIMIT " . ($page - 1) * 25 . ",25";
$this -> set ('artists', $this -> Artist -> query ($query));

Tried to post this earlier, but I couldn't without 100 reputation. Anyway here's the answer I tried to post earlier:
Dear visitors of this question. I am terribly sorry (especially for you ypercube because you took the time to think about AND answer my question!).
I just discovered that I made a very stupid mistake. Down in my controller, in a totally different method that shouldn't even be executed I had another query in a die() call. That was the query MySQL was complaining about. I never expected it to be executed but alas, it was the query causing my error. Seeing as I didn't need it anymore I deleted it and my error was gone.
Once again, I'm sorry for all of you that put time in this question. I shall try to be more careful in the future!

Related

PHP filters combining into one SQL query

I'm trying to filter through my database according to filters done by visitors.
$query = "select * from Sheet1 where";
//filter query start
if (!empty($brand)) {
$branddata = implode("','", $brand);
//testing removing query
$query .= " Brand in('$branddata') and";
}
if (!empty($model)) {
$modeldata = implode("','", $model);
//testing removing query
$query .= " Model in('$modeldata') and";
}
/* if(!empty($model) && empty($brand)){
} */
if (!empty($spower) && !empty($epower)) {
$query .= " Power>='$spower' and Power<='$epower' and";
}
if (!empty($sprice) && !empty($eprice)) {
$query .= " Doors>='$sprice' and Doors<='$eprice'";
}
$rs = mysqli_query($conn, $query) or die("Error : " . mysqli_error($conn));
The result I wish to get is a sql query that works and has correct syntax. Such as select * from Sheet1 where Doors>='$sprice' and Doors<='$eprice', if the visitor is filtering by price.
Currently, my code is made so that it simply adds a certain string to the variable. This means that if you don't filter by model, it skips model, because the model variable is empty. The problem comes to if you filter by power, the SQL will become select * from Sheet1 where Power>='$spower' and Power<='$epower' and. Obviously this doesn't work, so I need help in making the code make sure it works for every combination of filters.
Append $query .= " 1 = 1"; at the end. I did some modification in your given code. Have a look.
<?php
$query = "SELECT * FROM `Sheet1` WHERE";
//filter query start
if(!empty($brand)){
$branddata = implode("','",$brand);
$query .= " (Brand in('$branddata')) AND";
}
if(!empty($model)){
$modeldata = implode("','",$model);
$query .= " (Model in('$modeldata')) AND";
}
if(!empty($spower) && !empty($epower)){
$query .= " (Power>='$spower' AND Power<='$epower') AND";
}
if(!empty($sprice) && !empty($eprice)){
$query .= " (Doors>='$sprice' AND Doors<='$eprice') AND"; //Added 'AND'
}
$query .= " 1 = 1"; //Added new line
$rs = mysqli_query($conn,$query) or die("Error : ".mysqli_error($conn));
?>
Add AND on each query appended in if conditions. Then, at last add $query .= " 1 = 1";. Which will save you from extra AND coming at the end. If none of the conditions satisfy, then your query will be SELECT * FROM Sheet1 WHERE 1 = 1. Simple. And, don't forget to differentiate between conditions in query. Differentiate your conditions like how I did by opening and closing brackets.
I would do it this way
$filters=array();
if(!empty($brand)){
$branddata =implode("','",$brand);
//testing removing query
$filters[]= " Brand in('$branddata')";
}
if(!empty($model)){
$modeldata =implode("','",$model);
//testing removing query
$filters[]= " Model in('$modeldata') and";
}
if(!empty($spower) && !empty($epower)){
$filters[]= " Power>='$spower' and Power<='$epower' and";
}
if(!empty($sprice) && !empty($eprice)){
$filters[]= " Doors>='$sprice' and Doors<='$eprice'";
}
$query = "select * from Sheet1 where";
foreach ($filters as $filter) {
$query.=' AND '.$filter;
}
$rs = mysqli_query($conn,$query) or die("Error : ".mysqli_error($conn));

Ignore function on if condition PHP

I have some code but I want it to ignore 'customer::$data['vehicle_id']' when category_id = 1, 4, 9.
I've struggled with the code below and to add another function is out of my capabilities, so any advice would be great. Thanks in advance.
If vehicle_id is not selected it works fine.
if (empty($_GET['manufacturer_id'])) {
$manufacturers_query = database::query(
"select distinct m.id, m.name from ". DB_TABLE_PRODUCTS ." p
left join ". DB_TABLE_MANUFACTURERS ." m on m.id = p.manufacturer_id ".
(!empty($_GET['category_id']) ? " left join " . DB_TABLE_PRODUCTS_TO_CATEGORIES . " pc on pc.product_id = p.id " : "").
(!empty(customer::$data['vehicle_id']) ? " left join " . DB_TABLE_PRODUCTS_TO_VEHICLES . " ptv on ptv.product_id = p.id " : "").
"where p.status
and manufacturer_id
". (!empty($_GET['category_id']) ? "and pc.category_id = " . (int)$_GET['category_id'] : "") ."
". (!empty(customer::$data['vehicle_id']) ? "and ptv.vehicle_id = " . (int)customer::$data['vehicle_id'] : "") ."
order by m.name asc;"
);
I've tried using this:
". (!empty(customer::$data['vehicle_id']) && (!empty($_GET['category_id']) || !array_intersect(array(1, 4, 9), $_GET['category_id'])) ? "and ptv.vehicle_id = " . (int)customer::$data['vehicle_id'] : "") ."
EDIT:
while($manufacturer = database::fetch($manufacturers_query)) {
$box_filter->snippets['manufacturers'][] = array(
'id' => $manufacturer['id'],
'name' => $manufacturer['name'],
'href' => document::ilink('manufacturer', array('manufacturer_id' => $manufacturer['id'])),
);
}
I have taken your rather messy code and refactored it so it is readable, maintainable and better in a lot of small and big ways. It's by no means perfect, but now it can be reasoned about.
I also eliminated the SQL Injection opportunities for you, but you still need to redesign your database::query() function so it accepts an array of parameters to be used with your sql query in a prepared statement execution. I used named placeholders in your query to make it readable.
Doing the refactor this way, allowed me to add a boolean flag I can set if your ignore condition is true ($_GET['category_id'] equals one of [1,4,9])
if (empty($_GET['manufacturer_id']))
{
$ignoreVehicleId = false;
$params = [];
$query = "select distinct m.id, m.name
from ${DB_TABLE_PRODUCTS} p
left join ${DB_TABLE_MANUFACTURERS} m on m.id = p.manufacturer_id ";
if( !empty($_GET['category_id'])
{
$query .= " left join ${DB_TABLE_PRODUCTS_TO_CATEGORIES} pc on pc.product_id = p.id ";
if(in_array($_GET["category_id"], [1,4,9]) // <--- This array should be better documented to not use MAGIC NUMBERS. What is 1,4 or 9?
{
$ignoreVehicleId = true;
}
}
if( $ignoreVehicleId === false && !empty( customer::$data['vehicle_id'])
{
$query .= " left join ${DB_TABLE_PRODUCTS_TO_VEHICLES} ptv on ptv.product_id = p.id ";
}
$query .= "where p.status and manufacturer_id ";
/*
* In the following two IF's named parameters for prepared statements are being used.
* You need to refactor the database::query() function to accept a params array.
* Read up on using prepared statements with mysqli_* or better, PDO.
*
* DO NOT BUILD QUERIES WITH VARIABLES ANY OTHER WAY!!!
*
* If you do you are asking to be pwned by someone using your less than secure
* practises to do SQL Injection.
*/
if( !empty($_GET['category_id'])
{
" and pc.category_id = :category_id ";
$params[":category_id"] = (int)$_GET['category_id'];
}
if( $ignoreVehicleId === false && !empty(customer::$data['vehicle_id'])
{
" and ptv.vehicle_id = :vehicle_id ";
$params[":vehicle_id"] = (int)customer::$data['vehicle_id'];
}
$query .= " order by m.name asc;"
$manufacturers_query = database::query($query, $params);
}

Opencart sort by newest product

The question is kind of similar to randomize default products in opencart, but simpler. I am trying to have my products listed by newest first. I made the following change in catalog/model/catalog/product.php:
if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {
if ($data['sort'] == 'pd.name' || $data['sort'] == 'p.model') {
$sql .= " ORDER BY LCASE(" . $data['sort'] . ")";
} else {
$sql .= " ORDER BY " . $data['sort'];
}
} else {
$sql .= " ORDER BY p.date_added";
}
But I don't see this having any effect to the default sort.
I don't know which version of OC do You have, but You should also consider modifying the order part. In OC 1.5.5 it is like this:
if (isset($data['order']) && ($data['order'] == 'DESC')) {
$sql .= " DESC, LCASE(pd.name) DESC";
} else {
$sql .= " ASC, LCASE(pd.name) ASC";
}
In this case, with Your change and if no sort nor order data is provided the products will be sorted from the oldest to newest (oldest first). I recommend changing the order part to something like this:
if (isset($data['order']) && ($data['order'] == 'ASC')) {
$sql .= " ASC, LCASE(pd.name) ASC";
} else {
$sql .= " DESC, LCASE(pd.name) DESC";
}
If You are saying that there is no change also try to delete Your browser session as the sorting, filtering and other options are stored there.

How to reduce Mysql execution Time?

I'm using Mysql 5.5.16. I've a query where i combine 3 queries using union opeartor... Each query contains more than 10000 records.
My Query looks like...
$search_qry1 = " (SELECT PC_name as name FROM profile_category_tbl WHERE PC_status=1 and PC_parentid!=0 and (";
$search_qry2 = " (SELECT PROFKEY_name as name FROM profile_keywords_tbl WHERE PROFKEY_status=1 and (";
$search_qry3 = " (SELECT COM_name as name FROM ".$C."_company_profile_tbl WHERE COM_status=1 and (";
$order_by = "ORDER BY";
$word_length = explode(" ", $my_data);
for($i=0; $i <= count($word_length) - 1; $i++) {
$dt = $word_length[$i];
if ($dt) {
if ($i == 0) {
$or="";
}
else {
$or="OR";
}
$search_qry1 .= " $or regex_replace('[^a-zA-Z0-9\-]','',remove_specialCharacter(PC_name)) LIKE '%$dt%' ";
$search_qry2 .= " $or regex_replace('[^a-zA-Z0-9\-]','',remove_specialCharacter(PROFKEY_name)) LIKE '%$dt%' ";
$search_qry3 .= " $or regex_replace('[^a-zA-Z0-9\-]','',remove_specialCharacter(COM_name)) LIKE '%$dt%' ";
$order_by .= " IF(name LIKE '%$dt%',1,0) ";
}
if ($i == count($word_length) - 1) {
$search_qry1 .= ")";
$search_qry2 .= ")";
$search_qry3 .= ")";
}
if ($i != count($word_length) - 1) {
$order_by .= "+ ";
}
}
$search_qry1 .= " GROUP BY PC_name )";
$search_qry2 .= " GROUP BY PROFKEY_name )";
$search_qry3 .= " GROUP BY COM_name )";
$search_qry = "select name from ( $search_qry1 UNION ALL $search_qry2 UNION ALL $search_qry3 )a $order_by desc LIMIT 0,25";
It works perfectly... but it takes the time to execute it - more than 4 secs... for each search.... how possible to reduce its execution time?.... If anyone know an idea about this please let me know....
Actually I run this query for auto-complete search. If type "Rest" in search box, then
The Output Should be,
Family Restaurants
Everest Park
Fast Food Restaurants
Everest Park Residency
Fish Restaurant
Everest Power Solution
Fish Restaurants
Thanks in Advance,
Jeni
You are using regex_replace and like "%foobar%",
that actually slows down your query significat, since mySql has to do a fulltext search and the regex operation on every single row. Maybe it's faster if you do these operations after you fetched your results, using php instead of mysql.
The main problem is that you're doing a full scan of each table to check the like '%$dt%' condition. No matter which indices you have on the table, none of them will be used.
But if you post the final SQL sentence and what are you trying to do maybe we could help.

Can't get spaces in my SQL statement

I have two variables in my WHERE statement. I cant seem to separate them with a space so i end up getting a syntax error. Thanks for the help.
(I am using codeigniter)
btw i have tried setting a $space variable, and putting spaces before the and, after setting both variables, and in the sql.
ERROR
Error Number: 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 'source_adusers.ad_account="Wolfs, Marc" GROUP BY rollout_systems.eam_user LIMIT ' at line 2
SELECT *, COUNT(rollout_systems.EAM_USER) as systems FROM rollout_systems LEFT JOIN source_adusers ON rollout_systems.EAM_User = source_adusers.ad_account WHERE rollout_systems.scope_ID = 3AND source_adusers.ad_account="Wolfs, Marc" GROUP BY rollout_systems.eam_user LIMIT 0,50
Line Number: 330
PHP
if ($this->session->userdata('scopeId') != NULL) {
$where1 = 'WHERE rollout_systems.scope_ID = '. $this->session->userdata('scopeId') . '';
} else {
redirect('/headquarters/home');;
}
if ($search) {
$where2 = ' AND rollout_systems.sys_name ="'.$search.'"';
} else {
$where2 = '';
}
$query = $this->db->query('SELECT * FROM rollout_systems LEFT JOIN source_adusers
ON rollout_systems.eam_user = source_adusers.ad_account '. $where1 .''. $where2 .' GROUP BY rollout_systems.sys_name LIMIT '.$limit.',50');
what if you keep the spaces and the AND in the $query, instead of building them into your where variables? Then your $where 2 just needs to work without affecting the query - thus 0=0.
if ($this->session->userdata('scopeId') != NULL) {
$where1 = 'WHERE rollout_systems.scope_ID = '. $this->session->userdata('scopeId') . '';
} else {
redirect('/headquarters/home');;
}
if ($search) {
$where2 = 'rollout_systems.sys_name ="'.$search.'"';
} else {
$where2 = '0=0';
}
$query = $this->db->query('SELECT * FROM rollout_systems LEFT JOIN source_adusers
ON rollout_systems.eam_user = source_adusers.ad_account '. $where1 .' and '. $where2 .' GROUP BY rollout_systems.sys_name LIMIT '.$limit.',50');
Just add a space between the two vars - '. $where1 .' '. $where2 .'
As pointed out by others you really should be escaping your user input using mysql_real_escape_string() or intval() if you are expecting an integer value. If you are using PDO or mysqli use prepared statements.
If $this->db is a PDO instance you could use -
$params = array();
if ($this->session->userdata('scopeId') != NULL) {
$where = 'WHERE rollout_systems.scope_ID = ?';
$params[] = $this->session->userdata('scopeId');
} else {
redirect('/headquarters/home');;
}
if ($search) {
$where .= ' AND rollout_systems.sys_name = ?';
$params[] = $search;
}
$sql = "SELECT * FROM rollout_systems
LEFT JOIN source_adusers ON rollout_systems.eam_user = source_adusers.ad_account
$where
GROUP BY rollout_systems.sys_name
LIMIT ?, 50";
$params[] = $limit;
$query = $this->db->prepare($sql);
$query->execute($params);
$where = array();
if ($this->session->userdata('scopeId') != NULL) {
// better to escape your parameter here unless you trust it totally
// judging by its name, it's user-provided data, so I wouldn't trust it
$where[] = 'rollout_systems.scope_ID = '. $this->session->userdata('scopeId');
} else {
redirect('/headquarters/home');
// you may need to exit here after redirection, depends on your implementation
}
if ($search) {
// once again don't forget to escape $search in real application
$where[] = "rollout_systems.sys_name = '" . $search . "'";
}
$query = $this->db->query("
SELECT
*
FROM
`rollout_systems`
LEFT JOIN
`source_adusers`
ON rollout_systems.eam_user = source_adusers.ad_account
WHERE
" . implode (' AND ', $where) . "
GROUP BY
rollout_systems.sys_name
LIMIT " . $limit /* escape it! */ . ",50"
);
You also have the option to use the PHP syntax
$sql = " blah blah {$my_var} {$my_other_var} ";

Categories