PHP seemingly getting wrong query result - php

So, I built this query in SQLYog, and it returned the results I was looking for. However, when I copy-pasted it into php and used mysqli to run each query / fetch the results, my results were different (namely, one field was null rather than the correct results).
Query:
SET SESSION group_concat_max_len = 1000000;
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN field_number = ''',
wp.field_number,
'''
THEN ',
IF(lng.value = NULL, 'wp.value', 'lng.value'),
' ELSE NULL END) AS ',
CONCAT(fm.field_name, IF(fm.rank <> 0, fm.rank, ''))
)
)INTO #sql
FROM wp_rg_lead_detail wp
JOIN vh_rg_form_map fm
ON fm.field_number = wp.field_number
AND fm.form_id = wp.form_id
LEFT JOIN wp_rg_lead_detail_long lng
ON wp.id = lng.lead_detail_id
WHERE wp.form_id = 1;
SET #sql = CONCAT('SELECT lead_id,', #sql, ' FROM wp_rg_lead_detail wp
LEFT JOIN wp_rg_lead_detail_long lng
ON wp.id = lng.lead_detail_id
WHERE form_id = 1 GROUP BY lead_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
My results are almost exactly the same, the only difference lies in the picture field. Here are some pictures of the difference.

Silly mistake on my part: I had to add in a section to the where clause to ensure that I was getting a single lead_id (where lead_id = $n). I'm still unsure as to exactly why I was getting different responses for the same query in php and yog, but fixing my query fixed the problem.

Related

PDO error "Truncated incorrect DOUBLE value" using placeholder

I have the following PHP code that works perfectly ($qry_str is actually generated in the PHP):
$qry_str = <<<'QRY'
FIND_IN_SET('6-47', attributes)
AND FIND_IN_SET('4-176', attributes)
AND FIND_IN_SET('9-218', attributes)
QRY;
$pdo->query('DROP TEMPORARY TABLE IF EXISTS `temp_attr`');
$temp_sql = <<<"TEMP"
CREATE TEMPORARY TABLE IF NOT EXISTS `temp_attr` (
SELECT product_id, GROUP_CONCAT(CONCAT(group_id, '-', IF (custom_value != '', custom_value, value_id)) SEPARATOR ',') AS attributes
FROM `products_attributes`
GROUP BY `product_id`
HAVING $qry_str
);
TEMP;
$pdo->query($temp_sql);
$sql = "SELECT
m.recommended_price AS msrp,
m.purchase_price AS cost,
pp.USD AS regular_price,
pc.USD AS special_price,
pc.start_date AS start_date,
pc.end_date AS end_date,
pl.permalink AS permalink,
pi.name AS description,
m.sku AS sku,
m.default_category_id AS cat,
m.id AS prod_id
FROM `products` AS m
LEFT JOIN `products_prices` AS pp ON m.id = pp.product_id
LEFT JOIN `products_campaigns` AS pc ON m.id = pc.product_id
LEFT JOIN `permalinks` AS pl ON (m.id = pl.resource_id AND pl.resource = 'product')
LEFT JOIN `products_info` AS pi ON (m.id = pi.product_id)
LEFT JOIN `products_to_categories` AS ptc ON (m.id = ptc.product_id)
INNER JOIN `temp_attr` AS pa
WHERE ptc.category_id = :cat
AND m.status = 1
AND m.id = pa.product_id
LIMIT 55;
";
$data = $pdo->prepare($sql)
->bindValue('cat', 100)
->execute()
->fetchAll();
However, when I use a placeholder in the temp table code, i.e.
$temp_sql = <<<"TEMP"
CREATE TEMPORARY TABLE IF NOT EXISTS `temp_attr` (
SELECT product_id, GROUP_CONCAT(CONCAT(group_id, '-', IF (custom_value != '', custom_value, value_id)) SEPARATOR ',') AS attributes
FROM `products_attributes`
GROUP BY `product_id`
HAVING :qry_str
);
TEMP;
$sth = $pdo->prepare($temp_sql);
$sth->bindValue('qry_str', $qry_str, PDO::PARAM_STR);
$sth->execute();
I get the following error:
PHP Fatal error: Uncaught PDOException: SQLSTATE[22007]: Invalid datetime format: 1292 Truncated incorrect DOUBLE value: 'FIND_IN_SET('6-47', attributes)
AND FIND_IN_SET('4-176', attributes)
AND FIND_IN_SET('9-218', attributes)
AND FIND_IN_SET(...'
There are no datetime columns in this table.
group_id and value_id are integer columns
Since the code works fine without the placeholder, I'm at a loss as to why the use of a placeholder breaks the code. The placeholder in the main SQL works properly.
PHP 8.0
https://dev.mysql.com/doc/refman/8.0/en/prepare.html explains:
Parameter markers can be used only where data values should appear, not for SQL keywords, identifiers, and so forth.
In your case, you're apparently trying to bind an expression with the FIND_IN_SET() function. You can't do that. All expressions and other SQL syntax must be fixed in the query at the time you prepare it. You can use a parameter only in a place where you would otherwise use a scalar literal value. That is, a quoted string or a numeric literal.

how to execute complex mysql queries in laravel

I have one below mysql query that is working fine but i want to run it laravel using prepare statement.
SET #sql = NULL;
SELECT GROUP_CONCAT(CONCAT("SELECT '",colname,":' AS 'Label',GROUP_CONCAT(JSON_UNQUOTE(JSON_EXTRACT(attr_details,'$.", colname,"'))) AS 'val' FROM mytable GROUP BY Label") SEPARATOR " UNION ")
INTO #sql
FROM
(WITH RECURSIVE data AS (
SELECT attr_details,JSON_VALUE(JSON_KEYS(attr_details), '$[0]') AS colname, 0 AS idx FROM mytable
UNION
SELECT attr_details,JSON_VALUE(JSON_KEYS(attr_details), CONCAT('$[', d.idx + 1, ']'))
AS colname, d.idx + 1 AS idx FROM data AS d
WHERE d.idx < JSON_LENGTH(JSON_KEYS(attr_details)) - 1
) SELECT colname
FROM data
GROUP BY colname) V;
PREPARE stmt FROM #sql;
EXECUTE stmt;;
Now i have tried to convert in larvel like below
$PDO=DB::connection('mysql')->getPdo();
$stmt = $PDO->prepare(<<<_OUT
SET #sql = NULL;
SELECT GROUP_CONCAT(CONCAT("SELECT '",colname,"' AS 'Label',GROUP_CONCAT(JSON_UNQUOTE(JSON_EXTRACT(attr_details,'$.", colname,"'))) AS 'val' FROM product_attributes GROUP BY Label") SEPARATOR " UNION ")
INTO #sql
FROM
(WITH RECURSIVE data AS (
SELECT attr_details,JSON_VALUE(JSON_KEYS(attr_details), '$[0]') AS colname, 0 AS idx FROM product_attributes
UNION
SELECT attr_details,JSON_VALUE(JSON_KEYS(attr_details), CONCAT('$[', d.idx + 1, ']'))
AS colname, d.idx + 1 AS idx FROM data AS d
WHERE d.idx < JSON_LENGTH(JSON_KEYS(attr_details)) - 1
) SELECT colname
FROM data
GROUP BY colname) V;
_OUT
);
$stmt->execute();
$result = $stmt->fetchAll();
echo "<pre>"; print_r($result); die;
I am getting this error "syntax error, unexpected 'SELECT' (T_STRING), expecting ')'",
Can anyone help me what i am doing wrong
Please check your quotes at first. In the code "SELECT GROUP_CONCAT(CONCAT("SELECT PHP recognizes that as complete string "SELECT GROUP_CONCAT(CONCAT(" and something undefined SELECT ' with the next string, without concatenation.
At least for me my IDE highlights your code as incorrect. To deal with various quotes try to use that approach
$stmt = $PDO->prepare(<<<_OUT
SELECT * FROM `table` WHERE "1";
_OUT
);
Try to write the request without #sql variable, without PREPARE stm and without EXECUTE stm. I think, PDO will deal with preparing and executing by itself.
$stmt = $PDO->prepare(<<<_OUT
SELECT GROUP_CONCAT() ...
FROM data
GROUP BY colname) V;
_OUT
);
$stmt->execute();
$stmt->fetchAll();
Try to use Laravel approach: DB::select(DB::raw($sql));
SELECT GROUP_CONCAT(CONCAT("SELECT
^-- this quote must be escaped like this: \"
PHP thinks that your SQL string ends there.
Check the other quotes as well.
Edit: Other option might be to wrap the whole SQL to single quotes (') and then just escape those inside the query (by \')

DECLARE syntax in MySQLi Query | When To DECLARE variables in Query

Apologies if posted already.
Searched a lot on google but I'm not understanding how to use DECLARE syntax in MySQL Query.
I'm not expert in MySQL. I'm seeing these codes on internet for DECLARE syntax. Not seen complete query anywhere.
DECLARE #destlist varchar(max)
SET #destlist = SELECT destinations FROM tbl_rings_to_groups WHERE id = '1' AND user_id = '1'
SELECT count( id ) AS totalDestination, group_concat( ring_to_number ) AS phoneNumbers
FROM tbl_destinations
WHERE id IN (CONCAT('SELECT ', REPLACE(#destlist), ',', ' UNION ALL SELECT '))
I'm using this for fetch results.
$result = $db->query("select from
table where something =
somethingElse order by something");
Now, how to use DECLARE in above code.
I'm trying this.
$result = $db->query(" DECLARE #destlist varchar(max)
SET #destlist = SELECT destinations FROM tbl_rings_to_groups WHERE id = '1' AND user_id = '1'
SELECT count( id ) AS totalDestination, group_concat( ring_to_number ) AS phoneNumbers
FROM tbl_destinations
WHERE id IN (CONCAT('SELECT ', REPLACE(#destlist), ',', ' UNION ALL SELECT '))");
Is this correct way to using MySQL DECLARE?

MySQLi: Select price range if empty inputs

I have 2 variables to define a price range for a query. The problem I'm trying to solve is when these are not set in which case I want to show all rows (from 1, if the lower boundary is null, and to max(price) if the upper boundary is null).
I've tried with ifnull, but without success.
$priceFrom = $_POST['priceFrom'];
$priceTo = $_POST['priceTo'];
if(is_null($priceFrom) || is_null($priceTo)){
$priceFrom = 0;
$priceTo = 0;
}
$mass = array();
foreach($data as $current){
$sql = "SELECT p.price,
p.type,
p.area,
p.floor,
p.construction,
p.id as propertyID,
CONCAT(u.name, ' ',u.family) as bname,
p.type as ptype,
n.name as neighborhoodName,
CONCAT(o.name,' ',o.surname,' ',o.family) as fullName
FROM `property` p
LEFT JOIN `neighbour` n ON p.neighbour = n.id
RIGHT JOIN `owners` o ON p.owner = o.id
LEFT JOIN users u ON p.broker = u.id
WHERE `neighbour`= '$current'
AND `price` BETWEEN ifnull('$priceFrom', '1') AND ifnull('$priceTo','2000000')
";}
SQL INJECTION
^ Please Google that! Your code is seriously vulnerable! Your data can be stolen or deleted...
You have to sanitize your inputs at least with mysqli_real_escape_string()
Even better would be to take proper countermeasures to SQL injection and use prepared statements and parametrized queries! (as shown in the code below)
I think the best approach would be to handle the logic by altering the query based on the values of the variables:
$sql = "SELECT p.price,
p.type,
p.area,
p.floor,
p.construction,
p.id as propertyID,
CONCAT(u.name, ' ',u.family) as bname,
p.type as ptype,
n.name as neighborhoodName,
CONCAT(o.name,' ',o.surname,' ',o.family) as fullName
FROM `property` p
LEFT JOIN `neighbour` n ON p.neighbour = n.id
RIGHT JOIN `owners` o ON p.owner = o.id
LEFT JOIN users u ON p.broker = u.id
WHERE `neighbour`= :current "; //note: ending white space is recommended
//lower boundary clause -- if variable null - no restriction
if(!is_null($priceFrom){
sql = sql . " AND `price` >= :priceFrom "; // note: whitespace at end and beginning recommended
}
//upper boundary -- better than to set it to an arbitrary "high" value
if(!is_null($priceTo)){
sql = sql . " AND `price` <= :priceTo "; // note: whitespace at end and beginning recommended
}
This approach allows for any upper value: if there is a serious inflation, a different currency, or suddenly the code will be used to sell housese and there will be products with prices > 200000, you don't need to go out and change a lot of code to make it show...
The parameters need to be bound when executing the query of course:
$stmt = $dbConnection->prepare(sql);
$stmt->bind_param('current', $current);
if(!is_null($priceFrom)){
$stmt->bind_param('priceFrom', $priceFrom);
}
if(!is_null($priceTo)){
$stmt->bind_param('priceTo', $priceTo);
}
//execute and process in same way
$stmt->execute();
Also note: from your code it seems you are issuing queries in a loop. That is bad practice. If the data on which you loop comes
from the DB --> use a JOIN
from an array or other place of the code --> better use an IN clause for the elements
to fetch all data with one query. This helps a lot both in organizing and maintaining the code and results generally in better performance for the most cases.

convert rows into column in codeigniter

I have some problem when converting rows into column in codeigniter, i have a sql query to convert row into column using group_concat...
this is my query
SET ##group_concat_max_len = 5000;
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(idPertanyaan = ''',
idPertanyaan,
''', jawaban, NULL)) AS ',
idPertanyaan
)
) INTO #sql
FROM kuesioner;
SET #sql = CONCAT('SELECT idmember, ', #sql, ' FROM kuesioner GROUP BY idmember');
PREPARE stmt FROM #sql;
EXECUTE stmt;
I can't turn that query into codeigniter model
please tell me create model with this query or how to convert dynamic row into column... thanks
If you create a stored procedure in your database, then within your Model you can do this:
public function yourFunction() {
$query = $this->db->query("CALL `your_stored_procedure()`");
return $query->result_array();
}

Categories