This question already has answers here:
CONCAT_WS() for SQL Server
(6 answers)
Closed 8 years ago.
I am looking for SQL Server equivalent of MySQL concat_ws to concatenate strings with separator. I could not find one, is there a single function in SQL server to achieve this task?
There is no real equivalent (even the referenced answer is not exactly equivalent). You would normally add the separators between each value:
select A + ',' + B + . . .
One primary difference is that concat_ws() will skip NULL arguments, but + will not. You could emulate this behavior with:
select stuff((coalesce(',' + A, '') + coalesce(',' + B, '') + . . .
), 1, 1, '')
Of course, this doesn't convert the values to strings, as concat_ws() does. So, a closer version is something like:
select stuff((coalesce(',' + cast(A as varchar(255)), '') +
coalesce(',' + cast(B as varchar(255)), '') +
. . .
), 1, 1, '')
You can apply the same fixes to the referenced answer:
SELECT id,
STUFF((SELECT ';' + cast(v as varchar(255))
FROM (VALUES (a), (b), (c), (d)) AS v (v)
WHERE v is not null
FOR XML PATH (''), TYPE
).value('.[1]', 'varchar(max)'),
1, 1, ''
)
FROM foo
ORDER BY id;
Related
I have an SQL query that returns the following values:
BC - Worces
BC Bristol
BC Central
BC Torquay
BC-Bath
BC-Exeter
BC-Payroll
So, we have some BC with just a space, some with a dash and some with a dash with spaces on either side. When returning these values, I want to replace any of these BC variants with "Business Continuity: " followed by Bath, or Exeter etc.
Is there a way of checking what value is returned and (I'm assuming in a separate column) returning a field based on it? If every iteration was the same, I could just use Trim, but it's the variation that's throwing me out.
You could use a case on the select
CASE WHEN Left(`colname`, 5) = 'BC - ' THEN CONCAT('Business Continuity: ', SUBSTRING(`colname`, 6))
WHEN Left(colname, 3) = 'BC ' THEN CONCAT('Business Continuity: ', SUBSTRING(`colname`, 4))
WHEN Left(`colname`, 3) = 'BC-' THEN CONCAT('Business Continuity: ', SUBSTRING(`colname`, 4))
ELSE `colname`
END as `colname`
You can use REPLACE function along with CASE statement for this.
SELECT CASE
WHEN `col_name` LIKE 'BC %' THEN REPLACE(`col_name`, 'BC ', 'Business Continuity: ')
WHEN `col_name` LIKE 'BC-%' THEN REPLACE(`col_name`, 'BC-', 'Business Continuity: ')
ELSE `col_name`
END as `col_name` FROM `table_name`;
*Not tested
select 'Business Continuity:' + SUBSTRING(REPLACE(fieldname, 'BC - ', 'BC-'), 4) from table;
Replaces all instances of 'BC - ' with 'BC-'.
Substrings everything from 4 characters onwards ie 'BC-' and 'BC '
I have a normal SQL statement:
SELECT VALUE_ID, UF_CRM_TASK FROM b_uts_tasks_task
Now this returns a a different field everytime but they take the form of the following:
a:1:{i:0;s:7:"CO_2012";} or a:1:{i:0;s:5:"CO_12";} or a:1:{i:0;s:7:"CO_2017";}
Basically they're different everytime. What I need is to just get the number after the CO_ part. I have tried TRIM but because everything changes in the leading and trailing section I don't think this would work.
I have looked on Stack Overflow for a while and cannot find it. I know how to do it in PHP:
$data = $row['UF_CRM_TASK'];
$companyID = substr($data, strpos($data, "CO_") + 1);
$newCompanyID = preg_replace('/[^0-9.]+/', '', $companyID);
But not SQL. Thanks in advance
In MYSQL is a bit ugly:
/*SUBSTRING_INDEX BASED ON CO_ AND THE LAST " - in 2 SUBSTRINGS*/
SELECT `VALUE_ID`, SUBSTRING_INDEX(SUBSTRING_INDEX(`UF_CRM_TASK`, 'CO_', -1), '"', 1) AS `COMPANY_ID` FROM `b_uts_tasks_task`
In PHP you can just unserialize():
$data = unserialize($row['UF_CRM_TASK']);
$companyID = str_replace('CO_', '', $data[0]);
eg:
$data = unserialize('a:1:{i:0;s:5:"CO_12";}');
echo str_replace('CO_', '', $data[0]);
//==> 12
You need to use CharIndex and SubString (Microsoft SQL) or
This is the sample code I made for my Microsoft SQL server:
declare #companyIdString varchar(50) = 'a:1:{i:0;s:7:"CO_2012";}'
print 'Company ID in a string: ' + #companyIdString
print 'Find first position: ' + Cast(charindex('"CO_', #companyIdString) as varchar(2))
print 'Locate the second position (the last "): ' + Cast(charindex('"', #companyIdString, charindex('"CO_', #companyIdString)+4) as varchar(2))
print 'Extracted Company Id: ' + substring(#companyIdString,charindex('"CO_', #companyIdString)+4, charindex('"', #companyIdString, charindex('"CO_', #companyIdString)+4) - charindex('"CO_', #companyIdString) - 4)
select
#companyIdString as CompanyIdString,
substring(#companyIdString,charindex('"CO_', #companyIdString)+4, charindex('"', #companyIdString, charindex('"CO_', #companyIdString)+4) - charindex('"CO_', #companyIdString) - 4) as CompanyId
I also made the same code on a mySQL server:
set #companyIdString := 'a:1:{i:0;s:7:"CO_2012";}';
select
#companyIdString as CompanyIdString,
substring_index(substring_index(substring_index(#companyIdString, '"', 2), '"', -1), '_', -1) as CompanyId
The substring_index starts by locating the second " (string is now a:1:{i:0;s:7:"CO_2012), then it searches backward with the -1 to locate the first " (string is now CO_2012). And then it searches backward for the underscore (string is now 2012).
I have a table where I am attempting to take 3 database table values and reformat them in a single value. Here is the SQL statement that I have at the moment:
SELECT
CASE WHEN cb_cardtype = 'Discover Credit Card'
THEN 'DS'
END +
';' + RIGHT(cardnumbers,4) + ';' + LPAD(MONTH(planexpdate), 2, '0') +
'/' + LPAD(YEAR(planexpdate), 2, '0') AS account_billing_key
FROM my_table
So what I wanted to get as an output here would be:
DS;4242;07/14
The problem is that I am using the + to attempt this, which actually adds the values together. Rather, I understand that I need to use CONCAT() to merge the values. I am unclear about how I can pull the individual values and then concatenate them as desired.
If your query is otherwise correct, all you need to do is to wrap all the strings you want to concatenate - comma separated - inside a call to CONCAT;
SELECT
CONCAT(
CASE WHEN cb_cardtype = 'Discover Credit Card' THEN 'DS' END,
';',
RIGHT(cardnumbers,4),
';',
LPAD(MONTH(planexpdate), 2, '0'),
'/',
LPAD(YEAR(planexpdate), 2, '0')
) AS account_billing_key
FROM my_table
I use Oracle and MySql, so if you have any answer in both codes please let me know,
Issue:
I have 2 columns in one table called: USers
Column#1= Names
Column#2= UCNames
This list contain names that are from different sources but partially match like:
Names
Alex Jones Marfex
UCNames
Alex Jonnes Mike Marfex
I want to compare both of the columns and find match based on the following attributes:
Search on the first 4 for letters and 4 last words and to store in new column called: verifiyed
Thanks
This gives you the first word in a string
Substring(Col,1,(Locate (' ',Col + ' ')-1)) First
This gives you the last word in a string
Reverse(Substring(Reverse(Col), 1, Locate(' ',Reverse(Col)) - 1)) Last
So your compare could be
Where
Substring(Col1,1,( Locate(' ',Col1 + ' ')-1))
= Substring(Col2,1,( Locate(' ',Col2 + ' ')-1))
And
Reverse(Substring(Reverse(Col1), 1, Locate(' ',Reverse(Col1)) - 1))
= Reverse(Substring(Reverse(Col2), 1, Locate(' ',Reverse(Col2)) - 1))
I went with words which seemed safer for what you are trying to do with just a bit more effort. If you do want to keep the 4 characters, just replace the Locate es with 4.
Based on the answer by #asantaballa , but using MySQL SUBSTRING_INDEX function :-
WHERE SUBSTRING_INDEX(Col1, ' ', 1) = SUBSTRING_INDEX(Col2, ' ', 1)
AND SUBSTRING_INDEX(Col1, ' ', -1) = SUBSTRING_INDEX(Col2, ' ', -1)
or to crudely check the first 4 characters and the last 4 words:-
WHERE SUBSTRING(Col1, 1, 4) = SUBSTRING(Col2, 1, 4)
AND SUBSTRING_INDEX(Col1, ' ', -4) = SUBSTRING_INDEX(Col2, ' ', -4)
I am trying to extract a certain part of a column that is between delimiters.
e.g. find foo in the following
test 'esf :foo: bar
So in the above I'd want to return foo, but all the regexp functions only return true|false,
is there a way to do this in MySQL
Here ya go, bud:
SELECT
SUBSTR(column,
LOCATE(':',column)+1,
(CHAR_LENGTH(column) - LOCATE(':',REVERSE(column)) - LOCATE(':',column)))
FROM table
Yea, no clue why you're doing this, but this will do the trick.
By performing a LOCATE, we can find the first ':'. To find the last ':', there's no reverse LOCATE, so we have to do it manually by performing a LOCATE(':', REVERSE(column)).
With the index of the first ':', the number of chars from the last ':' to the end of the string, and the CHAR_LENGTH (don't use LENGTH() for this), we can use a little math to discover the length of the string between the two instances of ':'.
This way we can peform a SUBSTR and dynamically pluck out the characters between the two ':'.
Again, it's gross, but to each his own.
This should work if the two delimiters only appear twice in your column. I am doing something similar...
substring_index(substring_index(column,':',-2),':',1)
A combination of LOCATE and MID would probably do the trick.
If the value "test 'esf :foo: bar" was in the field fooField:
MID( fooField, LOCATE('foo', fooField), 3);
I don't know if you have this kind of authority, but if you have to do queries like this it might be time to renormalize your tables, and have these values in a lookup table.
With only one set of delimeters, the following should work:
SUBSTR(
SUBSTR(fooField,LOCATE(':',fooField)+1),
1,
LOCATE(':',SUBSTR(fooField,LOCATE(':',fooField)+1))-1
)
mid(col,
locate('?m=',col) + char_length('?m='),
locate('&o=',col) - locate('?m=',col) - char_length('?m=')
)
A bit compact form by replacing char_length(.) with the number 3
mid(col, locate('?m=',col) + 3, locate('&o=',col) - locate('?m=',col) - 3)
the patterns I have used are '?m=' and '&o'.
select mid(col from locate(':',col) + 1 for
locate(':',col,locate(':',col)+1)-locate(':',col) - 1 )
from table where col rlike ':.*:';
If you know the position you want to extract from as opposed to what the data itself is:
$colNumber = 2; //2nd position
$sql = "REPLACE(SUBSTRING(SUBSTRING_INDEX(fooField, ':', $colNumber),
LENGTH(SUBSTRING_INDEX(fooField,
':',
$colNumber - 1)) + 1)";
This is what I am extracting from (mainly colon ':' as delimiter but some exceptions), as column theline255 in table loaddata255:
23856.409:0023:trace:message:SPY_EnterMessage (0x2003a) L"{#32769}" [0081] WM_NCCREATE sent from self wp=00000000 lp=0023f0b0
This is the MySql code (It quickly did what I want, and is straight forward):
select
time('2000-01-01 00:00:00' + interval substring_index(theline255, '.', 1) second) as hhmmss
, substring_index(substring_index(theline255, ':', 1), '.', -1) as logMilli
, substring_index(substring_index(theline255, ':', 2), ':', -1) as logTid
, substring_index(substring_index(theline255, ':', 3), ':', -1) as logType
, substring_index(substring_index(theline255, ':', 4), ':', -1) as logArea
, substring_index(substring_index(theline255, ' ', 1), ':', -1) as logFunction
, substring(theline255, length(substring_index(theline255, ' ', 1)) + 2) as logText
from loaddata255
and this is the result:
# LogTime, LogTimeMilli, LogTid, LogType, LogArea, LogFunction, LogText
'06:37:36', '409', '0023', 'trace', 'message', 'SPY_EnterMessage', '(0x2003a) L\"{#32769}\" [0081] WM_NCCREATE sent from self wp=00000000 lp=0023f0b0'
This one looks elegant to me. Strip all after n-th separator, rotate string, strip everything after 1. separator, rotate back.
select
reverse(
substring_index(
reverse(substring_index(str,separator,substrindex)),
separator,
1)
);
For example:
select
reverse(
substring_index(
reverse(substring_index('www.mysql.com','.',2)),
'.',
1
)
);
you can use the substring / locate function in 1 command
here is a mice tutorial:
http://infofreund.de/mysql-select-substring-2-different-delimiters/
The command as describes their should look for u:
**SELECT substr(text,Locate(' :', text )+2,Locate(': ', text )-(Locate(' :', text )+2)) FROM testtable**
where text is the textfield which contains "test 'esf :foo: bar"
So foo can be fooooo or fo - the length doesnt matter :).