sql select string coming before space dash space - error-handling

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

Related

How can I remove the spaces from these numbers?

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.

Convert a percentage(string, with a %) to a decimal in postgresql

I would like to average on the Scores(string) of each person from the following table in postgresql,
No. | Name | Term | Score
1 | A | 1 | 95.00%
2 | A | 2 | 99.00%
3 | C | 1 | 90.00%
4 | D | 1 | 100.00%
.
.
It does not like % on the score. How can I convert it into a decimal/float from a string containing a % as shown above?
Tried,
score::decimal
but it complains as,
ERROR: invalid input syntax for type numeric: "95.00%"
SQL state: 22P02
cast also does not seem to work.
How do I convert this?
One method uses replace():
select replace(score, '%', '')::numeric
If you actually want to convert it to a number between 0 and 1 rather than 0 and 100, try a case:
select (case when right(score, 1) = '%'
then (replace(score, '%', '')::numeric) / 100
else score::numeric
end)

Dynamic Column Names in BigQuery SQL Query

I have a BigQuery table in which every row is a visit of a user in a country. The schema is something like this:
UserID | Place | StartDate | EndDate | etc ...
---------------------------------------------------------------
134 | Paris | 234687432 | 23648949 | etc ...
153 | Bangkok | 289374897 | 2348709 | etc ...
134 | Paris | 9287324892 | 3435438 | etc ...
The values of the "Place" columns can be no more than tens of options, but I don't know them all in advance.
I want to query this table so that in the resulted table the columns are named as all the possibilities of the Place column, and the values are the total number of visits per user in this place.
The end result should look like this:
UserID | Paris | Bangkok | Rome | London | Rivendell | Alderaan
----------------------------------------------------------------
134 | 2 | 0 | 0 | 0 | 0 | 0
153 | 0 | 1 | 0 | 0 | 0 | 0
I guess I can select all the possible values of "Place" with SELECT DISTINCT but how can I achieve this structure of result table?
Thanks
Below is for BigQuery Standard SQL
Step 1 - dynamically assemble proper SQL statement with all possible values of "place" field
#standardSQL
SELECT '''
SELECT UserID,''' || STRING_AGG(DISTINCT
' COUNTIF(Place = "' || Place || '") AS ' || REPLACE(Place, ' ', '_')
) || ''' FROM `project.dataset.table`
GROUP BY UserID
'''
FROM `project.dataset.table`
Note: you will get one row output with the text like below (already split in multiple rows for better reading
SELECT UserID,
COUNTIF(Place = "Paris") AS Paris,
COUNTIF(Place = "Los Angeles") AS Los_Angeles
FROM `project.dataset.table`
GROUP BY UserID
Note; I replaced Bangkok with Los Angeles so you see why it is important to replace possible spaces with underscores
Step 2 - just copy output text of Step 1 and simply run it
Obviously you can automate above two steps using any client of your choice
If you just want to count the places, you can use countif():
select userid,
countif(place = 'Paris') as paris,
countif(place = 'Bangkok') as bangkok,
countif(place = 'Rome') as rome,
. . .
from t
group by userid;

PostgreSQL search lists of substrings in string column

I have the following table in a postreSQL database (simplified for clarity):
| serverdate | name | value
|-------------------------------------
0 | 2019-12-01 | A LOC 123 DISP | 1
1 | 2019-12-01 | B LOC 456 DISP | 2
2 | 2019-12-01 | C LOC 777 DISP | 0
3 | 2019-12-01 | D LOC 000 DISP | 10
4 | 2019-12-01 | A LOC 700 DISP | 123
5 | 2019-12-01 | F LOC 777 DISP | 8
name columns is of type string. The substrings LOC and DISP can have other values of different lengths but are not of interest in this question.
The problem: I want to SELECT the rows that only contain a certain substring. There are several substrings, passed as an ARRAY, in the following format:
['A_123', 'F_777'] # this is an example only
I would want to select all the rows that contain the first part of the substring (sepparating it by the underscore '_'), as well as the second. In this example, with the mentioned array, I should obtain rows 0 and 5 (as these are the only ones with exact matches in both parts of the):
| serverdate | name | value
|-------------------------------------
0 | 2019-12-01 | A LOC 123 DISP | 1
5 | 2019-12-01 | F LOC 777 DISP | 8
Row 4 has the first part of the substring correct, but not the other one, so it shouldn't be returned. Same thing with row 2 (only second part matches).
How could this query be done? I'm relatively new to SQL.
This query is part of process in Python, so I can adjust the input parameter (the substring array) if needed, but the behaviour must be the same as the one described.
Thanks!
Have you tried with regexp_replace and a subquery?
SELECT * FROM
(SELECT serverdate, substring(name from 1 for 1)||'_'||
regexp_replace(name, '\D*', '', 'g') AS name, value
FROM t) j
WHERE name IN('A_123', 'F_777');
Or using a CTE
WITH j AS (
SELECT serverdate, substring(name from 1 for 1)||'_'||
regexp_replace(name, '\D*', '', 'g') AS name2,
value,name
FROM t
) SELECT serverdate,name,value FROM j
WHERE name2 IN('A_123', 'F_777');
serverdate | name | value
------------+----------------+-------
2019-12-01 | A LOC 123 DISP | 1
2019-12-01 | F LOC 777 DISP | 8
(2 Zeilen)
Just unnest the array and join the table using a like clause
select
*
from
Table1
join
(
select
'%'||replace(unnest, '_', '%')||'%' pat
from
unnest(array['A_123', 'F_777'])
) pat_table on "name" like "pat"
Just replace unnest(array['A_123', 'F_777']) with unnest(string_to_array(str_variable, ','))
Thanks for your answers! Solution by Larry B got me an error, but it was caused by external factors (I run the queries using an internal tool developed by my company and it threw errors when using the % wildcard. Strange behaviour, I already contacted support team), so I could not test it properly.
Solution by Jim Jones seemed an alternative, but I found that, in some cases, the values in the name field would look like these (didn't notice it when writing the question, as it a rare case):
ABC LOC 123 DISP
So I modified the solution a little bit so as to grab the first part of the name when splitting it by the ' ' character.
(TLDR: 1st substring of name could be of arbitrary length, but is always at the start)
My solution is this one:
SELECT * FROM
(SELECT serverdate, split_part(name, ' ', 1)||'_'||
regexp_replace(name, '\D*', '', 'g') AS name, value
FROM t) j
WHERE name IN('A_123', 'F_777');
split_part(name,'_',1) + '_' + split_part(name,'_',3) as name
this is the break down of the query: A + _ + 123 = A_123

Count spaces (ASCII code 32) at the beginning and end of string

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