I am trying to find the best way to extract specific values from a string which can contain nulls/duplicates for the values. The issue is I have to do this in a query and pull those values into a view for use down the line.
Example of the string:
ABCD: 123 EFG: 03 HIJ: NGAB XYZ: XYZ: 133
EFG: 03 HIJ: NGAB XYZ: 133
I am trying to extract the values for ABCD, EFG, HIJ, and XYZ.
For example, the first string should return:
123 (for value of ABCD)
03 (for value of EFG)
NGAB (for value of HIJ)
133 (for value of XYZ)
Second string should return:
NULL (for value of ABCD)
03 (for value of EFG)
NGAB (for value of HIJ)
133 (for value of XYZ)
The length of the values to return are always static (i.e. ABCD will always be ABCD and 123 will always be the length of the value to return - i.e 3 characters. Same applies for EFG and 03 - EFG will always be EFG and 03 will always be 2 characters and so on).
I am trying to use below to try and return my values:
SELECT substring(replace(replace(TEMPFIELD,' ',''),':',''), charindex('XYZ',replace(replace(TEMPFIELD,' ',''),':',''))+3,3) AS XYZ FROM MYTABLE
I change my query per field and adjust the length on the substring as needed. The issue is that when there are duplicates, I return the wrong values and when there are nulls, I return the wrong value.
For example, my query returns XYZ as the value of XYZ in the first string instead of 123. It also returns 03H as the value of ABCD in the second string instead of NULL. Is there a better function for me to use in this case to handle both scenarios of nulls/duplicates?
Updated query:
SELECT CASE WHEN TEMPFIELD LIKE '%XYZ%XYZ%'
THEN substring(stuff(replace(replace(TEMPFIELD ,' ',''),':',''),charindex('XYZ',replace(replace(TEMPFIELD ,' ',''),':','')),3,''), charindex('XYZ',stuff(replace(replace(TEMPFIELD ,' ',''),':',''),charindex('XYZ',replace(replace(TEMPFIELD ,' ',''),':','')),3,''))+3,3)
WHEN TEMPFIELD LIKE '%XYZ%'
THEN substring(replace(replace(TEMPFIELD ,' ',''),':',''), charindex('XYZ',replace(replace(TEMPFIELD ,' ',''),':',''))+3,3)
ELSE NULL
END AS XYZ
Ideally if you can you would want to sort out the string you are trying to pass as this could get very messy, but I can offer you this solution, based on the following assumptions:
Duplicated keys only occur twice as per your example
The values cannot contain the key
That when the keys are duplicated that the last one is the value you want.
CASE WHEN TEMPFIELD LIKE '%XYZ%XYZ%'
THEN SUBSTRING(TEMPFIELD, CHARINDEX('XYZ: ', TEMPFIELD, CHARINDEX('XYZ: ', TEMPFIELD) + 1) + 5, 3)
WHEN TEMPFIELD LIKE '%XYZ%'
THEN SUBSTRING(TEMPFIELD, CHARINDEX('XYZ: ', TEMPFIELD) + 5, 3)
ELSE NULL
END AS XYZ
Add in the replacements if you really need to but if you know the format is reliable enough you shouldn't need to do this as it will just add processing time.
To explain what this does a bit: the first case statement will deal with the duplicated values by getting the CHARINDEX of the second key, if that case criteria does not match then it will fall to the second case and do something similar to what you were already doing and finally if the string does not match either of those it simply gives you null.
Related
Related question so now I have a table Test with 3 columns id, value and term
TEST
id
value
Item
1
AB CD EF GH IJ KL
1 4 78 78 10 9
I will like a query to get the value in the Item column after the 4th space. In this case that will correspond to 'IJ' in the value column and in the "Item' column it will return '10'
This is what i tried
select
substring(item(REGEXP_COUNT( SPLIT( TRIM(REGEXP_REPLACE(value, '[^[:digit:]]', ' ')), 'IJ')[0] , ' ')
from Test
Use split_part()
select split_part('AB CD EF GH IJ KL', ' ',5);
This function split the string on the chosen character and allows you to choose which one you'd like to return as a string. In this case, the 5th part.
I want to query for numbered street names that can occur anywhere within a text column, and filter out matches for numbered street names with more digits, i.e. 2nd but not 42nd, 182nd, etc. Is there any method more graceful or simplified than combination of:
WHERE col LIKE '2nd%' OR col LIKE '% 2nd%'
As long as the 2nd doesn't occur at the beginning of the string, you can just check that the character before it is not a digit using
col LIKE '%[^0-9]2nd%'
For example:
select col, case when col like '%[^0-9]2nd%' then 'second' else 'not' end as test
from (values ('12 2nd st'), ('45 42nd st'), ('128 22nd st')) test(col)
Output:
col test
12 2nd st second
45 42nd st not
128 22nd st not
Nick's answer is very good, but it doesn't handle the case when '2nd' appears at the beginning of a string. This is easily handled by pre-pending a character on the column being compared:
' ' + col LIKE '%[^0-9]2nd%'
So I'm attempting to display a single character based on its position in a string from one column. Since this is grid data, there is a simple math to it. The grid has 24 rows 'A-X', and 44 columns.
So lets say I want to see the value in D9. I already know the expected value should be a 'A1', so that means the character length is '2'. If I do the math: (A + B + C = 3 x 44, + 9). That two-character value for D9 starts at the 141st position of that string in Col2. I attempted to use SUBSTRING with no success
SELECT
Col1 , SUBSTRING('Col2',141,2)
FROM Table1
Query result displays data in Col1, but for Col2 its just blank. What am I missing?
Asked too soon. Figured out I had to remove the ' from the column name
SELECT
Col1 , SUBSTRING('Col2',141,2)
FROM Table1
Didn't work
SELECT
Col1 , SUBSTRING(Col2,141,2)
FROM Table1
Works
I'm on Teradata. I have an ID column that looks like this:
23
34
W7
007
021
90
GS8
I want to convert the numbers to numeric so the 007 should be 7 and 021 be 21. When a number is stored as a string, I usually do column * 1 to convert to numeric but in this case it gives me a bad character error since there are letters in there.
How would I do this in a select statement within a query?
Assuming that numeric values always start with a number, then something like this should work:
update t
set col = (case when substr(col, 1, 1) between '0' and '9'
then cast(cast(col as int) as varchar(255))
else col
end);
Or, you can forget the conversion and do:
update t
set col = trim(leading '0' from col);
Note: both of these assume that if the first character is a digit then the whole string comprises digits. The second assumes that the values are not all zeroes (or, more specifically, that returns the empty string).
Simply use TO_NUMBER(col) which returns NULL when the cast fails.
I have 2 fields in my SQL table. One has 5 digits (ex: 12345) and the 2nd field has 2 digits (ex: 99) and I need to know if there is a way to take the LAST digit from the first field and push it to the beginning of the 2nd field. So the first field would be 1234 and the 2nd field would be 599 ???
UPDATE YourTable
SET Column2 = RIGHT(Column1, 1) + COALESCE(Column2, ''),
Column1 = LEFT(Column1, LEN(Column1)-1)
WHERE COALESCE(LEN(Column1), 0) > 1;
Here is a "typical" way to do this.
update t
set col1 = left(col1, length(col1) - 1),
col2 = concat(right(col1, 1), col2);
The exact details depend on the database.
Notes:
This sort of assumes the values are stored as strings, although the logic will convert back and forth from numbers.
The left() and right() functions may differ by database, although most databases do support them.
concat() may be replaced by an appropriate operator, depending on the database ('||', '+', '&', come to mind).
length() is sometimes called len().
And if it's integer columns:
update tablename set
c1 = c1/10,
c2 = mod(c1,10)*dpower(10,ceiling(dlog10(c2)))+c2