I'm struggling with the following problem. I have a column with this kind of data:
'abbb ccc '
' aaa abbb ccc'
'abbb ccc '
' aaa abbb ccc '
' ccc'
'aaa abbb'
I want to count the number of spaces on the left and the number of spaces on the right of each string.
Try using a combination of LEN, LTRIM, and REVERSE:
SELECT
LEN(col) - LEN(LTRIM(col)) AS num_left,
LEN(REVERSE(col)) - LEN(LTRIM(REVERSE(col))) AS num_right
FROM yourTable;
Demo
As #AaronDietz mentioned in the comment below, LEN actually also trims whitespace on the right. But LEN does not affect leading whitespace. To compensate for this we can reverse the string and then do the calculation using LTRIM.
DECLARE #s NVARCHAR(50)='abbb ccc '
DECLARE #t NVARCHAR(50)=' aaa abbb ccc'
SELECT
RightSpaces = LEN(RTRIM(REVERSE(#s))) - LEN(#s),
LeftSpaces = LEN(#t) - LEN(LTRIM(REVERSE(#t)))
output
RightSpaces LeftSpaces
3 4
or you can use DATALENGTH and remove the need for REVERSE
SELECT
LeftSpaces = (DATALENGTH(#s)- DATALENGTH(RTRIM(#s)))/2,
RightSpaces = (DATALENGTH(#t)- DATALENGTH(LTRIM(#t)))/2
output
RightSpaces LeftSpaces
3 4
You can ditch LEN and TRIM functions and use PATINDEX instead:
SELECT
str,
PATINDEX('%[^ ]%', str) - 1 AS leading_spaces,
PATINDEX('%[^ ]%', REVERSE(str)) - 1 AS trailing_spaces
FROM testdata
Output:
| str | leading_spaces | trailing_spaces |
+--------------------+----------------+-----------------+
| abbb·ccc··· | 0 | 3 |
| ····aaa·abbb·ccc | 4 | 0 |
| abbb·ccc··· | 0 | 3 |
| ···aaa·abbb·ccc··· | 3 | 3 |
| ···ccc | 3 | 0 |
| aaa·abbb | 0 | 0 |
SQL Fiddle
Use datalength to get the full length
len will rtrim
declare #t varchar(100) = ' abbb ccc ';
select len(#t) as 'len', datalength(#t) as 'datalength',
datalength(#t) - datalength(ltrim(#t)) as 'left',
datalength(#t) - datalength(rtrim(#t)) as 'right'
You can do this...
SELECT Len(col + 'End') - Len(Rtrim(col)) - 3 AS Rno,
Len(col) - Len(Ltrim(col)) AS Lno
Since LEN function does not include trailing spaces, you could add extra text at the end of the string and remove the length of that text later.
Refer this example (4 white spaces)
SELECT LEN('test ') = 4
SELECT LEN('test ' + 'End') = 11
SELECT LEN('test ' + 'End') - 3 = 8
Related
I am using SQL Server 2014 and I have a table (t1) in my database which contain a column called "MealPlan".
This column contains a list of strings (extract below):
MealPlan
Sansrepas315€/pers.=630€pour2pers.Devis/RésaSelectionner
Sansrepas394€/pers.=787€pour2pers.Devis/RésaSelectionner
Sansrepas547€/pers.=1 093€pour2pers.Devis/RésaSelectionner
Sansrepas547€/pers.=1 093€pour2pers.Devis/RésaSelectionner
Sansrepas700€/pers.=1 400€pour2pers.Devis/RésaSelectionner
Sansrepas328€/pers.=656€pour2pers.Devis/RésaSelectionner
I need to extract the numbers between the characters = and €
I have the following codes in place which does exactly what I need:
SUBSTRING(MealPlan,LEN(LEFT(MealPlan,CHARINDEX('=', MealPlan)+1)),LEN(MealPlan) - LEN(LEFT(MealPlan,CHARINDEX('=', MealPlan))) - LEN(RIGHT(MealPlan,CHARINDEX('€', (REVERSE(MealPlan)))))) AS [Price]
After running the above my column "Price" appear as follows:
Price
630
787
1 093
1 093
1 400
656
However, I want to get rid of that space in the numbers where a thousand digit is present.
My expected output:
Price
630
787
1093
1093
1400
656
I have tried the following but it is not working:
REPLACE(SUBSTRING(MealPlan,LEN(LEFT(MealPlan,CHARINDEX('=', MealPlan)+1)),LEN(MealPlan) - LEN(LEFT(MealPlan,CHARINDEX('=', MealPlan))) - LEN(RIGHT(MealPlan,CHARINDEX('€', (REVERSE(MealPlan)))))), ' ','') AS [Price2]
Any help would be much appreciated.
I just ran your query in my sample database and it is working fine..
select
REPLACE(SUBSTRING(Description,
LEN(LEFT(Description,CHARINDEX('=', Description)+1)),
LEN(Description) - LEN(LEFT(Description,CHARINDEX('=', Description))) - LEN(RIGHT(Description,CHARINDEX('€', (REVERSE(Description)))))
), ' ','') AS [Description]
from Worker
Table #a1
| MealPlan |
| -------- |
| Sansrepas315€/pers.=630€pour2pers.Devis/RésaSelectionner |
| Sansrepas394€/pers.=787€pour2pers.Devis/RésaSelectionner |
| Sansrepas547€/pers.=1 093€pour2pers.Devis/RésaSelectionner |
Query
SELECT
REPLACE(
SUBSTRING(MealPlan,CHARINDEX('=', MealPlan)+1, CHARINDEX('=',REVERSE(MealPlan)) - CHARINDEX('€',REVERSE(MealPlan)) -1 )
,' ', ''
)
as value
FROM #a1
results
value
630
787
1093
The solution about "cut and paste" provided by Jiří Baum above did the trick for me.
It is very easy to tokenize a string of characters by using XML and XQuery.
No need to parse string and call multiple functions: SUBSTRING(), CHARINDEX(), PATINDEX(), LEN(), REVERSE(), etc.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, MealPlan NVARCHAR(1000));
INSERT INTO #tbl (MealPlan) VALUES
(N'Sansrepas315€/pers.=630€pour2pers.Devis/RésaSelectionner'),
(N'Sansrepas394€/pers.=787€pour2pers.Devis/RésaSelectionner'),
(N'Sansrepas547€/pers.=1 093€pour2pers.Devis/RésaSelectionner'),
(N'Sansrepas547€/pers.=1 093€pour2pers.Devis/RésaSelectionner'),
(N'Sansrepas700€/pers.=1 400€pour2pers.Devis/RésaSelectionner'),
(N'Sansrepas328€/pers.=656€pour2pers.Devis/RésaSelectionner');
-- DDL and sample data population, end
DECLARE #separator CHAR(1) = '='
, #euro CHAR(1) = '€';
SELECT t.*
, REPLACE(c.value('(/root/r[3]/text())[1]', 'VARCHAR(20)'),SPACE(1),'') AS Price
FROM #tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(REPLACE(MealPlan,#euro,#separator), #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c);
Output
+----+------------------------------------------------------------+--------+
| ID | MealPlan | Result |
+----+------------------------------------------------------------+--------+
| 1 | Sansrepas315€/pers.=630€pour2pers.Devis/RésaSelectionner | 630 |
| 2 | Sansrepas394€/pers.=787€pour2pers.Devis/RésaSelectionner | 787 |
| 3 | Sansrepas547€/pers.=1 093€pour2pers.Devis/RésaSelectionner | 1093 |
| 4 | Sansrepas547€/pers.=1 093€pour2pers.Devis/RésaSelectionner | 1093 |
| 5 | Sansrepas700€/pers.=1 400€pour2pers.Devis/RésaSelectionner | 1400 |
| 6 | Sansrepas328€/pers.=656€pour2pers.Devis/RésaSelectionner | 656 |
+----+------------------------------------------------------------+--------+
Try this:
Declare #MealPlan as varchar(250) = 'Sansrepas547€/pers.=1 093€pour2pers.Devis/RésaSelectionner'
Select Replace(
SUBSTRING(#MealPlan,
CharIndex('=', #MealPlan)+1,
CharIndex(')',Replace(#MealPlan, '€p', ')'))- CharIndex('=', #MealPlan)-1 ),
' ', '')
Output:
Let me know if this doesn't work or you have a problem understanding the query.
Given the table table1 in PostgreSQL:
number1 | number2 | min_length | max_length
40 | 1801 | 8 | 8
40 | 182 | 8 | 8
42 | 32 | 6 | 8
42 | 4 | 6 | 6
43 | 691 | 9 | 9
I want to create new table table2 like:
start | stop
4018010000 | 4018019999
4018200000 | 4018299999
42320000 | 42329999
423200000 | 423299999
4232000000 | 4232999999
42400000 | 42499999
43691000000 | 43691999999
So the new table will be consisting of:
column_1 = a concatenation of old_column_1 + old_column_2 + a number of "0" equal to (old_column_3 - length of the old_column_2)
column_2 = a concatenation of old_column_1 + old_column_2 + a number of "9" equal to (old_column_3 - length of the old_column_2)
And when min_length is not equal to max_length, I need to take into account all the possible lengths. So for the line "42";"32";6;8 , all the lengths are: 6,7 and 8.
I tried to create the new table2 AS table1, then to create new columns start and stop, then to concatenate the columns 1 and 2 like that:
create table table2 as select * from table1;
alter table table2 add column start text,
add column stop text;
update table2 set start = number1 || number2
For the concatenation of the first 2 columns. But I can't figure out how to do the all concatenation, to add the "0"s and the "9"s.
Assuming all columns are NOT NULL, and max_length is always greater than min_length this does the job:
CREATE TABLE table2 AS
SELECT t.number1::text || rpad(t.number2::text, len, '0') AS start
, t.number1::text || rpad(t.number2::text, len, '9') AS stop
FROM table1 t, generate_series(min_length, max_length) len
db<>fiddle here
The manual for generate_series() and rpad().
If number1 or number2 can be NULL, throw in COALESCE:
SELECT COALESCE(t.number1::text, '') || rpad(COALESCE(t.number2::text,''), len, '0') AS start
, COALESCE(t.number1::text, '') || rpad(COALESCE(t.number2::text,''), len, '9') AS stop
FROM table1 t, generate_series(min_length, max_length) len;
db<>fiddle here
If min_length or max_length can be NULL, you'll have to define what's supposed to happen.
I have a column of data that looks like this:
52,0:58,1094.00
52,227.00
58,383:105,0
58,0:112,0:64,85.00
58,1376:112,0:105,0:107,0
57,2858.00
52,0:58,98
57,0:106,3317.00
I need to extract every number that is either before a comma "," OR between a colon ":" AND comma "," ONLY where the value after the comma "," is greater than 0.
Using the data above, I want to get:
58
52
58
64
58
57
58
106
Thanks in advance for the help!
You could do:
select split_part(s.v, ',', 1)::numeric res
from mytable t
cross join lateral regexp_split_to_table(t.vals, ':') as s(v)
where split_part(s.v, ',', 2)::numeric > 0
The query uses regexp_split_to_table() to split the strings on the ':' separator into new rows, that contains values like '52,0' or '58,1094.00'. Then, we use split_part() to extract the two numbers, and use the second one for filtering.
Demo on DB Fiddle:
select split_part(s.v, ',', 1) res
from mytable t
cross join lateral regexp_split_to_table(t.vals, ':') as s(v)
where split_part(s.v, ',', 2)::numeric > 0
| res |
| :-- |
| 58 |
| 52 |
| 58 |
| 64 |
| 58 |
| 57 |
| 58 |
| 106 |
In my table, the values appear like this in a column:
Names
----------------
Doe,John P
Woods, Adam
Hart, Keeve
Hensen,Sarah J
Is it possible to get a count of space between the comma and first character after it? Expected result:
Names |Count_of_spaces_before_next_character
-----------------|--------------------------------------
Doe,John P | 0
Woods, Adam | 1
Hart, Keeve | 5
Hensen,Sarah J | 0
Thanks for any direction, much appreciate it !
You may try with the following statement:
Table:
CREATE TABLE Data (Names varchar(1000))
INSERT INTO Data
(Names)
VALUES
('Doe,John P'),
('Woods, Adam'),
('Hart, Keeve'),
('Hensen,Sarah J')
Statement:
SELECT Names, LEN(After) - LEN(LTRIM(After)) AS [Count]
FROM (
SELECT
Names,
RIGHT(Names, LEN(Names) - CHARINDEX(',', Names)) AS After
FROM Data
) t
Result:
Names Count
Doe,John P 0
Woods, Adam 1
Hart, Keeve 5
Hensen,Sarah J 0
You can remove everything up to the comma and then measure the length after trimming off the spaces:
select len(rest) - len(ltrim(rest))
from t cross apply
(values (stuff(name, 1, charindex(',', name + ','), ''))
) v(rest);
The + ',' handles the case where there is no comma in name.
Here is a db<>fiddle.
Updated
Even shorter & Cleaner
select names
,patindex('%[^ ]%',stuff(names,1,charindex(',',names),''))-1 as Count_of_spaces_before_next_character
from mytab
-
+----------------+---------------------------------------+
| names | Count_of_spaces_before_next_character |
+----------------+---------------------------------------+
| Doe,John P | 0 |
| Woods, Adam | 1 |
| Hart, Keeve | 5 |
| Hensen,Sarah J | 0 |
| Hello World | 0 |
+----------------+---------------------------------------+
SQL Fiddle
Building off of Gordon's answer. If you are not familiar with table constructor approach in cross apply, you might find this more readable. Hope the select in cross apply clears your confusion around how it can behave like a subquery. Also, I don't think you need to pad the name column with an additional ',' because charindex will return 0 if it doesn't find that character.
select name, len(rest) - len(ltrim(rest))
from t1
cross apply (select stuff(name, 1, charindex(',', name), '') as rest) t2
Logic: LEN(string after first comma) - LEN(LTRIM(string after first comma))
SELECT Name, LEN (SUBSTRING(Names,CHARINDEX(',',Names,1)+1 ,LEN(Names) - CHARINDEX(',',Names,1)) ) - LEN(LTRIM(SUBSTRING(Names,CHARINDEX(',',Names,1)+1 , LEN(Names) - CHARINDEX(',',Names,1))))
FROM #Table
select string coming before space dash space
say table 1
id | name
1 | Poo - SR
2 | S-h-r - SR
3 | SDR - mj
4 | srk - kl
i want it like
id | name
1 | Poo
2 | S-h-r
3 | SDR
4 | srk
use REPLACE function in SQL?
example :SELECT REPLACE('abcdefghicde','cde','xxx');
You can use
select left(#column, charindex(' - ',#column) - 1 )+' '+right(right(#column, charindex(' - ',#column) + 1),charindex(' ',right(#column, charindex(' - ',#column) + 0))+1)
Replace #column with your table column name