Charindex function that can search for multiple values values in a string - sql-server

I'm trying to clean this data set and the home#dest column is giving me some issues. I would like to turn the one column into 4. they would be Homecity, Homestate/country, Destcity, and Deststate/country. I've tried many different combinations of functions, butI'm trying to clean this data set and the home#dest column is giving me some issues. I would like to turn the one column into 4. they would be Homecity, Homestate/country, Destcity, and Deststate/country. I've tried many different combinations of functions, but I'm new to data analytics and I'm not sure what to do. The problem is the column's data has no standard format. Some columns have all the info I'd need for my new columns will some just have one, or none. I don't mind having no info if it's not available. Charindex doesn't seem to work because not every row has a comma and also trying to find the first delimiter could wither be a comma, dash, or slash Any assistiance would be appreciated. I'm using MSSQL.
I tried this to get me started.
Select
SUBSTRING(home#dest, 1, CHARINDEX(',' , home#dest)) AS Homecity,
PARSENAME(REPLACE ( home#dest , '/' , '.' ), 2) AS HomeCountry,
PARSENAME(REPLACE ( home#dest , '/' , '.' ), 1) AS Destination
From PortfolioProjects..titanic
Where home#dest is not NULL

Related

ABAP SQL preserve OR pad trailing spaces

I am trying to find a way to preserve a space within SQL concatenation.
For context: A table I am selecting from a table with a single concatenated key column. Concatenated keys respect spaces.
Example: BUKRS(4) = 'XYZ ', WERKS(4) = 'ABCD' is represented as key XYZ ABCD.
I am trying to form the same value in SQL, but it seems like ABAP SQL auto-trims all trailing spaces.
Select concat( rpad( tvko~bukrs, 4, (' ') ), t001w~werks ) as key, datab, datbi
from t001w
inner join tvko on tvko~vkorg = t001w~vkorg
left join ztab on ztab~key = concat( rpad( tvko~bukrs, 4, (' ') ), t001w~werks ) "This is why I need the concat
rpad( tvko~bukrs, 4, ' ' ) in this example returns XYZ, instead of XYZ , which leads to concatenated value being XYZABCD, rather than XYZ ABCD.
lpad seems to work just fine (returning XYZ), which leads me to believe I'm doing something wrong.
SQL functions don't accept string literals or variables (which preserve spaces in the same circumstances in ABAP) as they are non-elementary types.
Is there any way to pad/preserve the spaces in ABAP SQL (without pulling data and doing it in application server)?
Update: I solved my problem by splitting key selection from data selection and building the key in ABAP AS. It's a workaround that avoids the problem instead of solving it, so I'll keep the question open in case an actual solution appears.
EDIT: this post doesn't answer the question of inserting a number of characters which vary based on values in some table columns e.g. LENGTH function is forbidden in RPAD( tvko~bukrs, LENGTH( ... ), (' ') ). It's only starting from ABAP 7.55 that you can indicate SQL expressions instead of fixed numbers. You can't do it in ABAP before that. Possible workarounds are to mix ABAP SQL and ABAP (e.g. LIKE 'part1%part2' and then filtering out using ABAP) or to use native SQL directly (ADBC, AMDP, etc.)
Concerning how the trailing spaces are managed in OpenSQL/ABAP SQL, they seem to be ignored, the same way as they are ignored with ABAP fixed-length character variables.
Demonstration: I simplified your example to extract the line Walldorf plant:
These ones don't work (no line returned):
SELECT * FROM t001w
WHERE concat( 'Walldorf ' , 'plant' ) = t001w~name1
INTO TABLE #DATA(itab_1).
SELECT * FROM t001w
WHERE concat( rpad( 'Walldorf', 1, ' ' ), 'plant' ) = t001w~name1
INTO TABLE #DATA(itab_2).
These 2 ones work, one with leading space(s), one using concat_with_space:
SELECT * FROM t001w
WHERE concat( 'Walldorf', ' plant' ) = t001w~name1
INTO TABLE #DATA(itab_3).
SELECT * FROM t001w
WHERE concat_with_space( 'Walldorf', 'plant', 1 ) = t001w~name1
INTO TABLE #DATA(itab_4).
General information: ABAP documentation - SQL string functions
EDIT: working example added, using leading space(s).

Oracle ROWTOCOL Function oddities

I have a requirement to pull data in a specific format and I'm struggling slightly with the ROWTOCOL function and was hoping a fresh pair of eyes might be able to help.
I'm using 10g Oracle DB (10.2) so LISTAGG which appears to do what I need to achieve is not an option.
I need to aggregate a number of usernames into a string delimited with a '$' but I also need to concatenate another column to to build up email addresses.
select
rowtocol('select username_id from username where user_id = '||s.user_id|| 'order by USERNAME_ID asc','#'||d.domain_name||'$')
from username s, domain d
where s.user_id = d.user_id
(I've simplified the query specific to just this function as the actual query is quite large and all works except for this particular function.)
in the DOMAIN Table I have a number of domains such as 'hotmail.com','gmail.com' etc
I need to concatenate the username, an '#' symbol followed by the domain and all delimited with a '$'
such as ......
joe.bloggs#gmail.com$joeblogs#gmail.com$joe_bloggs#gmail.com
I've battled with this and I've got close but in reverse?!.....
gmail.com$joe.bloggs#gmail.com$joeblogs#gmail.com$joe_bloggs
I've also noticed that if I play around with the delimiter (,'#'||d.domain_name||'$') it has a tendency to drop off the first character as can be seen above the preceding '#' has been dropped from the first email address.
Can anyone offer any suggestions as to how to get this working?
Many Thanks in advance!
Assuming you're using the rowtocol function from OTN, and have tables something like:
create table username (user_id number, username_id varchar2(20));
create table domain (user_id number, domain_name varchar2(20));
insert into username values (1, 'joe.bloggs');
insert into username values (1, 'joebloggs');
insert into username values (1, 'joe_bloggs');
insert into domain values (1, 'gmail.com');
Then your original query gets three rows back:
gmail.com$joe.bloggs
gmail.com$joe_bloggs#gmail.com$joebloggs
gmail.com$joe_bloggs#gmail.com$joebloggs
You're passing the data from each of your user IDs to a separate call to rowtocol, which isn't really what you want. You can get the result I think you're after by reversing it; pass the main query that joins the two tables as the select argument to the function, and have that passed query do the username/domain concatenation - that is a separate step to the string aggregation:
select
rowtocol('select s.username_id || ''#'' || d.domain_name from username s join domain d on d.user_id = s.user_id', '$')
from dual;
which gets a single result:
joe.bloggs#gmail.com$joe_bloggs#gmail.com$joebloggs#gmail.com
Whether that fits into your larger query, which you haven't shown, is a separate question. You might need to correlate it with the rest of your query.
There are other ways to string aggregation in Oracle, but this function is one way, and you already have it installed. I'd look at alternatives though, such as ThomasG's answer, which make it a bit clearer what's going on I think.
As Alex told you in comments, this ROWTOCOL isn't a standard function so if you don't show its code, there's nothing we can do to fix it.
However you can accomplish what you want in Oracle 10 using the XMLAGG built-in function.
try this :
SELECT
rtrim (xmlagg (xmlelement (e, s.user_id || '#' || d.domain_name || '$')).extract ('//text()'), '$') whatever
FROM username s
INNER JOIN domain d ON s.user_id = d.user_id

Splitting contents of one sql column into 3 columns based on certain characters that always happen in the value

I'm trying to form a SQL query, using SQL Server 2014 without creating a function. I do not have permissions on the database to create functions so I have to do it with a query only.
I have a column named Test with the example value of:
Accounting -> Add Missing functionality in Payable -> Saving a blank Missing row
I want my query to return the information (of varying length) between the two arrows (->). I have tried the right, left, substring, charindex and patindex functions and various combinations of each.
Basically the query needs to be SUBSTRING(Test, CHARINDEX(' -> ', TEST) +3, <some length here>)
The length is the part I'm having a hard time figuring out. I need the full length minus the first part before and including the first -> which evaluates to:
Add Missing functionality in Payable -> Saving a blank Missing row
From that result, I need to remove everything after and including the ->, which would then leave me with:
Add Missing functionality in Payable
At the end of the day, I want to split this one column up into 3 like so:
Domain | Feature | Test
------------------------------------------------------------------------------
Accounting | Add Missing functionality in Payable | Saving a blank Missing row
Can anyone show me how to do this query, without having to write a function? Any suggestions would be greatly appreciated as I have been working on this one portion of the query for the better part of 4 hours now. Thank you in advance for your help. Have a great day!!
I tried the following query and it is woking fine for me:
DECLARE #X as varchar(1000)
SET #X = 'Accounting -> Add Missing functionality in Payable -> Saving a blank Missing row'
SELECT SUBSTRING(#X,1,CHARINDEX('->',#X) - 1) AS Domain,
SUBSTRING(#X,CHARINDEX('->',#X) + 2,LEN(SUBSTRING(#X,CHARINDEX('->',#X) + 2,LEN(#X))) - LEN(SUBSTRING(#X,LEN(#X) - CHARINDEX('>-',REVERSE(#X)) ,LEN(#X)))) AS Feature,
SUBSTRING(#X,LEN(#X) - CHARINDEX('>-',REVERSE(#X)) + 2 ,LEN(#X)) AS Test
You have to use this query:
SELECT SUBSTRING([Test],1,CHARINDEX('->',[Test]) - 1) AS Domain,
SUBSTRING([Test],CHARINDEX('->',[Test]) + 2,LEN(SUBSTRING([Test],CHARINDEX('->',[Test]) + 2,LEN([Test]))) - LEN(SUBSTRING([Test],LEN([Test]) - CHARINDEX('>-',REVERSE([Test])) ,LEN([Test])))) AS Feature,
SUBSTRING([Test],LEN([Test]) - CHARINDEX('>-',REVERSE([Test])) + 2 ,LEN([Test])) AS Test
FROM MyTable --Replace MyTable with your table name

Query for pattern separated by new lines

I have a table (defect ) where a column stores a text. Each line in this text represents a version. (this is clearquest database running microsoft SQL, accessed via JDBC)
For example, following data represents three versions a fix is made.
defect version_fixed
1 2015.1.1
2 2015.1.1\n2015.1.13
3 2015.1.12\n2015.1.1
4 2015.1.12\n2015.1.1\n2015.1.13
5 2015.1.13\n2015.1.10
5 2015.1.100
As you see the version is not stored in an order. It can appear anywhere.
I am interested in all rows with fix version fixed containing "2015.1.1". But my query either gets more rows or skips some
version_fixed like '%2016.1.1%' (gets row 5 as it matches the pattern)
version_fixed like '%2016.1.1\n'(does not get any thing.)
I am looking for query to get exact list for 2015.1.1
defect version_fixed
1 2015.1.1
2 2015.1.1\n2015.1.13
3 2015.1.12\n2015.1.1
4 2015.1.12\n2015.1.1\n2015.1.13
How can I query where text matches with "exact string, delimited by new line or end of text". What is the correct way to escape new line?
Side note: Current solution is to get all records(including unwanted one and then filter out incorrect results)
You could try this. It relies on Sql Server adding the newline to the string when you break the line.
create table defect( version_fixed varchar(max) )
insert into defect( version_fixed )
values ( '2015.1.1' )
, ( '2015.1.1
2015.1.13' )
, ( '2015.1.12
2015.1.1' )
, ( '2015.1.12
2015.1.1
2015.1.13')
, ( '2015.1.13
2015.1.10' )
, ( '2015.1.100' )
-- break to a new line and Sql Server will include the newline character in the string
select * from defect where version_fixed like '%2015.1.1
%' or version_fixed like '%2015.1.1'
You can as the below:
WHERE '\' + version_fixed + '\' LIKE '%2015.1.1\%'
This solution depands on your sample data.

SQL mobile number validation

I have my sql database where i would like to filter out all the valid mobile numbers.
I currently use as follows;
WHERE pn.PhoneNumber LIKE '+[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
OR pn.PhoneNumber LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
OR pn.PhoneNumber LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
OR pn.PhoneNumber LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]'
However I still receive numbers such as 0000000, 0 ,0000 etc.
Some of the numbers aren't Irish mobiles either as they don't begin with 08.
To fix there if I wanted the beginning of the number to begin with an 087 would I just input [0][8][7] instead of the [0-9]?
try testing this !
this'll give numbers starting with 087 and mobile(length)=10
select * from table where mobile_number like '087%' and LEN(mobile_number)=10
DEMO
I would create a table containing all the prefixes that I was interested in and then use that to do the validation.
Something like ....
Create table Allowed ( Prefix VARCHAR(10) )
insert into allowed values ( '071' );
insert into allowed values ( '072' );
insert into allowed values ( '+44' );
select count(prefix) as OK
from allowed
where REPLACE( pn.phonenumber, ' ', '') like prefix || '%'
You can still do the numeric validation separately, or combine the regexp part into the suffix added above.
I know this is out of date but just developed code for a UK Mobile Number that someone might find useful. It checks with or without a space, hyphen etc after the first 5 numbers and returns a blank if the number isn't valid - I need to upload records to a third party who reject records with invalid mobile numbers but accept blanks.
Mobile = CASE WHEN MobileTel LIKE '07[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%' THEN left(MobileTel,11) WHEN MobileTel LIKE '07[0-9][0-9][0-9][^0-9][0-9][0-9][0-9][0-9][0-9][0-9]%' THEN (LEFT(MobileTel,5)+substring(MobileTel,7,6)) ELSE '' END

Resources