I wanted to add 3 periods to a result string if the string is over 20 characters. The result is using Group_Concat which works fine, I just don't know the best way to modify the result if over 20 chars.
query
LEFT(GROUP_CONCAT(employee.firstname, ' ', employee.lastname), 20) as employeenames
Totally untested:
CASE
WHEN CHAR_LENGTH(GROUP_CONCAT(employee.firstname, ' ', employee.lastname))>20
THEN CONCAT(LEFT(GROUP_CONCAT(employee.firstname, ' ', employee.lastname), 20) '...')
ELSE GROUP_CONCAT(employee.firstname, ' ', employee.lastname)
END AS employeenames
It's not likely that this performs decently, though. This is the kind of stuff your client-side language will possibly do way better.
Related
I have a very specific question.
I have to build a SQL statement that builds a table where some columns are merged together. These columns shall be formatted with delimiters like '\n' or ' ' or ' - '. These delimiters shall be added only if the column before is not empty or null. This should prevent empty lines or unneeded delimiters.
Here is how I started:
SELECT
any_table.table_id,
CONCAT(any_table.text1, '\n', any_table.text2) AS text1_2,
FROM
any_table
WHERE any_table.use = 'true'
This code concats text1 and text2 as a new column text1_2 and uses a line feed as delimiter. The missing part is that line feed shall just be added if any_table.text1 is not null or empty.
Is there an elegant way in doing this with SQL?
thx
Some databases support a very handy function called concat_ws() which does exactly what you want:
CONCAT_WS('\n', NULLIF(any_table.text1, ''), NULLIF(any_table.text2, '')) AS text1_2,
In standard SQL, you can do:
TRIM(LEADING '\n' FROM CONCAT( '\n', || NULLIF(any_table.text1, ''),
'\n' || NULLIF(any_table.text2, '')
)
)
It is possible that your database supports neither of these constructs.
if you'r under SQL SERVER you can use,
SELECT id, CONCAT(colonne1 + ' - ', colonne2) FROM "table"
if you'r under Oracle : you shoul use || for concaténation like
SELECT id, CONCAT(colonne1 || ' - ', colonne2) FROM "table"
I have a table 'car_purchases' with a 'description' column. The column is a string that includes first name initial followed by full stop, space and last name.
An example of the Description column is
'Car purchased by J. Blow'
I am using 'substring_index' function to extract the letter preceding the '.' in the column string. Like so:
SELECT
Description,
SUBSTRING_INDEX(Description, '.', 1) as TrimInitial,
SUBSTRING_INDEX(
SUBSTRING_INDEX(Description, '.', 1),' ', -1) as trimmed,
length(SUBSTRING_INDEX(
SUBSTRING_INDEX(Description, '.', 1),' ', -1)) as length
from car_purchases;
I will call this query 1.
picture of the result set (Result 1) is as follows
As you can see the problem is that the 'trimmed' column in the select statement starts counting the 2nd delimiter ' ' instead of the first from the right and produces the result 'by J' instead of just 'J'. Further the length column indicates that the string length is 5 instead of 4 so WTF?
However when I perform the following select statement;
select SUBSTRING_INDEX(
SUBSTRING_INDEX('Car purchased by J. Blow', '.', 1),' ', -1); -- query 2
Result = 'J' as 'Result 2'.
As you can see from result 1 the string in column 'Description' is exactly (as far as I can tell) the same as the string from 'Result 2'. But when the substring_index is performed on the column (instead of just the string itself) the result ignores the first delimiter and selects a string from the 2nd delimiter from the right of the string.
I've racked my brains over this and have tried 'by ' and ' by' as delimiters but both options do not produce the desired result of a single character. I do not want to add further complexity to query 1 by using a trim function. I've also tried the cast function on result column 'trimmed' but still no success. I do not want to concat it either.
There is an anomaly in the 'length' column of query 1 where if I change the length function to char_length function like so:
select length(SUBSTRING_INDEX(
SUBSTRING_INDEX(Description, '.', 1),' ', -1)) as length -- result = 5
select char_length(SUBSTRING_INDEX(
SUBSTRING_INDEX(Description, '.', 1),' ', -1)) as length -- result = 4
Can anyone please explain to me why the above select statement would produce 2 different results? I think this is the reason why I am not getting my desired result.
But just to be clear my desired outcome is to get 'J' not 'by J'.
I guess I could try reverse but I dont think this is an acceptable compromise. Also I am not familiar with collation and charset principles except that I just use the defaults.
Cheers Players!!!!
CHAR_LENGTH returns length in characters, so a string with 4 2-byte characters would return 4. LENGTH however returns length in bytes, so a string with 4 2-byte characters would return 8. The discrepancy in your results (including SUBSTRING_INDEX) says that the "space" between by and J is not actually a single-byte space (ASCII 0x20) but a 2-byte character that looks like a space. To workaround this, you could try replacing all unicode characters with spaces using CONVERT and REPLACE. In this example, I have an en-space unicode character in the string between by and J. The CONVERT changes that to a ?, and the REPLACE then converts that to a space:
SELECT SUBSTRING_INDEX( SUBSTRING_INDEX("Car purchased by J. Blow", '.', 1),' ', -1)
Output:
by J
With CONVERT and REPLACE:
SELECT SUBSTRING_INDEX( SUBSTRING_INDEX(REPLACE(CONVERT("Car purchased by J. Blow" USING ASCII), '?', ' '), '.', 1),' ', -1)
Output
J
For your query, you would replace the string with your column name i.e.
SELECT SUBSTRING_INDEX( SUBSTRING_INDEX(REPLACE(CONVERT(description USING ASCII), '?', ' '), '.', 1),' ', -1)
Demo on DBFiddle
I have the following MySQL query which works
SELECT *,
CONCAT( office, ' ', contactperson ) AS bigDataField
FROM webcms_mod_references
HAVING bigDataField REGEXP "one|two"
Now there is no ORDER BY and if:
- bigDataField contains "one" this field is shown
- bigDataField contains "one two" this field is shown aswell
now it depends on the id which one of those is shown first, but I want the one with the more matches to be shown first!
I tried with
SUM(
CASE WHEN bigDataField REGEXP "one|two"
THEN 1
ELSE 0 END
) AS matches
But that does not work. Can anyone help me. I think the best would be as the title says to count the matching charachters from the REGEXP. If there are other ways please explain.
The REGEXP is a user input, so, I'm trying to implement a small search over a small Database.
This is theoretical whilst sqlfiddle is down but you might have to split the REGEXP into two so you can count the matches. REGEXP will return either a 0 or 1. Either it matched or didn't. There's no support for finding how many times it was matched in a string.
SELECT *,
CONCAT( office, ' ', contactperson ) AS bigDataField
FROM webcms_mod_references
HAVING bigDataField REGEXP "one|two"
ORDER BY (bigDataField REGEXP "one" + bigDataField REGEXP "two") DESC
There is no way to count the amount of matches on a regex. What you can do is match them separately and order by each of those matches. EG:
SELECT *,
CONCAT( office, ' ', contactperson ) AS bigDataField
FROM webcms_mod_references
HAVING bigDataField REGEXP "one|two"
ORDER BY
CASE WHEN bigDataField REGEXP "one" AND bigDataField REGEXP "two" THEN 0
ELSE 1 -- The else should catch the "two" alone or the "one" alone because of the filtering
END
Of course, you can use a LIKE here too but maybe your regex are more complex than that :)
When I want to count some substring I do replace and "-" the length, example:
SELECT (
LENGTH('longstringlongtextlongfile') -
LENGTH(REPLACE('longstringlongtextlongfile', 'long', ''))
) / LENGTH('long') AS `occurrences`
I think this is an elegant solution for a problem of counting how many times 'long' appears inside provided 'string'
This is not especially the answer to this question, but I think strongly attached to it... (And I hope, will help someone, who cames from google, etc)
So if you use PHP (if not, may dont keep reading ...), you can build the query with that, and in this case, you can do this (about #Moob great answer):
function buildSearchOrderBy(string $regex, string $columName, string $alternateOrderByColumName): string
{
$keywords = explode ('|', $regex);
if (empty ($keywords)) {
return $alternateOrderByColumName;
}
$orderBy = '(';
$i = 0;
foreach ($keywords as $keyword) {
$i++;
if ($i > 1) $orderBy .= " + ";
$orderBy .= "IF((" . $columName . " REGEXP '" . $keyword . "')>0, " . (100 + strlen($keyword)) . ", 0)";
}
$orderBy .= ')';
return $orderBy;
}
So in this case every match worth 100 + so many scores, what the numbers of the characters in the current keyword. Every match starting from 100, because this ensure the base, that the first results will be these, where the total score originate from the more matches, but in proportionally worth more a longer keyword in any case.
Builded to one column check, but I think you can update easy.
If copied to your project, just use like this (just an example):
$orderBy = buildSearchOrderBy($regex, 'article.title', 'article.created');
$statement = "SELECT *
FROM article
WHERE article.title REGEXP '(" . $regex . ")'
ORDER BY " . $orderBy . " DESC"
;
Excuse me for bad English. I have a table with a field called Subject . The value of this field is any kind of string. is there a way to find how many space char in per field . for example for "mme mme" is one and for "mme" is zero and for "mme mme mme" is two.
From MySQL List:
select length(Subject) - length(replace(Subject, ' ', ''))
Or this:
SELECT CHAR_LENGTH(Subject) - CHAR_LENGTH(REPLACE(Subject, ' ', '')) as
num_spaces FROM my_table;
If you want to do it with PHP, you can use substr_count.
substr_count(STRING_HERE, " ");
Docs to substr_count(); (PHP.NET)
It will return the number of spaces as you needed.
You can try this:
SELECT length(Subject) - length(replace(Subject, ' ', '')) FROM table;
select now() will output 2012-11-20 09:05:38.
select substr(now(), locate(' ', now())) will output 09:05:38.
How can I obtain this result: 2012-11-20 instead? Been there, done that but can't achieve it yet. Forgive me for my lacking but please help me. Thanks!
Not an specific answer to your question about substrings, but if I wanted the DATE part of NOW() I would do:
SELECT DATE(NOW());
Or for the time portion
SELECT TIME(NOW());
For actual string purposes though you can use:
SUBSTR('SOME STRING', 0, LOCATE(' ', 'SOME STRING')) <- returns from position zero for a length of 4 characters
Or
SUBSTRING_INDEX('SOME STRING', ' ', 1) <- gives 'SOME'
SUBSTRING_INDEX('SOME STRING', ' ', -1) <- gives 'STRING'
you can use DATE_FORMAT
SELECT DATE_FORMAT('2012-11-20 09:05:38', '%Y-%m-%d')
or just DATE
SELECT DATE('2012-11-20 09:05:38')
SQLFiddle Demo (both queries)