I am trying to create a stored procedure using PHP. My reading indicates the best way to do this by running the .sql file using the 'exec' command in PHP.
In testing i created a file named amtv3_create_routines.sql with this contents:
DELIMITER //
DROP PROCEDURE IF EXISTS createTc //
CREATE PROCEDURE createTc()
BEGIN
drop table if exists v3_tc;
CREATE TABLE v3_tc (
source BIGINT UNSIGNED NOT NULL ,
dest BIGINT UNSIGNED NOT NULL ,
PRIMARY KEY (source, dest) )
ENGINE = InnoDB;
insert into v3_tc (source, dest)
select distinct rel.sourceid, rel.destinationid
from rf2_ss_relationships rel inner join rf2_ss_concepts con
on rel.sourceid = con.id and con.active = 1
where rel.typeid = (select distinct conceptid from rf2_ss_descriptions where term = 'is a')
and rel.active = 1;
REPEAT
insert into v3_tc (source, dest)
select distinct b.source, a.dest
from v3_tc a
join v3_tc b on a.source = b.dest
left join v3_tc c on c.source = b.source and c.dest = a.dest
where c.source is null;
set #x = row_count();
select concat('Inserted ', #x);
UNTIL #x = 0 END REPEAT;
create index idx_v3_tc_source on v3_tc (source);
create index idx_v3_tc_dest on v3_tc (dest);
END //
DELIMITER;
This code works fine when I manually enter it into mysql 5.6.22
However if I save the file and from the prompt enter the command.
mysql -uroot -p -hlocalhost amtv3 < [full path]/amtv3_create_routines.sql
I have tried saving the file using utf8 encoding and windows 1252 encoding.
From the command prompt, there is no feedback, and the procedure is not created.
In PHP I am using the codeigniter framework. If I use the db->query method I can create the stored procedure, however the database loses connection. issuing $db->reconnect() works, but not reliably.
Any suggestions on how to create the stored procedure?
Omitting the space in the last line, DELIMITER; should result in a syntax error (there may be some other reason why this error is not being printed).
DELIMITER is only a feature of certain MySQL clients, and not a feature of the server. Therefore, when executing a .sql file directly, the server will interpret the first semi-colon as the end of the first statement and DELIMITER // will be seen as a syntax violation:
Error 1064: 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 //
CREATE PROCEDURE . . .
Discovered this here:
https://github.com/go-sql-driver/mysql/issues/351#issuecomment-120081608
The Solution?
Simply don't change the delimiter. The BEGIN and END already delimit a compound statement.
Source:
https://www.tutorialspoint.com/mysql/mysql_begin_end_compound.htm
You can try this
mysql -h localhost -U <username> -d <database_name> -f /home/user/<procedure_name>.sql
Related
I'm trying to write a PHP program to update a MySQL table entry according to a phone number. The phone numbers in the database are entered without limitations and are typically formatted in the XXX-XXX-XXXX way, but sometimes have other characters due to typos. In order to ensure the query works every time, I want to remove all non-numeric characters from the entries so that I can compare the entries to phone numbers formatted like XXXXXXXXXX coming from a separate source.
I've done some research and found some solutions but am unsure how to incorporate them into the PHP script. I am fairly new to MySQL and most of the solutions provided user defined MySQL functions and I don't know how to put them into the PHP script and use them with the query I already have.
Here's one of the solutions I found:
CREATE FUNCTION [dbo].[CleanPhoneNumber] (#Temp VARCHAR(1000))
RETURNS VARCHAR(1000) AS BEGIN
DECLARE #KeepValues AS VARCHAR(50)
SET #KeepValues = '%[^0-9]%'
WHILE PATINDEX(#KeepValues, #Temp) > 0
SET #Temp = STUFF(#Temp, PATINDEX(#KeepValues, #Temp), 1, '')
RETURN #Temp
END
And this is the query I need the solution for:
$sql = "SELECT pid AS pid FROM patient_data " .
"WHERE pid = '$pID' AND phone_cell = '$phone_number';";
The query should return the data in the pid column for a single patient, so if the phone number is 1234567890 and the pid is 15, 15 should be returned. I have no output at the moment.
The example function definition is Transact-SQL (i.e. for Microsoft SQL Server), it's not valid MySQL syntax.
A function like this doesn't go "into" the PHP code. The function gets created on the MySQL database as a separate step, similar to creating a table. The PHP code can call (reference) the defined function just like it references builtin functions such as DATE_FORMAT or SUBSTR.
The SELECT statement follows the pattern of SQL that is vulnerable to SQL Injection. Any potentially unsafe values that are incorporated into SQL text must be properly escaped. A better pattern is to use prepared statements with bind placeholders.
As an example of a MySQL function:
DELIMITER $$
CREATE FUNCTION clean_phone_number(as_phone_string VARCHAR(1024))
RETURNS VARCHAR(1024)
DETERMINISTIC
BEGIN
DECLARE c CHAR(1) DEFAULT NULL;
DECLARE i INT DEFAULT 0;
DECLARE n INT DEFAULT 0;
DECLARE ls_digits VARCHAR(20) DEFAULT '0,1,2,3,4,5,6,7,8,9';
DECLARE ls_retval VARCHAR(1024) DEFAULT '';
IF ( as_phone_string IS NULL OR as_phone_string = '' ) THEN
RETURN as_phone_string;
END IF;
SET n := CHAR_LENGTH(as_phone_string);
WHILE ( i < n ) DO
SET i := i + 1;
SET c := SUBSTR(as_phone_string,i,1);
IF ( FIND_IN_SET(c,ls_digits) ) THEN
SET ls_retval := CONCAT(ls_retval,c);
END IF;
END WHILE;
RETURN ls_retval;
END$$
DELIMITER ;
We can execute these statements in the mysql command line client, connected as a user with sufficient privilege, to create the function.
This isn't necessarily the best way to write the function, but it does serve as a demonstration.
Once the function is created, we can reference it a SQL statement, for example:
SELECT t.foo
, clean_phone_number(t.foo)
FROM ( SELECT '1' AS foo
UNION ALL SELECT '1-888-TAXICAB'
UNION ALL SELECT '888-555-1212'
UNION ALL SELECT '+=_-()*&^%$##"''<>?/;:"abc...xyz'
UNION ALL SELECT ''
UNION ALL SELECT NULL
) t
the situation is this:
I have 200 txt files with different names like 601776.txt each file's name is actually an ID_foo and it contains some data like this (2 columns):
04004 Albánchez
04006 Albox
04008 Alcóntar
04009 Alcudia de Monteagud
.
.
.
now I wanna BULK INSERT these TXT files into a SQL Server Table which has 3 column one of these columns should be the name of the txt file. I'm using a PHP script, so I made a loop to get the file names and then what?
BULK INSERT Employee_Table
FROM '../home/601776.txt'
WITH (
FIELDTERMINATOR ='\t',
ROWTERMINATOR = ''\n''
)
how can i set the third column while bulk inserting with $file_name variable in each loop?
Do you think it is a better idea if it is possible to insert the table by reading the txt file line by line? And how?
Thanks
This is one of the few times that a cursor is actually ideal in SQL Server. Here's a way. Once you see the PRINT statement and are satisfied you can comment it out and uncomment out the two lines below it. I put some logic in to add the file name and a processed date which is usually needed, but your table definition would need these columns. It should get the idea across.
---------------------------------------------------------------------------------------------------------------
--Set some variables
---------------------------------------------------------------------------------------------------------------
DECLARE #dt VARCHAR(10) --date variable but stored as VARCHAR for formatting of file name
DECLARE #fileLocation VARCHAR(128) = 'E:\DATA_TRANSFERS\' --production location which is \\issqlstd01 but the xp_dirtree didn't like this
DECLARE #sql NVARCHAR(4000) --dynamic sql variable
DECLARE #fileName VARCHAR(128) --full file name variable
---------------------------------------------------------------------------------------------------------------
--Get a list of all the file names in the directory
---------------------------------------------------------------------------------------------------------------
IF OBJECT_ID('tempdb..#FileNames') IS NOT NULL DROP TABLE #FileNames
CREATE TABLE #FileNames (
id int IDENTITY(1,1)
,subdirectory nvarchar(512)
,depth int
,isfile bit)
INSERT #FileNames (subdirectory,depth,isfile)
EXEC xp_dirtree #fileLocation, 1, 1
---------------------------------------------------------------------------------------------------------------
--Create a cursor to fetch the file names
---------------------------------------------------------------------------------------------------------------
DECLARE c CURSOR FOR
select subdirectory from #FileNames where isfile = 1
OPEN c
FETCH NEXT FROM c INTO #fileName
---------------------------------------------------------------------------------------------------------------
--For each file, bulk insert
---------------------------------------------------------------------------------------------------------------
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'BULK INSERT Employee_Table FROM '''+ #fileLocation + #fileName +''' WITH (FIELDTERMINATOR = ''\t'',KEEPNULLS,ROWTERMINATOR = ''0x0a'')'
--Try the bulk insert, if error is thrown log the error
--Also update the Table Columns which aren't a part of the original file (load date and original file name)
BEGIN TRY
PRINT(#sql)
--EXEC(#sql)
--UPDATE Employee_Table SET OrigFile = #fileName, LoadDate = GETDATE() WHERE OrigFile IS NULL
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE()
END CATCH
FETCH NEXT FROM c INTO #fileName
END
CLOSE c
DEALLOCATE c
GO
I'm using a sequence and trigger to essentially auto increment a column in a table, however I'm getting an error - ORA-24344: success with compilation error.
I was using this post: How to create id with AUTO_INCREMENT on Oracle? and it worked successfully for two other tables w/ auto increment I made, but there must be something in here I'm not familiar with causing an error.
More edits: Thanks to Polppan we've established that this likely isn't an Oracle issue, rather an OCI with PHP issue. I'm using:
oci_execute($sql);
And as mentioned here (again, thanks Polppan for that link), there's a bit of an issue between EOL characters and oci_execute. It was 11 years ago, so I don't know if that's been patched or not, and I did try his solution but it didn't help. Does anyone know if there are other issues with oci_execute and creating triggers?
Creating the table: (works)
CREATE TABLE RT_documents (
documentID INT NOT NULL,
reviewID varchar2(20) NOT NULL,
file_location CLOB NOT NULL,
version NUMBER(*,3) NOT NULL,
CONSTRAINT RT_documents_pk PRIMARY KEY (documentID)
)
Creating the sequence: (works)
CREATE SEQUENCE rt_documents_seq
Creating/replacing trigger: (doesn't work)
CREATE OR REPLACE TRIGGER rt_documents_bir
BEFORE INSERT ON RT_documents
FOR EACH ROW
BEGIN
SELECT RT_documents_seq.NEXTVAL
INTO :new.documentID
FROM dual;
END;
EDIT: Exact error message as requested - (Note, I'm executing these query-by-query using OCI/Oracle in PHP. PHP tag added just in case, but pretty sure this is an oracle syntax error or something).
Error:
Notice: oci_execute(): OCI_SUCCESS_WITH_INFO: ORA-24344: success with
compilation error in (...)
-I can successfully execute the first two queries, and double checked and the table is there so it worked properly.
Trigger doesn't understand new.id as id doesn't exist in RT_documents table.
Your trigger should be
CREATE OR REPLACE TRIGGER rt_documents_bir
BEFORE INSERT
ON RT_documents
FOR EACH ROW
BEGIN
SELECT RT_documents_seq.NEXTVAL INTO :new.documentID FROM DUAL;
END;
Update
SELECT * FROM v$version;
Oracle Database 10g Enterprise Edition
CREATE TABLE RT_documents
(
documentID INT NOT NULL,
reviewID VARCHAR2 (20) NOT NULL,
file_location CLOB NOT NULL,
version NUMBER (*, 3) NOT NULL,
CONSTRAINT RT_documents_pk PRIMARY KEY (documentID)
);
Table created.
CREATE SEQUENCE rt_documents_seq;
Sequence created.
CREATE OR REPLACE TRIGGER rt_documents_bir
BEFORE INSERT
ON RT_documents
FOR EACH ROW
BEGIN
SELECT RT_documents_seq.NEXTVAL INTO :new.documentID FROM DUAL;
END;
/
Trigger created.
INSERT INTO RT_documents (reviewID, file_location, version)
VALUES ('test', 'test', 1);
1 row created.
SELECT * FROM RT_documents;
DOCUMENTID REVIEWID FILE_LOCATION
VERSION
---------- -------------------- -------------------------------------------
-------------------------------- ----------
1 test test
1
Thanks to Polppan.
The solution was removing the EOL characters. (I did try this but had, without realising, removed the semi-colons, which caused the same error code)
This was a PHP error after all. Using oci_execute, you must remove EOL characters in triggers:
$sql = "CREATE OR REPLACE TRIGGER ......."; //shortened for easy reading
$sql = str_replace(chr(13),'',$sql);
$sql = str_replace(chr(10),'',$sql);
oci_execute($sql);
when I try to create a function to retrieve userName from user table using their email it gives me this useless error:
#1064 - 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 'DECLARE name VARCHAR; BEGIN select userName AS name from
user WHERE `ema' at line 2
, the same code with a different syntax works in mssql so I wonder what is the difference? in better words what am I doing wrong here?
DELIMITER ;;
CREATE FUNCTION getUserName(email varchar(50)) RETURNS VARCHAR
BEGIN
DECLARE name VARCHAR;
SELECT `userName` AS name FROM `user` WHERE `email` = email;
RETURN name;
END ;;
Well, first of all, varchar needs to have length, which you lack in two places. Also, you need to select into the variable and return the variable, because you cannot return resultset. Also you should escape name, and you do not need to alias your column because you are selecting into anyway. So, your code should be like this:
DELIMITER ;;
CREATE FUNCTION getUserName(email VARCHAR(50)) RETURNS VARCHAR(50)
BEGIN
DECLARE NAME VARCHAR(50);
SELECT `userName` FROM `user` WHERE `email` = email
INTO `name`;
RETURN `name`;
END ;;
Have a script that I can copy and run in mysql shell just fine, but explodes when attempting the same script in php5 mysql_query. Part of the script:
-- sync shadow with users
drop trigger users_post_insert;
delimiter $$
create trigger users_post_insert after insert on users
for each row
begin
insert into shadow( usr_id ) values( new.usr_id );
end$$
delimiter ;
Raises error:
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 $$\ncreate trigger users_post_insert after insert
on users\n\tfor each ro' at line 8
Again, have done similar executing script files with PostgresQL and Oracle scripts, so this took me off guard.
Do MySQL scripts need to be passed through a regex before being run, or what?
These are scripts that have been debugged and then applied via php to new schemas.
Might you need to define delimiter first before executing a command, and make sure you dropped an already created trigger (or just use if exists clause) try this
-- sync shadow with users
delimiter $$
drop trigger if exists users_post_insert;$$
create trigger users_post_insert after insert on users
for each row
begin
insert into shadow( usr_id ) values( new.usr_id );
end;$$
delimiter ;
Testing shows mysql_execute cannot accept the DELIMITER command.
To make it work break up your file into chunks, leaving out the DELIMITER lines altogether. For example,
$procs = file_get_contents( '../sql/security.sql' );
$procArr = preg_split( "/delimiter .*\n/", $procs );
Also, remove the set delimiter "$$" from the remaining chunks.
Feed each non-empty chunk into mysql_execute - it's ugly, but it works.