using like in join with code igniter active records - mysql

I am having issues with a particular like in my active records query.
When I use join('users parent', 'child.treePath LIKE CONCAT(parent.treePath,"%")')
Code igniter spits out JOIN 'users' parent ON 'child'.'treePath' 'LIKE' CONCAT(parent.treePath,"%") (note that I have replaced all back ticks (`) with (') due to markdown :/)
So, the issue is that code igniter is wrapping LIKE in (`).
How can I tell it to not attempt to format this block?
Complete query:
$this->db->select('child.uuid')
->from('users child')
->join('users parent', 'child.treePath LIKE CONCAT(parent.treePath,"%")')
->where('parent.uuid', $uuid)
->where("LENGTH(REPLACE(child.treePath, parent.treePath, '')) - LENGTH(REPLACE(REPLACE(child.treePath, parent.treePath, ''), '/', '')) <= ", $levels, 'false')
->where("LENGTH(REPLACE(child.treePath, parent.treePath, '')) - LENGTH(REPLACE(REPLACE(child.treePath, parent.treePath, ''), '/', '')) > ", 0, 'false')
->group_by('child.treeId');

If you are chaining all these functions together in a single call, you might as well just use
$this->db->query("Write all your specific SQL here");
Not seeing the benefit of wrestling with Codeigniter's query builder in your case.

Related

How to crop text between braces

I have data in MySQL in one string field with below structure:
{language *lang_code*}text{language}{language *lang_code*}text{language}
And here is example:
{language en}text in english{language}{language de}text in german{language}
The ideal output for this would be in this case
text in english
So we want to disregard the other languages, just want to extract the first one, and put it into new column, because it's often the title of the product, with translations, and for us the first one is the most important.
The values in first braces may be different, so for example here the first one is english, but in other example it might be in german, so the lang code might also be dynamic.
I am wondering if it's possible to extract the text value between two first braces through SQL query?
This is really horrible but it works for your simple example -
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR('{language en}text in english{language}{language de}text in german{language}', '\\{language en\\}(.*?)\\{language\\}'), '}', -2), '{', 1);
or
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR('{language en}text in english{language}{language de}text in german{language}', '\\{language de\\}(.*?)\\{language\\}'), '}', -2), '{', 1);
to retrieve the german text.
To retrieve the first text in the string regardless of language you can use -
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR('{language en}text in english{language}{language de}text in german{language}', '\\{language [a-z]{2}\\}(.*?)\\{language\\}'), '}', -2), '{', 1);
Note this version assumes the language code is always 2 x a-z chars - [a-z]{2}
Here is an example of the above wrapped in a stored function -
DELIMITER $$
CREATE FUNCTION `ExtractLangString`(content TEXT, lang CHAR(8))
RETURNS text
DETERMINISTIC
BEGIN
-- if lang is not 2 chars in length or lang not found return first language string
IF LENGTH(lang) <> 2 OR content NOT LIKE CONCAT('%{language ', lang, '}%') THEN
SET lang = '[a-z]{2}';
END IF;
RETURN SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(content, CONCAT('\\{language ', lang, '\\}(.*?)\\{language\\}')), '}', -2), '{', 1);
END$$
DELIMITER ;
There is probably a cleaner way of doing it but I cannot think of it right now.
Obviously, the better solution would be to normalise the data that is currently serialised into this column.

Use DB::select + binding too select a row

I'm trying to get a row from the database but when using binding. I know that this doesn't work because the query automatically puts single quotes so it will be like this: select model, magazine, round('name', 2) etc. This doesn't work of course but how do I get rid of the single quotes?
$merkinformation = DB::select('select Model, Magazine, round(?, 2) as Rondetijd from rondetijden where Merk = ? order by ? limit 3;', [$track, $merk, $track]);
You can't use column nmaes like this.
You must concatinate the name of the column. But this is vulnerable to sql injection. So you must check if $track has a valid content
$merkinformation = DB::select('select Model, Magazine, round(`' . $track . '` , 2) as Rondetijd from rondetijden where Merk = ? order by ? limit 3;', [$merk, $track]);
there is ['] single quote and [`] punctuation mark. If start with single quote or double quote mysql will translate that as string where punctuation mark will be recognize as field name.
Are you sure that is a single quote ?

Using the trim function to narrow down results set

I need to gather data from two columns, concat them so that it's only the first six of the first column and the last six of the second column, separated by ' + '. Some have been input with weird spaces in front or in back, so we must also use the trim feature and get rid of all NULL. I haven't had any issues with the first part, but am struggling to use the trim feature in a way that gives the desired output.
Output needs to look like this:
Input Data sample:
The following code returns results, but the output doesn't match so I know the trim is wrong:
SELECT CONCAT(SUBSTRING(baseball, 1, 6), ' + ',
SUBSTRING(football, -6)) AS MYSTRING
FROM datenumtest2
WHERE baseball IS NOT NULL AND football IS NOT NULL;
I also tried the following, but get an error message about the parameters being incorrect:
SELECT CONCAT(SUBSTRING(LTRIM(baseball, 1, 6)), ' + ',
SUBSTRING(RTRIM(football, -6))) AS MYSTRING
FROM datenumtest2
WHERE baseball IS NOT NULL AND
football IS NOT NULL;
I'm still new to this site and learning, but I have tried to include as much as I can! If there is other information that I can add to help, please let me know.
You just need to use Trim() on the column(s), before using Substring() function on them:
SELECT CONCAT(SUBSTRING(TRIM(baseball), 1, 6), ' + ',
SUBSTRING(TRIM(football), -6)) AS MYSTRING
FROM datenumtest2
WHERE baseball IS NOT NULL AND
football IS NOT NULL;

MySQL to JSON not formed properly

I am trying to return JSON formatted results from a MySQL query but cannot get the correct format - it needs to be e.g.
{comCom:'test 3', comUid:'63',... etc
But what I'm getting is without apostrophes
{comCom:test 3, comUid:63,... etc
I am running the query in PHP as follows (shortened for ease of reading)
$result = mysql_query("select...
...GROUP_CONCAT(CONCAT('{comCom:',ww.comment, ', comUid:',h.user_id,', comName:',h.name,', comPic:',h.live_prof_pic,',comUrl:',h.url,',comWhen:',time_ago(ww.dateadded),'}')) comment,...
How can I get the punctuation?
I know mysql_query is deprecated btw, just in process of moving things to MySQLi
Can you not just escape the ' character with \'?
...GROUP_CONCAT(CONCAT('{comCom:\'',ww.comment, '\', comUid:\'',h.user_id,'\', comName:\'',h.name,'\', comPic:\'',h.live_prof_pic,'\',comUrl:\'',h.url,'\',comWhen:\'',time_ago(ww.dateadded),'\'}'))
or use a mixture of " with '
...GROUP_CONCAT(CONCAT("{comCom:'",ww.comment, "', comUid:'",h.user_id,"', comName:'",h.name,"', comPic:'",h.live_prof_pic,"',comUrl:'",h.url,"',comWhen:'",time_ago(ww.dateadded),"'}"))

Convert standard simplified pattern ( * ? ) to the LIKE pattern ( % _ )

I would like to know if there is a better way than :
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE('p%a_t*er?', '\\', '\\\\'), '%', '\%'), '_', '\_'), '*', '%'), '?', '_')
To transform standard search patterns * and ? to the LIKE equivalents % and _ in MySQL ?
There isn't a shorter method to perform multiple-character replacements directly in MySQL. There are alternatives such as User-Defined-Functions (UDFs), but I'm doubtful that any would be beneficial to your exact purpose.
My suggestion would be to perform the text replacement prior-to querying the database, if acceptable.
In PHP, this could be done with:
$searchQuery = $_GET['q'];
$searchQuery = str_replace(array('*', '?'), array('%', '_'), $searchQuery);
// perform your query as normal
In ASP, you could try:
string searchQuery = Request.QueryString["q"];
searchQuery = searchQuery.Replace("*", "%").Replace("?", "_");
// perform your query as normal
Though, both method aren't super-short, they do make it a little easier to read and also won't add any time to your db-query. Also, doing the replacement prior to the query will allow you to replace before the string is sanitized so you won't need to replace the \ as you do in your existing query - which saves you one replacement!
Instead of like you can use regexp of Mysql like this:
select * from my_table where col_name regexp 'p%a_t*er?';
While using regexp there is no need to do all those replacements to make your string like friendly.