Convert Dynamic Column Mysql to JSON - php

Heiii i have some problem, i have a dynamic query / pivot table mysql, i want convert this query to json, this is my script php
$db=new mysqli($dbhost,$dbuser,$dbpass,$dbname);
$supervisor='ganda.padeardja';
//-- query
$multi="
SET #SQL = NULL;
SELECT
GROUP_CONCAT(
DISTINCT CONCAT(
'MAX(IF(salesman = ''',
salesman,
''', total_aktivitas, 0)) AS `',
salesman,
'`'
)
) INTO #SQL
FROM
v_dashboard_supervisor_activity2
WHERE
supervisor LIKE '%ganda.padeardja%';
SET #SQL = CONCAT(
'SELECT v_calendar.cdate as aktivitas,',
#SQL,
' FROM v_dashboard_supervisor_activity2 RIGHT JOIN v_calendar ON v_calendar.cdate=v_dashboard_supervisor_activity2.tgl_aktivitas WHERE cdate BETWEEN CURDATE() - INTERVAL 6 DAY AND CURDATE() GROUP BY cdate ORDER BY cdate ASC '
);
PREPARE stmt
FROM
#SQL;
EXECUTE stmt;
";
if($result=$db->multi_query($multi)) {
$i=0;
do{
$db->next_result();
if(++$i==5)$result=$db->store_result();
}while($db->more_results() && $i<5);
}
$data=array();
$i=0;
print_r($db->error_list);
while($meta=$result->fetch_field()){
$data[$i]=array();
$data[$i]['name']=$meta->name;
$data[$i++]['data']=array();
}
$result->data_seek(0);
while($datas=$result->fetch_row()){
$i=0;
foreach($datas as $d){
$data[$i++]['data'][]=$d;
}
}
echo json_encode($data);
But result are :
Array ( )
Fatal error: Call to a member function fetch_field() on a non-object
in D:\xampp\htdocs\test\index_try2.php on line 53
And the results I expected was like this :
[{"name":"aktivitas","data":`["2015-11-22","2015-11-23","2015-11-24","2015-11-25","2015-11-26","2015-11-27","2015-11-28"]},
{"name":"abdul.qodir","data":["0","11","4","6","2","6","1"]},{"name":"andrinanta.putra","data":["0","4","7","6","5","0","0"]},{"name":"ganda.sls","data":["0","0","0","0","0","0","0"]},{"name":"paulus.jatmiko","data":["0","5","5","4","5","5","0"]},{"name":"sandy.wibowo","data":["0","0","0","6","5","12","0"]}]
Can you help me where I made ​​a mistake and miss something ??

Related

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

Paramaterize Case Statement Using ODBC

I am selecting data from an MS SQL DB using a similar query to this:
$result = odbc_prepare(
$connection,
"SELECT
t1.id, thumbnail, description, brand, vendor,
case
when ".implode(' AND ', $exactSearchTermDesc)." then 1
else 0
end as exactdescriptionmatch,
case
when ".implode(' AND ', $exactSearchTermMarkDesc)."". $exactThesaurusMarkDesc ."
then 1 else 0
end as exactcontentmatch,
case
when ".implode(' AND ', $searchTermDesc)."" . $thesaurusDesc ." then 1
else 0
end as descriptionmatch,
case
when ".implode(' AND ', $searchTermMarkDesc)."". $thesaurusMarkDesc ." then 1
else 0
end as contentmatch
FROM Martin.dbo.item_search"
);
odbc_execute($result);
How do I parameterize the variables in the case statements?
I tried, for example, just trying to paramaterize the first variable with this to no avail...
$exactSearchTermDesc = implode(' AND ', $exactSearchTermDesc);
$result = odbc_prepare(
$connection,
"SELECT
t1.id, thumbnail, description, brand, vendor,
case when ? then 1 else 0 end as exactdescriptionmatch,
case when ".implode(' AND ', $exactSearchTermMarkDesc)."". $exactThesaurusMarkDesc ." then 1 else 0 end as exactcontentmatch,
case when ".implode(' AND ', $searchTermDesc)."" . $thesaurusDesc ." then 1 else 0 end as descriptionmatch,
case when ".implode(' AND ', $searchTermMarkDesc)."". $thesaurusMarkDesc ." then 1 else 0 end as contentmatch
FROM Martin.dbo.item_search"
);
odbc_execute($result array($exactSearchTermDesc));
The variables are as below. $terms is the user input.
$searchTerms = explode(' ', $terms);
$exactSearchTermDesc = array();
$exactSearchTermMarkDesc = array();
$searchTermDesc = array();
$searchTermMarkDesc = array();
foreach ($searchTerms as $term) {
$term = trim($term);
if (!empty($term)) {
$exactSearchTermDesc[] = "description LIKE '$term %'";
$exactSearchTermMarkDesc[] = "contains(marketingDescription, '$term')";
$searchTermDesc[] = "description LIKE '%$term%'";
$searchTermMarkDesc[] = "marketingDescription LIKE '%$term%'";
$searchTermVendor[] = "vendor LIKE '%$term%'";
}
}
$exactThesaurusDesc = " Or " . implode(' AND ', $exactThesaurusDesc);
$exactThesaurusMarkDesc = " Or " . implode(' AND ', $exactThesaurusMarkDesc);
$thesaurusDesc = " Or " . implode(' AND ', $thesaurusDesc);
$thesaurusMarkDesc = " Or " . implode(' AND ', $thesaurusMarkDesc);
$thesaurusVendor = " Or " . implode(' AND ', $thesaurusVendor);
Consider re-factoring your SQL process. Rather than piecing together dynamic SQL components at application layer (i.e., PHP) that can impact readability and maintainability, consider multiple self-joins to a temp table of terms with below definition:
CREATE TABLE tmp_terms (
id IDENTITY(1,1) NOT NULL,
term VARCHAR(255),
thesauraus_indicator BIT
)
Specifically, run an aggregate query across joined matches where MIN returns 0 or 1. With this approach, the same SQL query is maintained but the underlying terms populated by PHP will be the dynamic component.
Below runs the non-thesaurus part of previous CASE logic. Also, since CONTAINS cannot use another column but only a literal value, JOIN expressions use LIKE with the leading and trailing wildcard.
SELECT
i.id, i.thumbnail, i.description, i.brand, i.vendor,
MIN(case
when exact_desc.term IS NOT NULL
then 1
else 0
end) AS exact_description_match,
MIN(case
when market_match.term IS NOT NULL
then 1
else 0
end) AS market_match,
MIN(case
when desc_match.term IS NOT NULL
then 1
else 0
end) AS desc_match,
MIN(case
when vendor_match.term IS NOT NULL
then 1
else 0
end) AS vendor_match
FROM Martin.dbo.item_search i
LEFT JOIN tmp_terms exact_desc
ON i.description LIKE CONCAT(exact_desc.term, ' %')
AND exact_desc.thesaurus_indicator = 0
LEFT JOIN tmp_terms market_match
ON i.marketingDescription LIKE CONCAT('%', market_match.term, '%')
AND market_match.thesaurus_indicator = 0
LEFT JOIN tmp_terms desc_match
ON i.description LIKE CONCAT('%', desc_match.term, '%')
AND desc_match.thesaurus_indicator = 0
LEFT JOIN tmp_terms vendor_match
ON i.vendor LIKE CONCAT('%', vendor_match.term, '%')
AND vendor_match.thesaurus_indicator = 0
GROUP BY i.id, i.thumbnail, i.description, i.brand, i.vendor
To integrate the thesaurus match, use UNION in CTE or subquery before aggregation in outer query.
WITH sub AS
(SELECT
i.id, i.thumbnail, i.description, i.brand, i.vendor,
exact_desc.term AS exact_desc_term, market_match.term AS market_match_term,
desc_match.term AS desc_match_term, vendor_match.term AS vendor_match_term
FROM Martin.dbo.item_search i
LEFT JOIN tmp_terms exact_desc
ON i.description LIKE CONCAT(exact_desc.term, ' %')
AND exact_desc.thesaurus_indicator = 0
LEFT JOIN tmp_terms market_match
ON i.marketingDescription LIKE CONCAT('%', market_match.term, '%')
AND market_match.thesaurus_indicator = 0
LEFT JOIN tmp_terms desc_match
ON i.description LIKE CONCAT('%', desc_match.term, '%')
AND desc_match.thesaurus_indicator = 0
LEFT JOIN tmp_terms vendor_match
ON i.vendor LIKE CONCAT('%', vendor_match.term, '%')
AND vendor_match.thesaurus_indicator = 0
UNION
SELECT
i.id, i.thumbnail, i.description, i.brand, i.vendor,
th_exact_desc.term, th_market_match.term,
th_desc_match.term, th_vendor_match.term
LEFT JOIN tmp_terms th_exact_desc
ON i.description LIKE CONCAT(th_exact_desc.term, ' %')
AND th_exact_match.thesaurus_indicator = 1
LEFT JOIN tmp_terms th_market_match
ON i.marketingDescription LIKE CONCAT('%', th_market_match.term, '%')
AND th_market_match.thesaurus_indicator = 1
LEFT JOIN tmp_terms th_desc_match
ON i.description LIKE CONCAT('%', th_desc_match.term, '%')
AND th_desc_match.thesaurus_indicator = 1
LEFT JOIN tmp_terms th_vendor_match
ON i.vendor LIKE CONCAT('%', th_vendor_match.term, '%')
AND th_vendor_match.thesaurus_indicator = 1
)
SELECT sub.id, sub.thumbnail, sub.description, sub.brand, sub.vendor,
MIN(case
when sub.exact_desc_term IS NOT NULL
then 1
else 0
end) AS exact_description_match,
MIN(case
when sub.market_match_term IS NOT NULL
then 1
else 0
end) AS market_match,
MIN(case
when sub.desc_match_term IS NOT NULL
then 1
else 0
end) AS desc_match,
MIN(case
when sub.vendor_match_term IS NOT NULL
then 1
else 0
end) AS vendor_match
FROM sub
GROUP BY sub.id, sub.thumbnail, sub.description, sub.brand, sub.vendor
Note: Above queries may need adjustment to final end use needs and testing. Performance may vary depending on number of search terms. But ultimately, the concept is to interact with data in sets and not long concatenated CASE WHEN... logic that grows with search terms.
Finally, in PHP simply clean out and populate the temp table with new values using parameterization and run any of the above final query:
odbc_exec($connection, "DELETE FROM tmp_terms");
$stmt = odbc_prepare($connection,
"INSERT INTO tmp_terms (term, thesaurus_indicator)
VALUES (?, ?)");
// NON-THESAURUS TERMS
foreach($search_terms as $t) {
odbc_execute($stmt, array($t, 0));
}
// THESAURUS TERMS
foreach($th_search_terms as $t) {
odbc_execute($stmt, array($t, 1));
}
// RUN FINAL SELECT QUERY
$result = odbc_exec($connection, "my_final_above_query");
while(odbc_fetch_row($result)){
for($i=1; $i<=odbc_num_fields($result); $i++){
// ... odbc_result($result,$i);
}
}

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();
}

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.

remove the last "UNION ALL" in building up a sql query with foreach loop

I want to build the following SQL query string using foreach loop
SELECT 'name' AS `field`. GROUP_CONCAT(DISTINCT `name` ORDER BY `name`) AS `value`
FROM product
UNION ALL
SELECT 'category' AS `field`. GROUP_CONCAT(DISTINCT `category` ORDER BY `category`) AS `value`
FROM product
UNION ALL
SELECT 'year' AS `field`. GROUP_CONCAT(DISTINCT `year` ORDER BY `year`) AS `value`
FROM product
The tricky part is that the following loop would result in an unnecessary "UNION ALL" in the last SELECT statement for year.
$selects = array("name"=>"Name","category"=>"Category","year"=>"Year");
$sql="";
foreach($selects as $select => $title)
{
$sql .= "SELECT '".$select."' AS `field` , GROUP_CONCAT( DISTINCT `".$select."`ORDER BY `".$select."` SEPARATOR '|' ) AS `value` FROM `product` UNION ALL";
}
Can anyone tell me how to remove the last UNION ALL from the last element (in this case,Year) in the array?
Use UNION ALL in a variable. Initialize it as a empty string.
Prepend it on each iteration. Then assign UNION ALL to the variable.
$selects = array("name"=>"Name","category"=>"Category","year"=>"Year");
$sql="";
$union_all="";
foreach($selects as $select => $title)
{
$sql .= $union_all . "SELECT '".$select."' AS `field` , GROUP_CONCAT( DISTINCT `".$select."`ORDER BY `".$select."` SEPARATOR '|' ) AS `value` FROM `product`";
$union_all=" UNION ALL ";
}
Give it a Try !!!
In your foreach, make an array of your queries without the UNION ALL. Then:
$sql = implode(' UNION ALL ', $queries);
The below code may solve your problem.
$selects = array("name"=>"Name","category"=>"Category","year"=>"Year");
$sql="";
foreach($selects as $select => $title)
{
$sql .= "SELECT '".$select."' AS `field` , GROUP_CONCAT( DISTINCT `".$select."`ORDER BY `".$select."` SEPARATOR '|' ) AS `value` FROM `product`". ($select!='Year')?" UNION ALL":"";
}

Categories