how to execute complex mysql queries in laravel - php

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 \')

Related

FIND_IN_SET universal symbol?

I would like to create query like this:
$get_products = "SELECT P.*, C.`category_name`, GROUP_CONCAT(`category_name` SEPARATOR ', ') AS `cat`
FROM `products` P
NATURAL JOIN
`categories` C
NATURAL JOIN
`product_to_categories`";
WHERE
FIND_IN_SET(`category_name`, :selected_categories)
AND `product_price` BETWEEN :price_min AND :price_max
GROUP BY `product_name`
ORDER BY 1 DESC ";
$db = getConnection();
$stmt = $db->prepare($get_products);
$stmt -> bindValue(selected_categories, $selected_categories);
$stmt -> bindValue(price_min, $price_min);
$stmt -> bindValue(price_max, $price_max);
the problem is that string $selected_categories in some cases is empty, and when it is empty obviously nothing is found.
Is there any parameter which I can use (for example $selected_categories = '*';) and it will cause that FIND_IN_SET will find everything?
or should I create completely new query for case when $selected_categories is empty?
You can use a variable to reference the same replacement parameter twice:
WHERE IF((#selected_categories:=:selected_categories)='*',1,FIND_IN_SET(category_name,#selected_categories))
and test some value you want to mean all ('*' in this example, you could use ='' or IS NULL or something else).
Some prefer using the SQL standard CASE instead of IF; that would look like:
WHERE
CASE
WHEN (#selected_categories := :selected_categories) = '*' THEN 1
ELSE FIND_IN_SET(category_name, #selected_categories)
END
You can solve this with simple logic
WHERE
(
:selected_categories = '*' OR
FIND_IN_SET(`category_name`, :selected_categories)
)
AND `product_price` BETWEEN :price_min AND :price_max

DB Raw query error in Laravel

This is my sql.. When i run it to phpmyadmin it is run ok. But when i am going to run as DB:raw in laravel5.5 it shows error. Here, Auckland is not column name.
$result = DB::select("select DISTINCT(SELECT count(id) FROM
commercial_lease where LENGTH(CONCAT(region,city,"Auckland")) =
LENGTH(location) ) as listing_without_address ,(SELECT count(id) FROM
commercial_lease where LENGTH(CONCAT(region,city,"Auckland")) <
LENGTH(location)) as listing_with_address ,(SELECT count(id) FROM
commercial_lease WHERE first_agent_name = 'None' and
second_agent_name='None') as private_listing from commercial_lease");
You are mixing quotes. Query is covered by double quotes and for Auckland you are trying to put these in double quotes again which is issuing an error.
To fix this issue you can escape your string like \"Auckland\" or using single quotes 'Auckland'
$result = DB::select("select DISTINCT
(SELECT count(id) FROM commercial_lease where LENGTH(CONCAT(region,city,'Auckland')) = LENGTH(location) ) as listing_without_address ,
(SELECT count(id) FROM commercial_lease where LENGTH(CONCAT(region,city,\"Auckland\")) < LENGTH(location)) as listing_with_address ,
(SELECT count(id) FROM commercial_lease WHERE first_agent_name = 'None' and second_agent_name='None') as private_listing from commercial_lease");

How to resolve quote issue in mysql php prepare statement

I have a mysql prepare statement in a PHP script as such:
$stmt = $ln_sph->prepare("SELECT (CASE WHEN n.Id IS NULL THEN e.ExclusionEn ELSE concat(e.ExclusionEn, ' (', n.TitleEn, ' (', n.Naics, '))') END) AS Exclusion
FROM tblExclusion e
LEFT JOIN tblNaics n ON (e.ExclusionClassNaicsId = n.Id)
WHERE NaicsId = :Id");
$stmt->bindValue(':match', $search_query, PDO::PARAM_STR);
$stmt->execute();
$docs = $stmt->fetchAll();
I would like to modify query in the prepare statement to handle this query...
SELECT (CASE WHEN n.Id IS NULL THEN e.ExclusionEn ELSE concat(e.ExclusionEn, ' (','(',n.TitleEn, ' (', n.Naics, '))') END) AS Exclusion
FROM tblExclusion e
LEFT JOIN tblNaics n ON (e.ExclusionClassNaicsId = n.Id)
WHERE NaicsId = :Id
I can run this query just fine directly within mysql but I don't know how to get it in the prepare statement due to the quotes. I think the bindValue might be of use but have not had any luck with it. Any help or point in the right direction would be appreciated.
First break up the SQL into a separate variable. Makes the code cleaner and easier to debug:
$sql = 'SELECT (CASE WHEN n.`Id` IS NULL THEN e.`ExclusionEn` ELSE concat(e.`ExclusionEn`, \' (\',\'(\',n.`TitleEn`, \' (\', n.`Naics`, \'))\') END) AS Exclusion
FROM `tblExclusion` AS e
LEFT JOIN `tblNaics` AS n ON (e.`ExclusionClassNaicsId` = n.`Id`)
WHERE `NaicsId` = :Id';
then you can var_dump to see how it comes out for use and see where it goes wrong.
Other note: You can replace \' with " - but I'm a single-quote fan :)
After that, chuck it into the prepare statement:
$stmt = $ln_sph->prepare($sql);

Perform an Inner Join in Zend PHP Framework

I want to perform an inner join on two table.
Table A -
item_id
item_title
varX
Table B -
item_id
varY
someVar
This is how I've done this using a RAW SQL query.
$sql = 'SELECT tableA.item_id, tableY.item_title AS Name, 5 * varX + 5 * count(*) AS myScore
FROM tableA
INNER JOIN tableY ON tableA.item_id=tableY.item_id
WHERE someVar=\'8\'
GROUP BY item_id
ORDER BY myScore DESC
LIMIT 10';
$stmt = $this->_db->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll();
Now I want to do this using a Zend Query.
This is what I've written -
$data = $this->_db->select()
->from(array('tablA'=>'tableA'), array('item_id', 'item_title'), 'myScore'=>'(5*'tableA'.'varX') + 5*count(*)')
->joinInner(array('tablB'=>'tableB'), 'tablA'.'item_id' = 'tablB'.'item_id')
->where('someVar = 8')
->GROUP('item_id')
->order('myScore DESC')
->limit(10);
$dataResult = $this->_db->fetchAll($data);
But I get this error -
syntax error, unexpected '=>' (T_DOUBLE_ARROW), expecting ',' or ')'
in line ->from(array('tablA'=>'tableA'), array('item_id', 'item_title'), 'myScore'=>'(5'tableA'.'varX') + 5*count()')
Not sure what to do do here as I've read the official documentation but still can't figure this out. Any help is appreciated!
The quotes were used in wrong way in your code. Also, tt seems like, you have used the unnecessary third parameter for 'myScore' field. It should be placed in the second parameterTry the following:
...
$data = $this->_db->select()
->from(array('tablA'=>'tableA'), array('item_id', 'item_title', 'myScore'=>'(5 * tableA.varX) + 5*count(*)'))
->joinInner(array('tablB'=>'tableB'), 'tablA.item_id = tablB.item_id')
->where('someVar = 8')
->group('tablA.item_id')
->order('myScore DESC')
->limit(10);

PHP seemingly getting wrong query result

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.

Categories