MySQL function if elseif 1064 - mysql

I'm trying to use MySQL but since 2 days I'm stuck on it.
I've got an 1064 error which mean syntax error. I tried a lot of things but none worked.
DELIMITER $$
CREATE FUNCTION set_libelle(civilite VARCHAR(4), prenom VARCHAR(30), nom VARCHAR(30))
RETURNS VARCHAR(20)
BEGIN
IF (LEN(civilite)+LEN(prenom)+LEN(nom)<19) THEN
RETURN civilite + ' ' + prenom + ' ' + nom;
ELSEIF (LEN(civilite)+LEN(nom)<17) THEN
RETURN civilite + ' ' + LEFT(prenom,1) + '. ' + nom;
ELSE
RETURN civilite + ' ' + LEFT(prenom,1) + '. ' + LEFT(nom, (17-(LEN(civilite)));
END IF;
END$$
DELIMITER ;
Have you got an idea why this doesn't work ?
Thank you

You are using + for string concatenation rather than concat().
The proper syntax is:
DELIMITER //
CREATE FUNCTION set_libelle(civilite VARCHAR(4), prenom VARCHAR(30), nom VARCHAR(30))
RETURNS VARCHAR(20)
BEGIN
IF (LEN(civilite) + LEN(prenom) + LEN(nom) < 19) THEN
RETURN CONCAT_WS(' ', civilite, prenom, ',', nom);
ELSEIF (LEN(civilite) + LEN(nom) < 17) THEN
RETURN CONCAT_WS(' ', civilite, LEFT(prenom, 1), '.', nom);
ELSE
RETURN CONCAT_WS(' ', civilite, LEFT(prenom, 1), '.', LEFT(nom, 17 - LEN(civilite)) );
END IF;
END; //
DELIMITER ;
Here is a SQL Fiddle.

Related

special Characters in DB query is failing

I had created a db named as Suri's _DB and had below query is failing when executed. If the db name is given without single quote the query is executing successfully.
The query is
USE [master];
IF EXISTS (SELECT 1 FROM tempdb..sysobjects WHERE [Id] = OBJECT_ID('tempdb..#tmp_filegroups'))
BEGIN
DROP TABLE #tmp_filegroups
END
CREATE TABLE #tmp_filegroups
(
[DbName] nvarchar(128),
[DbId] int,
[GroupName] nvarchar(128),
[GroupId] int,
[IsFileStream] bit
)
IF EXISTS (SELECT 1 FROM tempdb..sysobjects WHERE [Id] = OBJECT_ID('tempdb..#tmp_dbandlogfiles'))
BEGIN
DROP TABLE #tmp_dbandlogfiles
END
CREATE TABLE #tmp_dbandlogfiles
(
[DbName] nvarchar(128),
[DbId] int,
[GroupId] int,
[Name] nvarchar(128),
[FileName] nvarchar(260),
[Size] float,
[IsReadOnlyMedia] bit,
[IsReadOnly] bit,
[IsOffline] bit,
[IsSparse] bit,
[IsPrimaryFile] bit,
[SpaceUsed] float,
[FileType] int
)
IF EXISTS (SELECT 1 FROM tempdb..sysobjects WHERE [Id] = OBJECT_ID('tempdb..#tmp_fulltextcatalogfiles'))
BEGIN
DROP TABLE #tmp_fulltextcatalogfiles
END
CREATE TABLE #tmp_fulltextcatalogfiles
(
[DbName] nvarchar(128),
[DbId] int,
[Name] nvarchar(128),
[Path] nvarchar(260)
)
DECLARE #DB NVARCHAR(128)
DECLARE #DBID int
DECLARE #CMD NVARCHAR(MAX)
DECLARE Databases CURSOR FAST_FORWARD FOR
SELECT name,dbid FROM master..sysdatabases
WHERE name in (N'Suri''s _DB')
OPEN Databases
FETCH NEXT FROM Databases INTO #DB, #DBID
WHILE (##FETCH_STATUS = 0)
BEGIN
BEGIN TRY
SELECT #CMD = 'use ' + '[' + #DB + ']' + '; select N''' + #DB + ''' as [DbName],' + CAST(#DBID as varchar(30)) + ' as [DbId],s.name as [GroupName],s.data_space_id as [GroupId], CAST(case s.type when ''FD'' then 1 else 0 end AS bit) AS [IsFileStream] FROM sys.filegroups as s ORDER by [GroupId] ASC'
INSERT INTO #tmp_filegroups execute(#CMD)
SELECT #CMD = 'use ' + '[' + #DB + ']' + '; select N''' + #DB + ''' as [DbName],' + CAST(#DBID as varchar(30)) + ' as [DbId],s.data_space_id as [GroupId],s.name AS [Name],s.physical_name AS [FileName],s.size * CONVERT(float,8) AS [Size],s.is_media_read_only AS [IsReadOnlyMedia],s.is_read_only AS [IsReadOnly],CAST(case s.state when 6 then 1 else 0 end AS bit) AS [IsOffline],s.is_sparse AS [IsSparse],CAST(CASE s.file_id WHEN 1 THEN 1 ELSE 0 END AS bit) AS [IsPrimaryFile],CAST(fileproperty(s.name,''SpaceUsed'') AS float) * CONVERT(float,8) AS [SpaceUsed], Type AS [FileType] FROM sys.database_files as s'
INSERT INTO #tmp_dbandlogfiles execute(#CMD)
SELECT #CMD = 'use ' + '[' + #DB + ']' + '; select N''' + #DB + ''' as [DbName],' + CAST(#DBID as varchar(30)) + ' as [DbId],cat.name as [Name],cat.path as [Path] FROM sys.fulltext_catalogs AS cat ORDER by [Name] ASC'
INSERT INTO #tmp_fulltextcatalogfiles execute(#CMD)
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE() AS ERRMESS
END CATCH
FETCH NEXT FROM Databases INTO #DB, #DBID
END
CLOSE Databases
DEALLOCATE Databases
select [DbName],[DbId],[GroupName],[GroupId],[IsFileStream] from #tmp_filegroups
DROP TABLE #tmp_filegroups
Why this is failing?
I tried escaping the single quotes
When you build the sql query string, the dbname's single quote is not terminated. Replace any single quotes to 2 single quotes to terminate the character.
SELECT #CMD = 'use ' + '[' + #DB + ']' + '; select N''[' + replace(#DB, '''', '''''') + ']'' as [DbName],' + CAST(#DBID as varchar(30)) + ' as [DbId],s.name as [GroupName],s.data_space_id as [GroupId], CAST(case s.type when ''FD'' then 1 else 0 end AS bit) AS [IsFileStream] FROM sys.filegroups as s ORDER by [GroupId] ASC'
INSERT INTO #tmp_filegroups execute(#CMD)
SELECT #CMD = 'use ' + '[' + #DB + ']' + '; select N''[' + replace(#DB, '''', '''''') + ']'' as [DbName],' + CAST(#DBID as varchar(30)) + ' as [DbId],s.data_space_id as [GroupId],s.name AS [Name],s.physical_name AS [FileName],s.size * CONVERT(float,8) AS [Size],s.is_media_read_only AS [IsReadOnlyMedia],s.is_read_only AS [IsReadOnly],CAST(case s.state when 6 then 1 else 0 end AS bit) AS [IsOffline],s.is_sparse AS [IsSparse],CAST(CASE s.file_id WHEN 1 THEN 1 ELSE 0 END AS bit) AS [IsPrimaryFile],CAST(fileproperty(s.name,''SpaceUsed'') AS float) * CONVERT(float,8) AS [SpaceUsed], Type AS [FileType] FROM sys.database_files as s'
INSERT INTO #tmp_dbandlogfiles execute(#CMD)
SELECT #CMD = 'use ' + '[' + #DB + ']' + '; select N''[' + replace(#DB, '''', '''''') + ']'' as [DbName],' + CAST(#DBID as varchar(30)) + ' as [DbId],cat.name as [Name],cat.path as [Path] FROM sys.fulltext_catalogs AS cat ORDER by [Name] ASC'
INSERT INTO #tmp_fulltextcatalogfiles execute(#CMD)

Can I make a quickly SQL call in the MainThread? Delphi

I have several SQL calls in my Delphi VCL application which uses FireDac to call a MySQL Server to get some data.
However, I am doing all this calls inside the UIThread because they take only a couple of milliseconds. Like the example below:
This is my UI Form
type
TfrmCadPlacas = class(TForm)
lblNumeroDaPlaca: TLabel;
...
...
...
procedure TfrmCadPlacas.btnSalvarClick(Sender: TObject);
begin
// ------------- SQL -------------
if not EstaEditando then
begin
InserirPlaca(Placa, Marca, Modelo, Cor, IDLote, IDHistorico,
dmDados.IDUsuario, dmDados.IDLoteamento);
ShowMessage(SMsgPlacaInseridaSucesso);
end;
end;
InserirPlaca procedure
procedure InserirPlaca(Placa, Marca, Modelo, Cor:string; IDLote, IDHistorico, IDUsuario, IDLoteamento: Integer);
var
qryInserir: TFDQuery;
begin
qryInserir := TFDQuery.Create(nil);
with qryInserir do
begin
Connection := dmDados.FDConnection;
Active := False;
SQL.Clear;
SQL.Add('INSERT INTO ' + T_PLACAS);
SQL.Add('(' + C_PLACA + ', ');
SQL.Add(C_MARCA + ', ');
SQL.Add(C_MODELO + ', ');
SQL.Add(C_COR + ', ');
SQL.Add(C_ID_LOTE + ', ');
SQL.Add(C_ID_HISTORICO + ') ');
SQL.Add('VALUES (:' + C_PLACA + ', ');
SQL.Add(':' + C_MARCA + ', ');
SQL.Add(':' + C_MODELO + ', ');
SQL.Add(':' + C_COR + ', ');
SQL.Add(':' + C_ID_LOTE + ', ');
SQL.Add(':' + C_ID_HISTORICO + ') ');
Params[0].AsString := Placa;
Params[1].AsString := Marca;
Params[2].AsString := Modelo;
Params[3].AsString := Cor;
Params[4].AsInteger := IDLote;
Params[5].AsInteger := PesquisarHistorico(IDLote);
ExecSQL;
end;
end;
As you can see, I am performing a MySQL Server request in the MainThread.
After watching some classes I noticed it is wrong to perform heavy operation in the UIThread as it should be only for GUI. In my case, the operation is pretty fast so it doesn't disturb the UI, if the internet connection is good.
Should I put this MySQL Server request in a background Thread?

Delphi 2009, How can I detect if a MySQL transaction was rolled back?

Adapting the code from mysql transaction - roll back on any exception I am making two inserts into a table via a transaction that rolls back if either insert fails. I would like to use Delphi to detect if a rollback has happened or not.
I already use a try - except block to check for errors in executing the whole transaction but presumably a rollback is treated by Delphi as a correct execution.
Is the only way to do this to use a SELECT afterward to see if the data is there?
That could be tricky as the live data that is inserted could possibly be duplicated if two transactions happened for the same person, same amount and on the same day. (The uniqueness of each row is implemented via an autoincrement column (subs_paid_id) that doesn't appear in the inserts)
At the risk of being verbose I have below shown the DLL for the table and my delphi code for doing the inserts.
(ToSQL is just a class that converts various passed parameters into a format suitable for a SQL string. MyConnection1 is a Devart MyDAC TMyConnection conected to a remote database)
/*DDL Information*/
-------------------
CREATE TABLE subscriptions_paid
(
subscription_year varchar(4) NOT NULL DEFAULT '',
member_id int(11) NOT NULL DEFAULT '0',
individual_subs_due float DEFAULT NULL,
individual_subs_paid float DEFAULT NULL,
payment_date date DEFAULT NULL,
import_date date DEFAULT NULL,
user_comment varchar(100),
subs_paid_id int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (subscription_year,member_id,subs_paid_id),
KEY subs_paid_id (subs_paid_id)
)
ENGINE=InnoDB AUTO_INCREMENT=538 DEFAULT CHARSET=utf8
and the Delphi code, including generating the SQL is
procedure TFrm_EditSubsPaid.btnConfirmTransferToSelectedClick(Sender: TObject);
//make sql to add a new payment for FirstMemberID, FirstSubsDue, FirstSubsYear using
//dtpNewPaymentDate, edtNewPaymentComment, edtNewPayment and
//a new negative 'payment' for SecondMemberID, SecondSubsDue,
//SecondSubsYear, using edtAmountToTransferFrom , dtpTransferFrom and
//edtNewTransferFromComment
var overpaid : single;
begin
if TransferAmountValid then
begin
SQL := ''
+'DELIMITER $$ '
+'CREATE PROCEDURE transfer() '
+'BEGIN '
//next two lines allow for all the transaction to be rolled back if any insert fails
+' DECLARE `_rollback` BOOL DEFAULT 0; '
+' DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET `_rollback` = 1; '
+ 'START TRANSACTION '
+'INSERT INTO subscriptions_paid ' //the positive payment into account
+' ( '
+' subscription_year , '
+' member_id , '
+' individual_subs_due , '
+' individual_subs_paid, '
+' payment_date , '
+' import_date , '
+' user_comment '
+' ) '
+' VALUES '
+' ( '
+' ToSQL.Text(FirstSubsYear) + ', '
+ FirstMemberID + ', '
+ ToSQL.Float(StrToFloat(FirstSubsDue)) +', '
+ ToSQL.Float(StrToFloat(edtAmountToTransferFrom.Text)) +', '
+ ToSQL.Date(DateOf(dtpTransferFrom.date)) + ', '
+ 'NULL' + ', '
+ ToSQL.Text('(Tfr From ' + SecondMemberID +') ' + edtNewTransferFromComment.text) +' '
+ ');'
+'INSERT INTO subscriptions_paid ' //the negative payment out of account
+' ( '
+' subscription_year , '
+' member_id , '
+' individual_subs_due , '
+' individual_subs_paid, '
+' payment_date , '
+' import_date , '
+' user_comment '
+' ) '
+' VALUES '
+' ( '
+ ToSQL.Text(FirstSubsYear) + ', '
+ SecondMemberID + ', '
+ ToSQL.Float(StrToFloat(SecondSubsDue)) +', '
+ ToSQL.Float(StrToFloat('-' + edtAmountToTransferFrom.Text)) +', '
+ ToSQL.Date(DateOf(dtpTransferFrom.date)) + ', '
+ 'NULL' + ', '
+ ToSQL.Text('(Tfr To ' + FirstMemberID +') ' + edtNewTransferFromComment.text) +' '
+ ');'
//next five lines allow for all the transaction to be rolled back if any insert fails
+'IF `_rollback` THEN '
+' ROLLBACK; '
+'ELSE '
+' COMMIT; '
+'END IF; '
+'END$$'
+'DELIMITER ;' ;
try
begin
dMod.MyConnection1.ExecSQL(sql);
dMod.MyConnection1.ExecSQL('CALL transfer;');
// ???? now check if the inserts went OK ???
end;
except
on E : Exception do
begin
showmessage (
'Exception class name = '+E.ClassName+ slinebreak
+ 'Exception message = '+E.Message);
end //on E
end;//try
end; //if
end;

Receiving data from an SQL table in Delphi

I have a form which needs to fetch and display data from a MYSQL database.
The SQL code which I have written works fine, as I have tried to execute it within MYSQL.
I have also used a similar format of code to the one in my form, within another form, to fetch and display SQL data. The code works perfectly in the other form.
However, my code for this form does not seem to be receiving/displaying the data from the SQL table.
Here's a snippet of the code written for the OnShow event of the form.
procedure TfrmEditBooking.FormShow(Sender: TObject);
var
CustName: string;
begin
if SelectedID > 0 then
begin
with frmBookingData.ADOQuery1 do
begin
Open;
SQL.Clear;
SQL.Add('SELECT Name, Surname ' +
'FROM customers_main ' +
'WHERE customers_main.idcustomers_main ' +
'IN ' +
'(SELECT bookings_main.customers_main_idcustomers_main ' +
'FROM bookings_main ' +
'WHERE bookings_main.idbookings_main = ' + IntToStr(SelectedID) + ')');
ExecSQL;
CustName := FieldByName('Surname').AsString + ' ' + FieldByName('Name').AsString;
Label1.Caption := CustName;
Close;
end;
end;
end;
One uses 'execsql' when one is not expecting to receive a cursor into a dataset (in other words, use 'execsql' with 'update', 'insert' and 'delete' statements but not with 'select').
You should replace the 'execsql' command with 'open' ... and remove the 'open' before 'sql.clear'.
Don't use a subquery when you should be using a join.
I think that your code ought to look like this
procedure TfrmEditBooking.FormShow(Sender: TObject);
begin
if SelectedID > 0 then
with frmBookingData.ADOQuery1 do
begin
SQL.Clear;
SQL.Add ('SELECT Name, Surname ');
sql.add ('FROM customers_main inner join bookings_main');
sql.add ('on customers_main.idcustomers_main = ');
sql.add ('bookings_main.customers_main_idcustomers_main');
sql.add ('where bookings_main.idbookings_main = :p1');
sql.params[0].asinteger:= SelectedID;
open;
Label1.Caption := fieldbyname ('name').asstring + ' ' +
fieldbyname ('surname').asstring;
Close;
end;
end;
To get this running you should change it to
procedure TfrmEditBooking.FormShow(Sender: TObject);
var
CustName: string;
begin
if SelectedID > 0 then
begin
with frmBookingData.ADOQuery1 do
begin
Close; // close first
SQL.Clear;
SQL.Add(
'SELECT Name, Surname '+
'FROM customers_main '+
'WHERE customers_main.idcustomers_main '+
'IN '+
'(SELECT bookings_main.customers_main_idcustomers_main '+
'FROM bookings_main '+
'WHERE bookings_main.idbookings_main = '+IntToStr(SelectedID)+')');
Open; // open the query
if not Eof then
CustName := FieldByName('Surname').AsString+' '+FieldByName('Name').AsString
else
CustName := 'not found';
Close; // close when finished
end;
Label1.Caption := CustName;
end;
end;
But you should get some (negative) side effects, if frmBookingData.ADOQuery1 is already in use for something different

How to split the name string in mysql?

How to split the name string in mysql ?
E.g.:
name
-----
Sachin ramesh tendulkar
Rahul dravid
Split the name like firstname,middlename,lastname:
firstname middlename lastname
--------- ------------ ------------
sachin ramesh tendulkar
rahul dravid
I've separated this answer into two(2) methods. The first method will separate your fullname field into first, middle, and last names. The middle name will show as NULL if there is no middle name.
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(fullname, ' ', 1), ' ', -1) AS first_name,
If( length(fullname) - length(replace(fullname, ' ', ''))>1,
SUBSTRING_INDEX(SUBSTRING_INDEX(fullname, ' ', 2), ' ', -1) ,NULL)
as middle_name,
SUBSTRING_INDEX(SUBSTRING_INDEX(fullname, ' ', 3), ' ', -1) AS last_name
FROM registeredusers
This second method considers the middle name as part of the lastname. We will only select a firstname and lastname column from your fullname field.
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(fullname, ' ', 1), ' ', -1) AS first_name,
TRIM( SUBSTR(fullname, LOCATE(' ', fullname)) ) AS last_name
FROM registeredusers
There's a bunch of cool things you can do with substr, locate, substring_index, etc. Check the manual for some real confusion. http://dev.mysql.com/doc/refman/5.0/en/string-functions.html
There is no string split function in MySQL. so you have to create your own function. This will help you. More details at this link.
Function:
CREATE FUNCTION SPLIT_STR(
x VARCHAR(255),
delim VARCHAR(12),
pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
delim, '');
Usage:
SELECT SPLIT_STR(string, delimiter, position)
Example:
SELECT SPLIT_STR('a|bb|ccc|dd', '|', 3) as third;
+-------+
| third |
+-------+
| ccc |
+-------+
Well, nothing I used worked, so I decided creating a real simple split function, hope it helps:
DECLARE inipos INTEGER;
DECLARE endpos INTEGER;
DECLARE maxlen INTEGER;
DECLARE item VARCHAR(100);
DECLARE delim VARCHAR(1);
SET delim = '|';
SET inipos = 1;
SET fullstr = CONCAT(fullstr, delim);
SET maxlen = LENGTH(fullstr);
REPEAT
SET endpos = LOCATE(delim, fullstr, inipos);
SET item = SUBSTR(fullstr, inipos, endpos - inipos);
IF item <> '' AND item IS NOT NULL THEN
USE_THE_ITEM_STRING;
END IF;
SET inipos = endpos + 1;
UNTIL inipos >= maxlen END REPEAT;
You can use bewlo one also:
SELECT SUBSTRING_INDEX(Name, ' ', 1) AS fname,
SUBSTRING_INDEX(SUBSTRING_INDEX(Name,' ', 2), ' ',-1) AS mname,
SUBSTRING_INDEX(Name, ' ', -1) as lname FROM mytable;
Here is the split function I use:
--
-- split function
-- s : string to split
-- del : delimiter
-- i : index requested
--
DROP FUNCTION IF EXISTS SPLIT_STRING;
DELIMITER $
CREATE FUNCTION
SPLIT_STRING ( s VARCHAR(1024) , del CHAR(1) , i INT)
RETURNS VARCHAR(1024)
DETERMINISTIC -- always returns same results for same input parameters
BEGIN
DECLARE n INT ;
-- get max number of items
SET n = LENGTH(s) - LENGTH(REPLACE(s, del, '')) + 1;
IF i > n THEN
RETURN NULL ;
ELSE
RETURN SUBSTRING_INDEX(SUBSTRING_INDEX(s, del, i) , del , -1 ) ;
END IF;
END
$
DELIMITER ;
SET #agg = "G1;G2;G3;G4;" ;
SELECT SPLIT_STRING(#agg,';',1) ;
SELECT SPLIT_STRING(#agg,';',2) ;
SELECT SPLIT_STRING(#agg,';',3) ;
SELECT SPLIT_STRING(#agg,';',4) ;
SELECT SPLIT_STRING(#agg,';',5) ;
SELECT SPLIT_STRING(#agg,';',6) ;
select (case when locate('(', LocationName) = 0
then
horse_name
else
left(LocationName, locate('(', LocationName) - 1)
end) as Country
from tblcountry;
concat(upper(substring(substring_index(NAME, ' ', 1) FROM 1 FOR 1)), lower(substring(substring_index(NAME, ' ', 1) FROM 2 FOR length(substring_index(NAME, ' ', 1))))) AS fname,
CASE
WHEN length(substring_index(substring_index(NAME, ' ', 2), ' ', -1)) > 2 THEN
concat(upper(substring(substring_index(substring_index(NAME, ' ', 2), ' ', -1) FROM 1 FOR 1)), lower(substring(substring_index(substring_index(f.nome, ' ', 2), ' ', -1) FROM 2 FOR length(substring_index(substring_index(f.nome, ' ', 2), ' ', -1)))))
ELSE
CASE
WHEN length(substring_index(substring_index(f.nome, ' ', 3), ' ', -1)) > 2 THEN
concat(upper(substring(substring_index(substring_index(f.nome, ' ', 3), ' ', -1) FROM 1 FOR 1)), lower(substring(substring_index(substring_index(f.nome, ' ', 3), ' ', -1) FROM 2 FOR length(substring_index(substring_index(f.nome, ' ', 3), ' ', -1)))))
END
END
AS mname
To get the rest of the string after the second instance of the space delimiter
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX('Sachin ramesh tendulkar', ' ', 1), ' ', -1) AS first_name,
SUBSTRING_INDEX(SUBSTRING_INDEX('Sachin ramesh tendulkar', ' ', 2), ' ', -1)
AS middle_name,
SUBSTRING('Sachin ramesh tendulkar',LENGTH(SUBSTRING_INDEX('Sachin ramesh tendulkar', ' ', 2))+1) AS last_name
SELECT
p.fullname AS 'Fullname',
SUBSTRING_INDEX(p.fullname, ' ', 1) AS 'Firstname',
SUBSTRING(p.fullname, LOCATE(' ',p.fullname),
(LENGTH(p.fullname) - (LENGTH(SUBSTRING_INDEX(p.fullname, ' ', 1)) + LENGTH(SUBSTRING_INDEX(p.fullname, ' ', -1))))
) AS 'Middlename',
SUBSTRING_INDEX(p.fullname, ' ', -1) AS 'Lastname',
(LENGTH(p.fullname) - LENGTH(REPLACE(p.fullname, ' ', '')) + 1) AS 'Name Qt'
FROM people AS p
LIMIT 100;
Explaining:
Find firstname and lastname are easy, you have just to use SUBSTR_INDEX function
Magic happens in middlename, where was used SUBSTR with Locate to find the first space position and LENGTH of fullname - (LENGTH firstname + LENGTH lastname) to get all the middlename.
Note that LENGTH of firstname and lastname were calculated using SUBSTR_INDEX
You could use the common_schema and use the tokenize function. For more information about this, follow the links. Your code the would end up like:
call tokenize(name, ' ');
However, be aware that a space is not a reliable separator for first and last name. E.g. In Spain it is common to have two last names.
CREATE DEFINER=`root`#`localhost` FUNCTION `getNameInitials`(`fullname` VARCHAR(500), `separator` VARCHAR(1)) RETURNS varchar(70) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE `result` VARCHAR(500) DEFAULT '';
DECLARE `position` TINYINT;
SET `fullname` = TRIM(`fullname`);
SET `position` = LOCATE(`separator`, `fullname`);
IF NOT `position`
THEN RETURN LEFT(`fullname`,1);
END IF;
SET `fullname` = CONCAT(`fullname`,`separator`);
SET `result` = LEFT(`fullname`, 1);
cycle: LOOP
SET `fullname` = SUBSTR(`fullname`, `position` + 1);
SET `position` = LOCATE(`separator`, `fullname`);
IF NOT `position` OR NOT LENGTH(`fullname`)
THEN LEAVE cycle;
END IF;
SET `result` = CONCAT(`result`,LEFT(`fullname`, 1));
-- SET `result` = CONCAT_WS(`separator`, `result`, `buffer`);
END LOOP cycle;
RETURN upper(`result`);
END
1.Execute this function in mysql.
2.this will create a function. Now you can use this function anywhere you want.
SELECT `getNameInitials`('Kaleem Ul Hassan', ' ') AS `NameInitials`;
3. The above getNameInitails first parameter is string you want to filter and second is the spectator character on which you want to separate you string.
4. In above example 'Kaleem Ul Hassan' is name and i want to get initials and my separator is space ' '.
We have stored the value of course Name and chapter name in single column ChapterName.
Value stored like : " JAVA : Polymorphism "
you need to retrieve CourseName : JAVA and ChapterName : Polymorphism
Below is the SQL select query to retrieve .
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(ChapterName, ' ', 1), ' ', -1) AS
CourseName,
REPLACE(TRIM(SUBSTR(ChapterName, LOCATE(':', ChapterName)) ),':','') AS
ChapterName
FROM Courses where `id`=1;
Please let me know if any question on this.
Combined a few answers here to create a SP that returns the parts of the string.
drop procedure if exists SplitStr;
DELIMITER ;;
CREATE PROCEDURE `SplitStr`(IN Str VARCHAR(2000), IN Delim VARCHAR(1))
BEGIN
DECLARE inipos INT;
DECLARE endpos INT;
DECLARE maxlen INT;
DECLARE fullstr VARCHAR(2000);
DECLARE item VARCHAR(2000);
create temporary table if not exists tb_split
(
item varchar(2000)
);
SET inipos = 1;
SET fullstr = CONCAT(Str, delim);
SET maxlen = LENGTH(fullstr);
REPEAT
SET endpos = LOCATE(delim, fullstr, inipos);
SET item = SUBSTR(fullstr, inipos, endpos - inipos);
IF item <> '' AND item IS NOT NULL THEN
insert into tb_split values(item);
END IF;
SET inipos = endpos + 1;
UNTIL inipos >= maxlen END REPEAT;
SELECT * from tb_split;
drop table tb_split;
END;;
DELIMITER ;
To get the rest of the string after the second instance of the space delimiter:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(MsgRest, ' ', 1), ' ', -1) AS EMailID
, SUBSTRING_INDEX(SUBSTRING_INDEX(MsgRest, ' ', 2), ' ', -1) AS DOB
, IF(
LOCATE(' ', `MsgRest`) > 0,
TRIM(SUBSTRING(SUBSTRING(`MsgRest`, LOCATE(' ', `MsgRest`) +1),
LOCATE(' ', SUBSTRING(`MsgRest`, LOCATE(' ', `MsgRest`) +1)) +1)),
NULL
) AS Person
FROM inbox
DELIMITER $$
DROP FUNCTION IF EXISTS `split_name`$$
CREATE FUNCTION split_name (p_fullname TEXT, p_part INTEGER)
RETURNS TEXT
READS SQL DATA
BEGIN
DECLARE v_words INT UNSIGNED;
DECLARE v_name TEXT;
SET p_fullname=RTRIM(LTRIM(p_fullname));
SET v_words=(SELECT SUM(LENGTH(p_fullname) - LENGTH(REPLACE(p_fullname, ' ', ''))+1));
IF v_words=1 THEN
IF p_part=1 THEN
SET v_name=p_fullname;
ELSEIF p_part=2 THEN
SET v_name=NULL;
ELSEIF p_part=3 THEN
SET v_name=NULL;
ELSE
SET v_name=NULL;
END IF;
ELSEIF v_words=2 THEN
IF p_part=1 THEN
SET v_name=SUBSTRING(p_fullname, 1, LOCATE(' ', p_fullname) - 1);
ELSEIF p_part=2 THEN
SET v_name=SUBSTRING(p_fullname, LOCATE(' ', p_fullname) + 1);
ELSEIF p_part=3 THEN
SET v_name=NULL;
ELSE
SET v_name=NULL;
END IF;
ELSEIF v_words=3 THEN
IF p_part=1 THEN
SET v_name=SUBSTRING(p_fullname, 1, LOCATE(' ', p_fullname) - 1);
ELSEIF p_part=2 THEN
SET p_fullname=SUBSTRING(p_fullname, LOCATE(' ', p_fullname) + 1);
SET v_name=SUBSTRING(p_fullname, 1, LOCATE(' ', p_fullname) - 1);
ELSEIF p_part=3 THEN
SET p_fullname=REVERSE (SUBSTRING(p_fullname, LOCATE(' ', p_fullname) + 1));
SET p_fullname=SUBSTRING(p_fullname, 1, LOCATE(' ', p_fullname) - 1);
SET v_name=REVERSE(p_fullname);
ELSE
SET v_name=NULL;
END IF;
ELSEIF v_words>3 THEN
IF p_part=1 THEN
SET v_name=SUBSTRING(p_fullname, 1, LOCATE(' ', p_fullname) - 1);
ELSEIF p_part=2 THEN
SET p_fullname=REVERSE(SUBSTRING(p_fullname, LOCATE(' ', p_fullname) + 1));
SET p_fullname=SUBSTRING(p_fullname, LOCATE(' ', p_fullname,SUBSTRING_INDEX(p_fullname,' ',1)+1) + 1);
SET v_name=REVERSE(p_fullname);
ELSEIF p_part=3 THEN
SET p_fullname=REVERSE (SUBSTRING(p_fullname, LOCATE(' ', p_fullname) + 1));
SET p_fullname=SUBSTRING(p_fullname, 1, LOCATE(' ', p_fullname) - 1);
SET v_name=REVERSE(p_fullname);
ELSE
SET v_name=NULL;
END IF;
ELSE
SET v_name=NULL;
END IF;
RETURN v_name;
END;
SELECT split_name('Md. Obaidul Haque Sarker',1) AS first_name,
split_name('Md. Obaidul Haque Sarker',2) AS middle_name,
split_name('Md. Obaidul Haque Sarker',3) AS last_name
First Create Procedure as Below:
CREATE DEFINER=`root`#`%` PROCEDURE `sp_split`(str nvarchar(6500), dilimiter varchar(15), tmp_name varchar(50))
BEGIN
declare end_index int;
declare part nvarchar(6500);
declare remain_len int;
set end_index = INSTR(str, dilimiter);
while(end_index != 0) do
/* Split a part */
set part = SUBSTRING(str, 1, end_index - 1);
/* insert record to temp table */
call `sp_split_insert`(tmp_name, part);
set remain_len = length(str) - end_index;
set str = substring(str, end_index + 1, remain_len);
set end_index = INSTR(str, dilimiter);
end while;
if(length(str) > 0) then
/* insert record to temp table */
call `sp_split_insert`(tmp_name, str);
end if;
END
After that create procedure as below:
CREATE DEFINER=`root`#`%` PROCEDURE `sp_split_insert`(tb_name varchar(255), tb_value nvarchar(6500))
BEGIN
SET #sql = CONCAT('Insert Into ', tb_name,'(item) Values(?)');
PREPARE s1 from #sql;
SET #paramA = tb_value;
EXECUTE s1 USING #paramA;
END
How call test
CREATE DEFINER=`root`#`%` PROCEDURE `test_split`(test_text nvarchar(255))
BEGIN
create temporary table if not exists tb_search
(
item nvarchar(6500)
);
call sp_split(test_split, ',', 'tb_search');
select * from tb_search where length(trim(item)) > 0;
drop table tb_search;
END
call `test_split`('Apple,Banana,Mengo');
Based on previous answers and do some modifications...
note:
p_delimiter has to be VARCHAR(1) couse CHAR(1) if is ' ' (space) gives '' (removes space and returns empty string)
Instead use of LENGTH I prefer CHAR_LENGTH which is safe for multibyte characters like UTF
DROP FUNCTION IF EXISTS FN_SPLIT_STR;
DELIMITER ;;
CREATE FUNCTION FN_SPLIT_STR(
p_input VARCHAR(2000), p_delimiter VARCHAR(1), p_position INT
)
RETURNS VARCHAR(2000)
DETERMINISTIC
BEGIN
DECLARE chunks INT;
SET chunks := CHAR_LENGTH(p_input) - CHAR_LENGTH(REPLACE(p_input, p_delimiter, '')) + 1;
IF p_position > chunks THEN
RETURN NULL;
END IF;
RETURN SUBSTRING_INDEX(SUBSTRING_INDEX(p_input, p_delimiter, p_position), p_delimiter, -1);
END;;
DELIMITER ;
SELECT "SUBSTRING_INDEX(name, ' ', 1) as first_name", "TRIM(REPLACE(name, SUBSTRING_INDEX(name, ' ', 1), '')) as last_name" FROM tbl;