I'm trying to alt WP tables with the function. Mysql code works fine if I call it from mysql client (adds columns), but when I called it via $wpdb->query() it gave me error pointing to DELIMITER line. Upon some googling, I found out that I should use mysqli for this purpose. Now the error log is empty but columns are still not created. Anyone got an idea of what I'm doing wrong? Function code is below
global $wpdb;
$tables=array(
'wp_users',
'wp_usermeta',
'wp_term_taxonomy',
'wp_term_relationships',
'wp_terms',
'wp_taxonomymeta',
'wp_posts',
'wp_postmeta',
'wp_p2p',
'wp_p2pmeta',
'wp_options',
'wp_fb_user_timezone',
'wp_fb_coaching_call_report_team_user',
'wp_fb_coaching_call_report_team',
'wp_fb_3d_notes',
'wp_comments',
'wp_commentmeta',
'wp_coaching_teams_student',
'wp_coaching_teams_coach',
'wp_coaching_teams',
'wp_coaching_call_count'
);
if (is_array($tables)&&count($tables)>0)
{
foreach ($tables as $table)
{
$aaa=mysqli_multi_query($wpdb->dbh,'DELIMITER $$
DROP PROCEDURE IF EXISTS add_createdat_and_updatedat_fields $$
CREATE PROCEDURE add_createdat_and_updatedat_fields()
BEGIN
IF EXISTS(SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=DATABASE() AND table_name=\''.$table.'\') THEN
IF NOT EXISTS ((SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name=\''.$table.'\' AND column_name=\'created_at\')) THEN
ALTER TABLE `'.$table.'` ADD `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;
END IF;
IF NOT EXISTS ((SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name=\''.$table.'\' AND column_name=\'updated_at\')) THEN
ALTER TABLE `'.$table.'` ADD `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;
END IF;
END IF;
END $$
CALL add_createdat_and_updatedat_fields() $$
DROP PROCEDURE IF EXISTS add_createdat_and_updatedat_fields $$
DELIMITER;');
}
}
Do not use multiquery, run each command separately with mysqli_query() instead, that way you don't need manipulating separators at all.
Related
I have a products table stored inside the database which contains info related to the product.I have a stored procedure that gets the rows with maximum quantity.
Whenever i try to call that stored procedure from the php it returns false while when i run the same query in mysql console, it returns me the rows.
PHP Code:
$resVal=$mysqli->query('CALL get_max_quant_rows("'.$company.'","'.$type.'","'.$limit.'")');
$countVal=$resVal->fetch_row();
$countVal=$countVal[0];
$results = $mysqli->query('CALL get_max_quant_rows("'.$company.'","'.$type.'","'.$limit.'")');
var_dump('CALL get_max_quant_rows("'.$company.'","'.$type.'","'.$limit.'")');
var_dump($results);
The ouput of the var_dump of the above queries give me:
string(72) "CALL get_max_quant_rows("1471941595186287666657bc0bdb1c25d","Cakes","1")" bool(false)
I have shown you the var_dump of the query as to show you that the values are going perfectly inside the stored procedure.
When i ran the same query inside the console,it ran and it gave me the results.What could pe the possible reason for this behaviour?
Stored Procedure:
DELIMITER $$
USE `dboxyz`$$
DROP PROCEDURE IF EXISTS `get_max_quant_rows`$$
CREATE PROCEDURE `get_max_quant_rows`(company VARCHAR(8000),product_type VARCHAR(8000),limiter INT)
BEGIN
DECLARE emptyCheckFirst BIT;
DECLARE emptyCheckSecond BIT;
SET emptyCheckFirst=`dboxyz`.isNullOrEmpty(company);
SET emptyCheckSecond=`dboxyz`.isNullOrEmpty(product_type);
IF (emptyCheckFirst=0 AND emptyCheckSecond=0)
THEN
SELECT p1.id,p1.price,p1.product_code,p1.product_name,p1.quantity,p1.amount,p1.companyId FROM products p1
INNER JOIN (SELECT product_code,MAX(quantity) max_quantity FROM products WHERE companyId=company AND `type`=product_type
GROUP BY product_code) p2 ON p1.product_code=p2.product_code AND p1.quantity=p2.max_quantity LIMIT limiter;
END IF;
IF emptyCheckFirst=1 AND emptyCheckSecond=1
THEN
SELECT p1.id,p1.price,p1.product_code,p1.product_name,p1.quantity,p1.amount,p1.companyId FROM products p1
INNER JOIN (SELECT product_code,MAX(quantity) max_quantity FROM products
GROUP BY product_code) p2 ON p1.product_code=p2.product_code AND p1.quantity=p2.max_quantity LIMIT limiter;
END IF;
END$$
DELIMITER ;
Update:
Error given by the DB
Commands out of sync; you can't run this command now
DELIMITER $$
USE `dboxyz`$$
DROP FUNCTION IF EXISTS `isNullOrEmpty`$$
CREATE FUNCTION `isNullOrEmpty`(xx VARCHAR(8000)) RETURNS BIT(1)
BEGIN
DECLARE somevariable VARCHAR(8000);
SET somevariable=xx;
IF (somevariable IS NOT NULL AND LEN(somevariable)>0)
THEN
RETURN 0;
ELSE
RETURN 1;
END IF;
END$$
DELIMITER ;
MySQL stored procedures can return more than one result set, that is the reason to clear all results before do another query using the same connection.
Just use next_result, and do another query:
$results = $mysqli->query("CALL stored_procedure()");
$mysqli->next_result();
$results2 = $mysqli->query("CALL another_stored_procedure()");
How do I use php and mysql to create the following trigger for each table created.
I want to convert the following code to be used as a sql query from php.
DELIMITER $$
CREATE TRIGGER trigger1
BEFORE INSERT
ON table1
FOR EACH ROW
BEGIN
SELECT COUNT(*) INTO #cnt FROM table1;
IF #cnt >= 25 THEN
CALL sth();
END IF;
END
$$
DELIMITER ;
I tried to use the following but it does not work.
if ($method == "T")// method is activated if $_GET["method'] = T method is set to T in script to allways return true
{
$sql = "CREATE TRIGGER TRIGGER1
BEFORE INSERT
ON 49a64d6512
FOR EACH ROW
BEGIN
SELECT COUNT(*) INTO #cnt FROM 49a64d6512;
IF #cnt >=25 THEN
CALL sth();
END IF;
END";
echo '1';
}
Is what i am trying to do even possible?
$link->query("DROP TABLE IF EXISTS table2");
$link->query("CREATE TABLE table2 (newcol BIGINT UNSIGNED PRIMARY KEY)");
$result=$link->query("select col1 from table1");
while($data=$result->fetch_array(MYSQL_ASSOC))
{
$link->query("insert into table2 (newcol) values($data['col1']);
$link->query(""ALTER TABLE table2 ADD `".$data['col1']."` BIGINT DEFAULT 0"");
}
What Iam trying to do is
Create a table "table2" with one column "newcol".
select all the values of "col1" from "table1" And
for each value of col1 from table1
-insert the value into "newcol" of table2 And
-add a column named (value from col1 of table 1) into "table2"
The above code looks very neat and efficient in php , but the problem is it takes some amount of time .So I think its better to convert these into MySQL Stored procedure .Since I'm new to stored procedures , very much confused .Please help me guys.
Of course, I couldn't test it, but it is compiling fine on on my computer.
DELIMITER //
CREATE PROCEDURE `myProcedure` ()
BEGIN
DECLARE _done BOOLEAN DEFAULT FALSE;
DECLARE _myField BIGINT UNSIGNED DEFAULT 0;
/* the cursor here is like your PDOStatement
* it is used to fetch data */
DEClARE _myReader CURSOR FOR
SELECT `col1` FROM `table1`;
/* it is not very elegant, but we need to throw an exception
* to break the loop */
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET _done = TRUE;
DROP TABLE IF EXISTS `table2`;
CREATE TABLE `table2` (
`newcol` BIGINT UNSIGNED PRIMARY KEY
);
/* you open your PDOStatement */
OPEN _myReader;
/* myLoop is like a GOTO*/
myLoop: LOOP
/* $result->fetch_array(MYSQL_ASSOC)*/
FETCH _myReader INTO _myField;
/* if the no data exception had been thrown,
* goto the end of the loop */
IF _done = 1 THEN
LEAVE myLoop;
END IF;
INSERT INTO `table2` (newcol) VALUES (_myField);
ALTER TABLE `table2` ADD `_myField` BIGINT DEFAULT 0;
END LOOP myLoop;
/* close your PDO object */
CLOSE _myReader;
END //
Jonathan Parent Lévesque helped me a lot in figuring out how the looping inside stored procedures work and to get the overall structure for the stored procedure equivalent to the php code described in the question above.
Thanks Jonathan Parent Lévesque
But in his code Adding column name using a variable didn't work as expected.
Finally I figured it out
BEGIN
DECLARE _done BOOLEAN DEFAULT FALSE;
DECLARE _myField BIGINT DEFAULT 0;
DEClARE _myReader CURSOR FOR
SELECT id FROM `tags`;
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET _done = TRUE;
DROP TABLE IF EXISTS `tag_similarity`;
CREATE TABLE `tag_similarity` (
`tag` BIGINT UNSIGNED PRIMARY KEY
);
OPEN _myReader;
myLoop: LOOP
FETCH _myReader INTO _myField;
IF _done = 1 THEN
LEAVE myLoop;
END IF;
INSERT INTO `tag_similarity` (tag) VALUES (_myField);
SET #sql = CONCAT('ALTER TABLE tag_similarity ADD `',_myfield,'` BIGINT DEFAULT 0');
PREPARE stmt FROM #sql;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt;
END LOOP myLoop;
CLOSE _myReader;
END
I try to check if all the column exist in a MySql ddb. I use this answer MySQL add column if not exist but i have a 1064 error. Anyboby can helps me ?
Thanks
foreach($source_bdd as $each_column)
{
$source_column = explode('***',$each_column);
$nullable = $source_column[4] == 'YES' ? 'DEFAULT NULL' : 'NOT NULL';
$verify_and_update_column .= '
DELIMITER $$
DROP PROCEDURE IF EXISTS Alter_Table_'.$source_column[0].''.$source_column[1].' $$
CREATE PROCEDURE Alter_Table_'.$source_column[0].''.$source_column[1].'()
BEGIN
DECLARE '.$source_column[0].''.$source_column[1].'_count INT;
SET '.$source_column[0].''.$source_column[1].'_count = ( SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = "'.$source_column[0].'" AND
COLUMN_NAME = "'.$source_column[1].'");
IF '.$source_column[0].''.$source_column[1].'_count = 0 THEN
ALTER TABLE '.$source_column[0].'
ADD COLUMN '.$source_column[1].' '.$source_column[9].' '.$nullable.';
END IF;
END $$
CALL Alter_Table_'.$source_column[0].''.$source_column[1].'() $$
DELIMITER ;
';
}
Here is an extract of the query and the error at the end :
DELIMITER $$
DROP PROCEDURE IF EXISTS Alter_Table_table_1_column_1 $$
CREATE PROCEDURE Alter_Table_table_1_column_1()
BEGIN
DECLARE table_1_column_1_count INT;
SET table_1_column_1_count = ( SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = "table_1" AND
COLUMN_NAME = "table_1");
IF table_1_column_1_count = 0 THEN
ALTER TABLE table_1
ADD COLUMN table_1 varchar(512) DEFAULT NULL;
END IF;
END $$
CALL Alter_Table_table_1_column_1() $$
DELIMITER ;
DELIMITER $$
DROP PROCEDURE IF EXISTS Alter_Table_table_1_column_2 $$
CREATE PROCEDURE Alter_Table_table_1_column_2()
BEGIN
DECLARE table_1_column_2_count INT;
SET table_1_column_2_count = ( SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = "table_1" AND
COLUMN_NAME = "table_1");
IF table_1_column_2_count = 0 THEN
ALTER TABLE table_1
ADD COLUMN table_1 varchar(512) DEFAULT NULL;
END IF;
END $$
CALL Alter_Table_table_1_column_2() $$
DELIMITER ;
….
DELIMITER $$
DROP PROCEDURE IF EXISTS Alter_Table_table_25_column_12 $$
CREATE PROCEDURE Alter_Table_table_25_column_12()
BEGIN
DECLARE table_25_column_12_count INT;
SET table_25_column_12_count = ( SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = "table_1" AND
COLUMN_NAME = "table_1");
IF table_25_column_12_count = 0 THEN
ALTER TABLE table_1
ADD COLUMN table_1 varchar(512) DEFAULT NULL;
END IF;
END $$
CALL Alter_Table_table_25_column_12() $$
DELIMITER ;
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 'DELIMITER $$
DROP PROCEDURE IF EXISTS Alter_Table_table_1_column_1 $$
CREATE PROC' at line 11064
I have a PHP script where users create questionnaires, and the script tables in the DB to store the incoming data. The site's been live for a while, and there are about 100 tables in the database.
My script was awfully flawed! It calls for "tinytext" fields in places where I really need "text". Is there a way to bulk update all of the tinytext columns to text?
Thanks!
Solution without stored procedures (using only phpMyAdmin or any other DBA tool).
Run the following query
SELECT
CONCAT('ALTER TABLE ',
TABLE_NAME,
' CHANGE COLUMN ',
COLUMN_NAME,
' ',
column_name,
' TARGET_TYPE ',
CASE
WHEN IS_NULLABLE = 'NO' THEN ' NOT '
ELSE ''
END,
' NULL;') AS que
FROM
information_schema.columns
WHERE
table_schema = 'MY DB'
AND data_type = 'SOURCE_TYPE';
This query will return you all the statements to fire. You can run them or save into a SQL Upgrade script
Example (from tinyint to bit):
ALTER TABLE mytable CHANGE COLUMN redacted redacted BIT NULL;
ALTER TABLE mytable CHANGE COLUMN redacted2 redacted2 BIT NOT NULL;
One way of doing this, is to find all the tinytext columns in the given database and then create ALTER TABLE statement for the each column. Working solution using stored procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS `BULK_RETYPE` $$
CREATE PROCEDURE `BULK_RETYPE`(IN SCHEMA_NAME VARCHAR(255), IN FROM_TYPE VARCHAR(255), IN TO_TYPE VARCHAR(255))
BEGIN
DECLARE `done` INT DEFAULT FALSE;
DECLARE tn VARCHAR(255);
DECLARE fn VARCHAR(255);
DECLARE `cur1` CURSOR FOR
SELECT
`TABLE_NAME`,
`COLUMN_NAME`
FROM
`information_schema`.`COLUMNS`
WHERE
`DATA_TYPE` = FROM_TYPE AND `TABLE_SCHEMA` = SCHEMA_NAME;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO `tn`, `fn`;
IF done THEN
LEAVE read_loop;
END IF;
SET #ALTER_SQL = CONCAT('ALTER TABLE ', '`', tn,'`' , ' MODIFY ', '`', fn,'`' , ' ', TO_TYPE);
PREPARE stmt1 FROM #ALTER_SQL;
EXECUTE stmt1;
END LOOP;
CLOSE cur1;
END $$
DELIMITER ;
CALL BULK_RETYPE('test', 'tinytext', 'text');
Not really, though if you use PHPMyAdmin, it's a rather quick task... alternatively, you could export a list of all the tables and fields you need to change and put together the necessary ALTER TABLE statements and then execute them.
You can just select from schema and prepare SQL for mass alter
SELECT table_scheme, table_name, columun_name FROM information_schema.`COLUMNS`
WHERE DATA_TYPE='tinyint'