I have the following code that I'm trying to refactor to format a phone number field in the format I need it in:
STUFF(STUFF(STUFF(REPLACE('02 212345678','02 2','02 '), 7, 0, ' '), 3, 0, ') '), 1, 0, '(')
It returns data currently as this:
(02) 123 45678
where I need it in this format
(02) 1234 5678
The problem is the extra space after the closing bracket and having 4 numbers either side.
Based on your example, does the following work for you?
with sampledata as (select '02 212345678' num)
select Concat(Stuff('() ',2,0,Left(num,2)), Stuff(Right(num,8),5,0,' '))
from sampledata
You existing code works, just need to change the 7 to an 8, but I far prefer to keep my formatting and data seperated. The code is waaaaaay easier to read and modify:
DECLARE #PhoneNumber varchar(20) = '02 212345678';
SELECT FORMATMESSAGE('(%s) %s %s', LEFT(#PhoneNumber, 2), SUBSTRING(#PhoneNumber, 4, 4), SUBSTRING(#PhoneNumber, 8, 4) );
Related
Im working on a query where the most obvious solution would be to combine the functionality of Like and Between, but im not sure if its possible.
My goal is to get ID's between a certain range, where the IDs are constructed of a leading code, followed by datetime, and the possible a couple more caracters like so:
ABC180715051623XYZ
The range would be from the current time, to 10 minutes prior. the leading characters don't matter for what is chosen, just the date time numbers in the center. an additional issue is that these leading characters can vary in length, somtimes 2, and other times 4.
On thatnote, ive been trying to use wildcards, and the like function, but they dont work as needed on there own. Is there any way to combine them?
Thank You
Assuming that:
The leading ID characters are always letters (actually just not numbers)
The date is always in the format yyMMddhhmmss
Then you could have your query as such:
SELECT * FROM [your_table]
WHERE CONVERT( -- Converts to a datetime
DATETIME, STUFF( -- STUFF #1
STUFF( -- STUFF #2
STUFF( -- STUFF #3
SUBSTRING([id_column],
PATINDEX('%[0-9]%',[id_column]), -- gets the index of the first number
12), -- gets the 12 digit date string (SUBSTRING)
7, 0, ' '), -- adds a space between date and time portions (STUFF #3)
10, 0, ':'), -- adds a ':' between hours and minutes (STUFF #2)
13, 0, ':')) -- adds a ':' between minutes and seconds (STUFF #1)
BETWEEN DATEADD(minute,-10, CURRENT_TIMESTAMP) -- 10 minutes ago
AND CURRENT_TIMESTAMP; -- now
This is taking the date and time part of the ID and forming it into a string that can then be converted into a datetime which can then be used in a the between of 10 mins ago and now. I've tried to format it so that it can be read but I'll explain the parts from the inside out below so you can edit if required.
Using your given value for ID of
ABC180715051623XYZ
First PATINDEX('%[0-9]%',[id_column]) This gets the (1-based) index first number in the id column. So this would be 4
This makes SUBSTRING([id_column], 4, 12) which gets out 180715051623
So then STUFF('180715051623', 7, 0, ' ') puts a space at the 7th index, giving 180715 051623
Then STUFF('180715 051623', 10, 0, ':') puts a ':' at the 10th index, giving 180715 05:1623
Then STUFF('180715 05:1623', 13, 0, ':') puts a ':' at the 13th index, giving 180715 05:16:23
This is then converted into the date '2018-07-15 05:16:23.000' and then used in the the between clause of two other datetimes.
I have the following field called "MaterialPrice". It is a data type of -
DECIMAL (18,2)
So a sample values is "10.88"
What I need to change it to is something like below -
0000000000000**1088**0
So the field length is 18, where the last character (to the left is always 0) and the characters in front of the original value are padded with zeros also.
Another example would be
501.02
would be
000000000000**50102**0
Any help would be appreciated.
Thanks
If I understand correctly the requirement, you could as the below:
DECLARE #val DECIMAL(18, 2) = 501.02
SELECT REPLICATE(0, 18 - LEN(#val)) + '**' + REPLACE(CAST(#val AS VARCHAR(50)), '.', '') + '**0'
Result: 000000000000**50102**0
I would:
Multiply by 100,
cast to string,
Measure length,
Concatenate: (17-length) "0"s, "**", the string number and "**0
I am attempting to concatenate two strings using "+", both these strings derive from a substring which have each been cast to varchar(20) from ntext fields that do not allow nulls.
When I run the code, it only takes the first of the two strings, and ignores the second, so the concatenation is unsuccessful. Any idea what I am doing wrong or missing here?
Select Top 100
Substring(Cast(w.WO_Type_Field_02 As nvarchar(20)), 1, 20) As PossFirst,
Substring(Cast(w.WO_Type_Field_04 As nvarchar(20)), 1, (20 -
Len(Substring(Cast(w.WO_Type_Field_02 As nvarchar(20)), 1, 20)) + 1)) As PossLast,
Substring(Cast(w.WO_Type_Field_02 As nvarchar(20)), 1, 20) +
Substring(Cast(w.WO_Type_Field_04 As nvarchar(20)), 1, (20 -
Len(Substring(Cast(w.WO_Type_Field_02 As nvarchar(20)), 1, 20)) + 1)) As PossLogin
from V_WOI_WorkOrder w
What I'm getting is the Following:
PossFirst PossLast PossLogin
----------- ----------- -----------
james roberts james
mark smith mark
harry chapman harry
What i should be getting is:
PossFirst PossLast PossLogin
----------- ----------- -----------
james roberts jamesroberts
mark smith marksmith
harry chapman harrychapman
The reason for my len within my substring is that the complete concatenation should not exceed 20 characters long, I'm not finished that part yet, but i think that is irrelevant to the point that the concatenation is failing for me.
Screenshot of results
Hmm, I'm not sure about the issue yet, but we can try doing this ..
SELECT PossFirst, PossLast, ISNULL(PossFirst,'') + ISNULL(PossLast,'') AS PossLogin FROM (
Select
Convert(nvarchar(20),Substring(Cast(w.WO_Type_Field_02 As nvarchar(20)), 1, 20)) As PossFirst,
Convert(nvarchar(20),Substring(Cast(w.WO_Type_Field_04 As nvarchar(20)), 1, (20 -
Len(Substring(Cast(w.WO_Type_Field_02 As nvarchar(20)), 1, 20)) + 1))) As PossLast,
from V_WOI_WorkOrder w
) AS T
EDIT : This is wierd, I have this table
and tried this
select PossFirst, PossLast, PossFirst + PossLast from (
select
Substring(Cast(w.firstname As nvarchar(20)), 1, 20) As PossFirst
, Substring(Cast(w.lastname As nvarchar(20)), 1, (20 -
Len(Substring(Cast(w.lastname As nvarchar(20)), 1, 20)) + 1)) As PossLast
from nTextDataTypeTest w
) AS T
with this result...
I wonder with what column data types you have, and I wonder what SQL version you're using..
EDIT : Lets try trimming them..
SELECT PossFirst, PossLast, ISNULL(PossFirst,'') + ISNULL(PossLast,'') AS PossLogin FROM (
Select
Rtrim(Ltrim(Convert(nvarchar(20),Substring(Cast(w.WO_Type_Field_02 As nvarchar(20)), 1, 20)))) As PossFirst,
Rtrim(Ltrim(Convert(nvarchar(20),Substring(Cast(w.WO_Type_Field_04 As nvarchar(20)), 1, (20 -
Len(Substring(Cast(w.WO_Type_Field_02 As nvarchar(20)), 1, 20)) + 1))))) As PossLast,
from V_WOI_WorkOrder w
) AS T
Weather using nText, or a varchar field that has originally derived from an nText field, a visual count on the characters differed from a Len on the characters by a total of 1 character.
A visual count on the characters showed for example 12 characters. A len on the [field] showed 13 characters, so when I substring [field] to len[field]-1 as shown below, I am then able to concatenate to it.
SUBSTRING([Field], 1, (Len([Field]) - 1)
What we have done is trimmed off the trailing hidden/special character that is stopping our concatenation from working.
CAST(SUBSTRING([Field], 1, (Len([Field]) - 1) As varchar(20))
We then Cast our result to varchar, in order to match the other other fields that we wish to concatenate.
I now have my final code using my fields and tables below which works successfully!
Select Cast(SUBSTRING(w.WO_Type_Field_02,1,(Len(w.WO_Type_Field_02)-1)) As varchar(20)) As PossFirst,
Substring(Cast(w.WO_Type_Field_04 As nvarchar(20)), 1, (20 -
Len(Substring(Cast(w.WO_Type_Field_02 As nvarchar(20)), 1, 20)) + 1)) As PossLast,
Cast(SUBSTRING(w.WO_Type_Field_02,1,(Len(w.WO_Type_Field_02)-1)) As varchar(20)) + '.' +
Substring(Cast(w.WO_Type_Field_04 As nvarchar(20)), 1, (20 -
Len(Substring(Cast(w.WO_Type_Field_02 As nvarchar(20)), 1, 20)) + 1)) As PossLogin
from V_WOI_WorkOrder w
The problem here is your ntext fields contain whitespace. These hidden characters are eating into your 20 character limit.
There are two easy ways to spot whitespace. You an use the LEN function and/or concatenate a leading and trailing character.
I've created an example on stack data exchange (link and code below) using a table variable. The benefit of this approach is we can all share the same code.
In this example james is postfixed with a number of blank spaces. The other records are not. As you can see james is returned without a surname. The others are not. This happens because the spaces count towards the 20 character limit. Using RTRIM will remove these.
RTRIM in SQL Server only works on spaces. If your whitespace is made from other control characters you will need a different approach.
I've replaced the SUBSTRINGs with a LEFT, which will achieve the same result in fewer steps.
EDIT 1: To include description of original problem and solution.
EDIT 2: Answer rewritten after the OPs issue was solved. New answer better explains the issue and solution.
Example
/* Let's make a variable that we can all share.
*/
DECLARE #SampleData TABLE
(
FirstName NTEXT NOT NULL,
LastName NTEXT NOT NULL
)
;
/* Populate the table with sample values for us
* to experiment with.
* Postfix james with blank spaces.
*/
INSERT INTO #SampleData
(
FirstName,
LastName
)
VALUES
('james ', 'roberts'),
('mark', 'smith'),
('harry', 'chapman')
;
/* CAST and CONCATENATE the NTEXT fields.
* SUBSTRING replaced with LEFT for simplicity.
* Pipe added to end of each string to show its length.
*/
SELECT
FirstName,
LastName,
LEFT(CAST(FirstName AS NVARCHAR(20)) + CAST(LastName AS NVARCHAR(20)), 20) + '|' AS FirstLastName_NoTRIM,
LEFT(RTRIM(CAST(FirstName AS NVARCHAR(20))) + RTRIM(CAST(LastName AS NVARCHAR(20))), 20) + '|' AS FirstLastName_WithTRIM
FROM
#SampleData
;
I have this string which is a combination of date and time but in string format meaning that it has no space. I parsed it from a very long string but I now have or need to convert it to a standard date and time.
This is my string for date and time:
141007024755
This is how I parsed it from a very long string of data
[date&time] = SUBSTRING(#ProductCode, 27, 12)
This is the format I'm expecting but can't do it.
2014-10-07 02:47:55.000
Can anyone give me a hint on how to do this? An advice perhaps.
Thanks.
If the string is always 12 characters long you could try this:
select cast(stuff(stuff(stuff('141007024755', 7,0,' '), 10,0,':'), 13,0,':') as datetime)
Basically it uses the stuff function to insert a space between the date and time parts and colons between the different time parts producing a string like141007 02:47:55that can be converted todatetimeusingcast.
Assuming the dates are formatted exactly as your sample string, you can just keep chopping up the string and appending it back together and cast the result to date. Simple function like this may help:
CREATE FUNCTION dbo.udf_ReturnDateFromString(#DateString AS VARCHAR(14))
RETURNS DATETIME
AS
BEGIN
SET #DateString = '20' + #DateString
RETURN CAST(LEFT(#DateString, 4) + '-' +
SUBSTRING(#DateString, 5, 2) + '-' +
SUBSTRING(#DateString, 7, 2) + ' ' +
SUBSTRING(#DateString, 9, 2) + ':' +
SUBSTRING(#DateString, 11, 2) + ':' +
SUBSTRING(#DateString, 13, 2) AS DATETIME)
END;
GO
SELECT dbo.udf_ReturnDateFromString('141007024755');
The result is:
2014-10-07 02:47:55.000
You get the idea. This was done on SS 2008 R2.
I'm trying to run this query:
SELECT
USER_KEY, CHAR_KEY, CONVERT(VARCHAR,substring(char_data, 9, 16)) as CHAR_NAME
FROM CHAR_DATA0
WHERE CONVERT(VARCHAR,substring(char_data, 9, 16)) LIKE '%BrightSide08'
Which returns me nothing. (I don't understand why)
But changing the query to
SELECT
USER_KEY, CHAR_KEY, CONVERT(VARCHAR,substring(char_data, 9, 16)) as CHAR_NAME
FROM CHAR_DATA0
WHERE CONVERT(VARCHAR,substring(char_data, 9, 16)) LIKE '%BrightSide08%'
Note that the only change is ...LIKE '%BrightSide08%'
This query now returns 1 row with the data:
21045 300434 BrightSide08
examples:
(I only need the wild card to be at the beginning because)
I want the following:
0BrightSide08
1BrightSide08
But not:
0BrightSide082
1BrightSide083
This is char_data
0x0600700701003800427269676874536964653038000000000401040024002900870000006126001E0000000000000000000000007526211E0000000000000000000000006B26021E0000000000000000000000007F26031E0000000000000000000000008C26041E0000000000000000000000009A26051E0000000000000000000000009F1F000014FE180079704700A83F0000EA47193000000000000000000000F102FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16220B00000000000000000000000000E82210000000000000000000000000006722060000000000000000000000000097221800000000000000000000000000832202000000000000000000000000000000DC055802DC055C025802D007370000000600891300009B3300004D6400004D640000BCAC050076D71F00E462362D1C1300006E600A139A58000020060000000000000000000000000000DC1701000000000000000000000000004712022B0000000000000000000000004B1203320000000000000000000001004B1204130000000000000000000001004B1205320000000000000000000001003D120600000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4712080C0000000000000000000000000106090500000000000000000000010047120A190000000000000000000001004B120B0A000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1210E09000000000000000000000202C1210E09000000000000000000000202210610000000000000000000000000000A3111000000000000000000000000004D221213000000000000000000004C004D221213000000000000000000004C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1210E09000000000000000000000202C1210E0900000000000000000000020236121800000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D221213000000000000000000004C004D221213000000000000000000004C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA221D06000000000000000000004701DA221D06000000000000000000004701FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A3D200500000000000000000000000057222105000000000000000000008201572221050000000000000000000082012F22231400000000000000000000F4012F22231400000000000000000000F401DA221D06000000000000000000004701DA221D06000000000000000000004701FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A3D200500000000000000000000000057222105000000000000000000008201572221050000000000000000000082012F22231400000000000000000000F4012F22231400000000000000000000F401FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB373011000000000000000000000000FB373011000000000000000000000000953C3202000000000000000000000000953C32020000000000000000000000001438341D0000000000000000000000001438341D000000000000000000000000B5383690000000000000000000000000B5383690000000000000000000000000FB373011000000000000000000000000FB373011000000000000000000000000953C3202000000000000000000000000953C32020000000000000000000000001438341D0000000000000000000000001438341D000000000000000000000000B5383690000000000000000000000000B5383690000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31000000C6340000000000000200000000000000040000000000000000000000000000000000000000000000000000000D0000009C00000069CF7F0000000000FFFF000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Actually, I spoke too soon in my comment. Defining an explicit length for the portion of the substring you're going after does prevent the volatility of varchar without length from interfering with your query:
DECLARE #x TABLE(y VARBINARY(MAX));
INSERT #x VALUES(
0x0600700701003800427269676874536964653038000000000401040024002900870000006126001E0000000000000000000000007526211E0000000000000000000000006B26021E0000000000000000000000007F26031E0000000000000000000000008C26041E0000000000000000000000009A26051E0000000000000000000000009F1F000014FE180079704700A83F0000EA47193000000000000000000000F102FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16220B00000000000000000000000000E82210000000000000000000000000006722060000000000000000000000000097221800000000000000000000000000832202000000000000000000000000000000DC055802DC055C025802D007370000000600891300009B3300004D6400004D640000BCAC050076D71F00E462362D1C1300006E600A139A58000020060000000000000000000000000000DC1701000000000000000000000000004712022B0000000000000000000000004B1203320000000000000000000001004B1204130000000000000000000001004B1205320000000000000000000001003D120600000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4712080C0000000000000000000000000106090500000000000000000000010047120A190000000000000000000001004B120B0A000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1210E09000000000000000000000202C1210E09000000000000000000000202210610000000000000000000000000000A3111000000000000000000000000004D221213000000000000000000004C004D221213000000000000000000004C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1210E09000000000000000000000202C1210E0900000000000000000000020236121800000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D221213000000000000000000004C004D221213000000000000000000004C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA221D06000000000000000000004701DA221D06000000000000000000004701FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A3D200500000000000000000000000057222105000000000000000000008201572221050000000000000000000082012F22231400000000000000000000F4012F22231400000000000000000000F401DA221D06000000000000000000004701DA221D06000000000000000000004701FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A3D200500000000000000000000000057222105000000000000000000008201572221050000000000000000000082012F22231400000000000000000000F4012F22231400000000000000000000F401FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB373011000000000000000000000000FB373011000000000000000000000000953C3202000000000000000000000000953C32020000000000000000000000001438341D0000000000000000000000001438341D000000000000000000000000B5383690000000000000000000000000B5383690000000000000000000000000FB373011000000000000000000000000FB373011000000000000000000000000953C3202000000000000000000000000953C32020000000000000000000000001438341D0000000000000000000000001438341D000000000000000000000000B5383690000000000000000000000000B5383690000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31000000C6340000000000000200000000000000040000000000000000000000000000000000000000000000000000000D0000009C00000069CF7F0000000000FFFF000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
);
SELECT CONVERT(VARCHAR, SUBSTRING(y, 9, 16)) FROM #x
WHERE CONVERT(VARCHAR, SUBSTRING(y, 9, 16)) LIKE '%BrightSide08';
-- 0 rows
SELECT CONVERT(VARCHAR, SUBSTRING(y, 9, 16)) FROM #x
WHERE CONVERT(VARCHAR(12), SUBSTRING(y, 9, 16)) LIKE '%BrightSide08';
-- 1 row
Now, whether you should be using 12 or something else depends on what all of the possible values might be and where they may be embedded in this specific slot in your varbinary value. If you can give some more specific examples we can help further, but in the meantime, it pays to be specific rather than wishy-washy when declaring varchar.
The most likely reason is that there is some unseen character after the 08. One way this could occur is if the field is defined as a char; it would then be padded with spaces.
One way to see if there are any such values is to append characters to delimit the value:
select '|'+char_data+'|'
. . .
You have another problem in your query. You are using varchar without a length. Bad, bad, bad. In fact, the convert doesn't seem to be needed at all. You can just do:
substring(char_data, 9, 16) LIKE '%BrightSide08'
But this is equivalent to:
left(char_data, 25) LIKE '%BrightSide08'
Or, because you are looking for values at the end of the field:
right(char_data, 12) = 'BrightSide08'