run prepared statement in fat-free framework - mysql

I need to run a following prepared statement query in fat-free framework.
I am trying to run the query as normal query.
public function weeklyLunchReport($date1=null, $date2=null)
{
$user = AclHelper::getCurrentUser();
$default_userID = intval($user['user_id']);
$defDate = new DateTime();
$default_date = $defDate->format('Y-m-d');
$date1 = (isset($date1) && $date1 != '') ? $date1 : $default_date;
$date2 = (isset($date2) && $date2 != '') ? $date2 : $default_date;
$sql =
"
SET #SQL = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'SUM(CASE WHEN date = "',dt,'" THEN lunchStatus ELSE 0 END) AS "',dt,'"',
)
) INTO #SQL
FROM
(
SELECT DATE(issuedDateTime) as dt
FROM `lunch_status`
WHERE DATE(issuedDateTime) BETWEEN '$date1' AND '$date2'
) d;
SET #SQL
= CONCAT('SELECT userId, ', #SQL, '
FROM
(
SELECT userId, lunchStatus, DATE(issuedDateTime) as date
FROM `lunch_status`
WHERE DATE(issuedDateTime) BETWEEN '$date1' AND '$date2'
) as a
GROUP BY userId;');
PREPARE stmt FROM #SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
";
return $this->db->exec($sql);
}
But I know this isn't the right way.
Do I run it as stored procedure?

Put code in stored procedure and call it from F3, something like this:
$rows = $f3->get('DB')->exec("call my_stored_procedure($var1,$var2,...)");

This question doesn't relate directly to FFF, as it is a general question about what to do with complex SQL queries like yours.
I have had the same question myself (as I also have some weekly reports to run), and finally I have decided to keep the SQL query in the code, as you are doing. I didn't want to have it as a stored procedure, because I didn't want to rely on DB set up (it is not versioned). So as much as I hate it, I have some vanilla SQL code in my app too.
The question here maybe rather on how to test this kind of method. My advice is to put report related queries in a service initialized by a factory (factory is needed to return a service depending on the source of your data - for now it is SQL, but it can later change).

Related

MySQL - create a table with all of the fields that two tables have [duplicate]

I have to convert a MSSQL stored proc that passes a varchar that is a query:
INSERT INTO Results
EXEC (#Expresion);
This isn't working. I'm pretty sure that EXEC and EXECUTE aren't MySQL commands, but CALL doesn't work either.
Does anyone know if it's even possible to have something like JavaScript's eval function for MySQL?
I think you're looking for something like this:
SET #queryString = (
SELECT CONCAT('INSERT INTO user_group (`group_id`,`user_id`) VALUES ', www.vals) as res FROM (
SELECT GROUP_CONCAT(qwe.asd SEPARATOR ',') as vals FROM (
SELECT CONCAT('(59,', user_id, ')') as asd FROM access WHERE residency = 9
) as qwe
) as www
);
PREPARE stmt FROM #queryString;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #asd = NULL;
This is the SQL equivalent of eval(my_string);:
#Expression = 'SELECT "Hello, World!";';
PREPARE myquery FROM #Expression;
EXECUTE myquery;
Basically I combined the existing answers, neither tells you how to do eval exactly.
If you want to add parameters, you can use this:
#username = "test";
#password = "asdf";
#Expression = 'SELECT id FROM Users WHERE name = ? AND pass = ?;'
PREPARE myquery FROM #Expression;
EXECUTE myquery USING #username, #password;
And to answer the original question exactly:
#Expression = 'SELECT "Hello, World!";'
PREPARE myquery FROM #Expression;
INSERT INTO Results
EXECUTE myquery;
Note that the PREPARE ... FROM statement wants a session variable (prefixed with #). If you try to pass a normal variable, it will throw its hands up in the air and it just won't care.
EXECUTE is a valid command in MySQL. MySQL reference manual
The EXECUTE MySQL command can only be used for one prepared statement.
If case you want to execute multiple queries from the string, consider saving them into file and source it, e.g.
SET #query = 'SELECT 1; SELECT 2; SELECT 3;';
SELECT #query INTO OUTFILE '/tmp/temp.sql';
SOURCE /tmp/temp.sql;

Debugging a MySQL procedure in phpMyAdmin

I have a really basic question that I've been unable to find the answer to so far. I've read several answers but they don't seem to be working for me.
I'm not looking for someone to debug this (unless you are feeling super helpful!) I just would like some help to debug it myself.
I have the following procedure that I'm in the process of writing. I've obviously made a mistake but can someone show me the best way to debug this. When I call this procedure in phpMyAdmin I can't see what the value of #sql is.
I tried entering SELECT #sql; but that didn't seem to work as nothing was displayed when I called the procedure.
How can I find out what the value of #sql is so that I can properly debug this.
Thanks in advance.
BEGIN
set #sql = (select concat('SELECT a.id as "Asset ID", ',
group_concat(
concat('max(case when ap.property_id = ',ap_id, ' then ap.', ap_data_type, '_value else null end) as "', ap_name,'",')
)
,' FROM chekrite_prod.equipment AS a JOIN chekrite_prod.asset_properties ap on ap.asset_id = a.id group by a.site_id, a.asset_id;'
)
from
(
SELECT i.id as ap_id, item as ap_name, asset_property_data_type as ap_data_type
FROM chekrite_prod.config_items as i
JOIN chekrite_prod.config_tables as t on t.id = i.table_id
WHERE t.company_id = 161 AND t.class = 'asset_property' ) a
)
;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END

MySQL Prepared Statements Appeding Where Condition Not Working

Here is the actual query
select taken_date, DATE_FORMAT(taken_date, '%Y') taken_date_year, count(id) num_of_orders, sum(total_order_days) total_work_days from
(
select id, taken_date, getNumOfWorkDaysForOrder(order.order_num) total_order_days from order
where order.is_active = 1 and order.deleted_at is null and order.vendor_id = vendor_input and
order.company_id = company_input and order.contact_id = contact_input and order.candidate_id = candidate_input
order by taken_date
) as order_years group by YEAR(taken_date) order by taken_date desc;
I want to add where condition based on the input if it is not null, tried prepared statements and concatenation to add the where condition to the query but no luck.
DELIMITER $$
CREATE PROCEDURE
getAllActiveOrdersGroupByTakenDate(vendor_input INT, company_input INT, contact_input INT, candidate_input INT)
BEGIN
SET #prepareQuery = "select id, taken_date, getNumOfWorkDaysForOrder(order.order_num) total_order_days from order
where order.vendor_id = "+ vendor_input +" and order.is_active = 1 and order.deleted_at is null";
IF company_input IS NOT NULL THEN
SET #prepareQuery = CONCAT(#prepareQuery, ' ', "and order.company_id = "+company_input);
END IF;
IF contact_input IS NOT NULL THEN
SET #prepareQuery = CONCAT(#prepareQuery, ' ', "and order.contact_id = "+contact_input);
END IF;
IF candidate_input IS NOT NULL THEN
SET #prepareQuery = CONCAT(#prepareQuery, ' ', "and order.candidate_id = "+candidate_input);
END IF;
SET #finalQueryPart1 = CONCAT("select taken_date, DATE_FORMAT(taken_date, '%Y') taken_date_year, count(id) num_of_orders, sum(total_order_days) total_work_days from
(", #prepareQuery);
SET #finalQuery = CONCAT(#finalQueryPart1, ") as order_years group by YEAR(taken_date) order by taken_date desc");
PREPARE stmt FROM #finalQuery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$
DELIMITER ;
Can someone help me to achieve this?
Update: you had an issue with your CONCAT() syntax before you edited your question.
When you want to append content, you must assign it back to the original string. CONCAT() is a function that returns the concatenated string. It does not have any side-effect of modifying the variable you use as an argument.
WRONG:
CONCAT(#prepareQuery, ' ', "and order.company_id=company_input");
RIGHT:
SET #prepareQuery = CONCAT(#prepareQuery, ' ', "and order.company_id=company_input");
Also, I'm not sure if you can reference the procedure input parameters in these expressions.
Frankly, I hardly ever use stored procedures. MySQL's implementation of stored procedures sucks. It's inefficient, doesn't save compiled procedures, there's no debugger, there are no packages, and so on.
Mostly I just execute dynamic SQL from my applications. There you have debugging, code reuse, familiar string manipulation in a familiar language.
I understand that stored procedures are the tradition in Oracle and Microsoft SQL Server communities, but it's really better to avoid stored procedures in MySQL.

Where clause not working in stored procedure, when working outside of it

We built a piece of dynamic sql that generates a wide view from data in long format. Seen here:
CREATE PROCEDURE `selectPivotedTermpoints`(studyid varchar(300))
BEGIN
SET SESSION group_concat_max_len = 10000000;
SET #psql = NULL;
SET #finalSQL = NULL;
SET #StudyID = studyid;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT('SUM(CASE WHEN terminate = ''', REPLACE(Terminate,'''', ''''''), ''' THEN 1 ELSE 0 END) AS `', REPLACE(Terminate,'''', ''), '`')
) INTO #psql
FROM Dashboard
WHERE studyid = #StudyID
AND completion_status = 'terminate';
SET #finalSQL = CONCAT('
SELECT Sample_provider as Provider,
completion_status as `Status`,',
#psql,'
FROM Dashboard
WHERE studyid = ''', #StudyID, '''
AND completion_status = ''terminate''
GROUP BY Sample_provider');
SELECT #finalSQL;
PREPARE stmt FROM #finalSQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
When the sql is run as a query,(from SET to DEALLOCATE)setting #StudyID manually, we return a table with only the columns for that specific study(distinct Terminate as columns for only that study), however when the query is turned into a stored procedure and run it is generating a table with columns for all studies(all distinct Terminate as columns).
It appears that the first where clause (in the select group_concat) is being ignored when run as a stored procedure, but this is not the case when run as a simple query.
Stored procedure call:
selectPivotedTermpoints('bhp_03a');
Does anyone know why this is the case and / or how I can correct the issue?
I helped someone with a similar issue recently in another question; it confused us for quite a while. Change the parameter name to something else, I am guessing that WHERE is using it instead of the field in the table.
(You might be able to get away with Dashboard.studyid as well, but changing the parameter name will cause less confusion; and I am not positive how the query in #finalSQL would behave either.)

Mysql:Trim all fields in database

UPDATE mytable SET mycolumn= LTRIM(RTRIM(mycolumn));
works fine on trimming columns removing trailer spaces, but how can i adjust it to trim all columns without having to write each column name in table ?? cause i kind have a huge database.
Some years late, but might help others:
This code trims all fields of a the table your_table.
Could be expanded to work on the whole database in the same way....
SET SESSION group_concat_max_len = 1000000;
SELECT concat('update your_table set ',
group_concat(concat('`',COLUMN_NAME, '` = trim(`',COLUMN_NAME,'`)')),';')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'your_table'
INTO #trimcmd;
PREPARE s1 from #trimcmd;
EXECUTE s1;
DEALLOCATE PREPARE s1;
you expand the query for each column:
UPDATE mytable
SET mycolumn = LTRIM(RTRIM(mycolumn)),
mycolumn2 = LTRIM(RTRIM(mycolumn2)),
...;
Since the question asks for the whole database, here is the script that generates the required SQL. I skip the auto execute, execute it as you like.
-- Set your database name here
SET #my_database:='YOUR_DB_NAME';
SET SESSION group_concat_max_len = 1000000;
SELECT
CONCAT('UPDATE `', #my_database, '`.`', TABLE_NAME,
'` SET ', GROUP_CONCAT(
CONCAT('`', COLUMN_NAME, '` = TRIM(`', COLUMN_NAME, '`)')
ORDER BY ORDINAL_POSITION ASC),
';') AS `query`
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_SCHEMA = #my_database
GROUP BY TABLE_NAME
ORDER BY TABLE_NAME ASC;
#ZweiStein Thanks.
UPDATE mytable SET
mycolumn = LTRIM(RTRIM(mycolumn)),
mycolumn2 = LTRIM(RTRIM(mycolumn2))
and so on, and so forth.
If there are not too many columns, you could just
directly
UPDATE each by your_column_name, via the TRIM() function:
UPDATE mytable SET
mycolumn1 = TRIM(mycolumn1),
mycolumn2 = TRIM(mycolumn2),
mycolumn3 = TRIM(mycolumn3),
mycolumn4 = TRIM(mycolumn4)
Otherwise, ZweiStein's answer above for a single table,
or Izhar Aazmi's answer for an entire database seem the way to go.
Hiram's answer to another SO Post includes a check to only TRIM VARCHAR fields: excellent feature!
Or, if using T-SQL, or others which do not support TRIM, use the LTRIM(RTRIM(...)) trick,
suggested by Jim Rubenstein and Denis de Bernardy above.
I was actually looking for something similar for a legacy table that's constantly updated by an outside source when I came across this question. I realize the OP was looking for a purely SQL(MySQL) answer, but in case you use Rails, you might find this tidbit that I came up with helpful:
MyModel.update_all(MyModel.columns.map(&:name).map{|x| "#{x} = TRIM(#{x})"}.join(', '))
You can also wrap it into a class method in your model
class MyModel < ActiveRecord::Base
def self.trim_all
update_all(columns.map(&:name).map{|x| "#{x} = TRIM(#{x})"}.join(', '))
end
end
Then call it like this
MyModel.trim_all
You can use PHP for it ( in order to avoid sql errors, better print queries then execute them later ) :
$dbHost = 'localhost';
$dbUsername = 'root';
$dbPassword = '';
$dbName = 'database';
$db = new mysqli($dbHost, $dbUsername, $dbPassword, $dbName);
$db->set_charset("utf8");
$queries = '';
$query="SELECT * from table";
$result = $db->query($query);
$headers = $result->fetch_fields();
foreach($headers as $header) {
$col = $header->name;
$queries .= "UPDATE table SET `".$col."` = TRIM(`".$col."`) </br>";
}
echo $queries;
?>