Left selection up until a certain character SQL - sql-server

My select statement returns two columns Column A is based on Column B BUT I removed the initial 17 characters. What I would then like to do is take all the characters in Column A up until it hits a \ (backslash). Can anyone help me achieve this please - current code below
SELECT distinct substring(Path,17,18) AS Detail, Path
FROM [DB].[dbo].[Projects]
Where [Path] like '\DATA%'
AND [Deleted] = '0'
Just to re-iterate as my example wasn't very clear in the comment below. I am trying to extract from the following result
\DATA\More Data\Even More Data\Data 1
To show
Even More Data
So I have removed the proceeding 17 characters until the next \

For ColumnA, if you only want to take out the first 17 characters, you should use
RIGHT(Path, LEN(Path) - 17)
As your current solution will not work correctly if Path is longer than 35 characters.
As for returning the string up to the first backslash, use:
SELECT LEFT(Detail, CHARINDEX('\', Detail)) FirstFolder, Detail, Path
FROM
(
SELECT distinct RIGHT(Path, LEN(Path) - 17) AS Detail, Path
FROM [DB].[dbo].[Projects]
Where [Path] like '\DATA%'
AND [Deleted] = '0'
) a
Or all in one:
SELECT DISTINCT SUBSTRING(Path, 18, CHARINDEX('\', Path, 18) - 18)
FROM [DB].[dbo].[Projects]
WHERE [Path] like '\DATA%'
AND [Deleted] = '0'
This says:
extract a substring from path
start at Character 18
The length of the string will be calculated by finding the position of the first backslash in path starting at Character 18, minus 18 (because we started the search on the 18th character, and we want it relative to the start of our search not the start of the original string)
Update:
As #etsa correctly points out, if you cannot guarantee that Path is at least 18 characters long and contains a backslash after character 18 for every row, you should use the following to return only the rows that do meet this criteria:
SELECT DISTINCT SUBSTRING(Path, 18, CHARINDEX('\', Path, 18) - 18)
FROM [DB].[dbo].[Projects]
WHERE [Path] like '\DATA%'
AND [Deleted] = '0'
AND CHARINDEX('\', Path, 18) > 0

Regardless of the length of your data, this gets the parent folder which seems to be what you want.
DECLARE #table TABLE ([Path] VARCHAR(256))
INSERT INTO #table VALUES
('\DATA\More Data\Even More Data\Data 1'),
('\\server\top folder\middle folder\bottom folder\file 1'),
('x\x\x\x\x\x\x\x\x\x\x\x\x\x\x\x\x\x\x\this is what we want\x')
SELECT
[Path]
,CHARINDEX('\',REVERSE([Path])) as [Reverse Position of last \]
,CHARINDEX('\',REVERSE([Path]),CHARINDEX('\',REVERSE([Path])) + 1) as [Reverse Postion of next to last \]
,REVERSE(
SUBSTRING(
REVERSE([Path]),
CHARINDEX('\',REVERSE([Path]))+1,
CHARINDEX('\',REVERSE([Path]),CHARINDEX('\',reverse([Path]))+1)-CHARINDEX('\',REVERSE([Path])) - 1)) as [Your Desired Results]
FROM
#table
RETURNS
+--------------------------------------------------------------+----------------------------+-----------------------------------+----------------------+
| Path | Reverse Position of last \ | Reverse Postion of next to last \ | Your Desired Results |
+--------------------------------------------------------------+----------------------------+-----------------------------------+----------------------+
| \DATA\More Data\Even More Data\Data 1 | 7 | 22 | Even More Data |
| \\server\top folder\middle folder\bottom folder\file 1 | 7 | 21 | bottom folder |
| x\x\x\x\x\x\x\x\x\x\x\x\x\x\x\x\x\x\x\this is what we want\x | 2 | 23 | this is what we want |
+--------------------------------------------------------------+----------------------------+-----------------------------------+----------------------+

Related

Defeat these dashed dashes in SQL server

I have a table that contains the names of various recording artists. One of them has a dash in their name. If I run the following:
Select artist
, substring(artist,8,1) as substring_artist
, ascii(substring(artist,8,1)) as ascii_table
, ascii('-') as ascii_dash_key /*The dash key next to zero */
, len(artist) as len_artist
From [dbo].[mytable] where artist like 'Sleater%'
Then the following is returned. This seems to indicate that a dash (ascii 45) is being stored in the artist column
However, if I change the where clause to:
From [dbo].[mytable] where artist like 'Sleater' + char(45) + '%'
I get no results returned. If I copy and paste the output from the artist column into a hex editor, I can see that the dash is actually stored as E2 80 90, the Unicode byte sequence for the multi-byte hyphen character.
So, I'd like to find and replace such occurrences with a standard ascii hyphen, but I'm am at a loss as to what criteria to use to find these E2 80 90 hyphens?
Your char is the hyphen, information on it here :
https://www.charbase.com/2010-unicode-hyphen
You can see that the UTF16 code is 2010 so in T-SQL you can build it with
SELECT NCHAR(2010)
From there you can use any SQL command with that car, for example in a select like :
Select artist
From [dbo].[mytable] where artist like N'Sleater' + NCHAR(2010) + '%'
or as you want in a
REPLACE( artist, NCHAR(2010), '-' )
with a "real" dash
EDIT:
If the collation of your DB give you some trouble with the NCHAR(2010) you can also try to use the car N'‐' that you'll copy/paste from the charbase link I gave you so :
REPLACE( artist , N'‐' , '-' )
that you can even take from the string here (made with the special car) so all made for you :
update mytable set artist=REPLACE( artist, N'‐' , '-' )
I don't know your table definition and COLLATION but I'm almost sure that you are mixing NCHAR and CHAR types and convert unicode, multibyte characters to sinle byte representations. Take a look at this demo:
WITH Demo AS
(
SELECT N'ABC'+NCHAR(0x2010)+N'DEF' T
)
SELECT
T,
CASE WHEN T LIKE 'ABC'+CHAR(45)+'%' THEN 1 ELSE 0 END [Char],
CASE WHEN T LIKE 'ABC-%' THEN 1 ELSE 0 END [Hyphen],
CASE WHEN T LIKE N'ABC‐%' THEN 1 ELSE 0 END [Unicode-Hyphen],--unicode hyphen us used here
CASE WHEN T LIKE N'ABC'+NCHAR(45)+N'%' THEN 1 ELSE 0 END [NChar],
CASE WHEN CAST(T AS varchar(MAX)) LIKE 'ABC-%' THEN 1 ELSE 0 END [ConvertedToAscii],
ASCII(NCHAR(0x2010)) ConvertedToAscii,
CAST(SUBSTRING(T, 4, 1) AS varbinary) VarbinaryRepresentation
FROM Demo
My results:
T Char Hyphen Unicode-Hyphen NChar ConvertedToAscii ConvertedToAscii VarbinaryRepresentation
------- ----------- ----------- -------------- ----------- ---------------- ---------------- --------------------------------------------------------------
ABC‐DEF 0 0 1 0 1 45 0x1020
UTF-8 (3 bytes) representation is the same as 2010 in unicode.

SQL Server - How to get last numeric value in the given string

I am trying to get last numeric part in the given string.
For Example, below are the given strings and the result should be last numeric part only
SB124197 --> 124197
287276ACBX92 --> 92
R009321743-16 --> 16
How to achieve this functionality. Please help.
Try this:
select right(#str, patindex('%[^0-9]%',reverse(#str)) - 1)
Explanation:
Using PATINDEX with '%[^0-9]%' as a search pattern you get the starting position of the first occurrence of a character that is not a number.
Using REVERSE you get the position of the first non numeric character starting from the back of the string.
Edit:
To handle the case of strings not containing non numeric characters you can use:
select case
when patindex(#str, '%[^0-9]%') = 0 then #str
else right(#str, patindex('%[^0-9]%',reverse(#str)) - 1)
end
If your data always contains at least one non-numeric character then you can use the first query, otherwise use the second one.
Actual query:
So, if your table is something like this:
mycol
--------------
SB124197
287276ACBX92
R009321743-16
123456
then you can use the following query (works in SQL Server 2012+):
select iif(x.i = 0, mycol, right(mycol, x.i - 1))
from mytable
cross apply (select patindex('%[^0-9]%', reverse(mycol) )) as x(i)
Output:
mynum
------
124197
92
16
123456
Demo here
Here is one way using Patindex
SELECT RIGHT(strg, COALESCE(NULLIF(Patindex('%[^0-9]%', Reverse(strg)), 0) - 1, Len(strg)))
FROM (VALUES ('SB124197'),
('287276ACBX92'),
('R009321743-16')) tc (strg)
After reversing the string, we are finding the position of first non numeric character and extracting the data from that position till the end..
Result :
-----
124197
92
16

select last n lines of a text field in postgres on the bases of a split character

I have a text field in PostgreSQL in which I have stored content of a text file.
Query:
SELECT m_Field
FROM m_table
WHERE id = 1;
When I run query the response is:
'The basic steps are shown here and rely heavily on using snort as an IPS.\n1. Utilize snort IPS to prevent downloads of initial infection vectors\n2. Utilize snort IPS to prevent downloads of Trojan executable\n3. Utilize snort IPS to alert on current infections\n4. Kill and remove malware from the initally infected machine\n5. Kill other instances of malware and remove from machines.\n6. Prevent further infection and ensure business success.'
Now I want to read only last n lines from this field on the basis of a split character which in this case is \n
Is it possible to do this using some SQL query, or do I have to read data from the column and then split it?
Thanks in advance
If you want to do this in Python, you can get get query result and and split it on \n and and get last n lines like this
q = exec_query('SELECT m_Field FROM m_table WHERE id = 1;') # suppose you are executing with some function exec_query
last_n_lines = q.split('\n')[-n]
If you want to do this on database end, you can this like this
q = exec_query(SELECT string_to_array(m_Field, '\n') FROM m_table WHERE id = 1;)
last_n_lines = q[-n]
Here string_to_array is a postgres function.
An approach by PostgreSQL alone:
select id, rn, sentence
from (
select
id
, reverse(sentence) sentence
, row_number() over(partition by id) rn
from m_table, unnest(string_to_array(reverse(m_field), 'n\')) sentence(token)
) t
where rn <= 3 --<< alter this number to suit
order by rn DESC
nb: Reversing the string is to enable selecting the last n lines
+----+----+---------------------------------------------------------------+
| id | rn | sentence |
+----+----+---------------------------------------------------------------+
| 1 | 3 | 4. Kill and remove malware from the initally infected machine |
| 1 | 2 | 5. Kill other instances of malware and remove from machines. |
| 1 | 1 | 6. Prevent further infection and ensure business success. |
+----+----+---------------------------------------------------------------+
see: http://rextester.com/GXMED5871

SQL Server - Split string on last occuring number

I have following column (with fictional data):
Location
---------------
15630London
45680Edinburg
138739South Wales
This column contains both Zipcodes and City names. I want to split those 2 into 2 seperate columns.
So in this case, my output would be:
Zip | City
-------|---------
15630 | London
45680 | Edinburg
138739 | South Wales
I tried the zipcode with
LEFT(location,LEN(location)-CHARINDEX('L',location))
But I couldn't find out how to set the CHARINDEX to work on all letters.
Any suggestions / other ideas?
Here is one way using PATINDEX and some string functions
SELECT LEFT(Location, Patindex('%[a-z]%', Location) - 1),
Substring(Location, Patindex('%[a-z]%', Location), Len(Location))
FROM (VALUES ('15630London'),
('45680Edinburg'),
('138739South Wales'))tc(Location)
Note : Above code considers always zip codes are numbers and characters start only with city name and city is present in all the rows (ie) strings are present in every row
Detect the first non-numeric character and pull of that many chars from the left, then read beyond that point to the end:
select
left(Location, patindex('%[^0-9]%', Location) - 1),
substring(Location, patindex('%[^0-9]%', Location), len(Location))
from t
declare #string varchar(200)='15630London'
select substring(#string,1,patindex('%[a-z,A-Z]%',#string)-1),
substring(#string,patindex('%[a-z,A-Z]%',#string),len(#string))

SQL Script patindex

I think i have some syntax error in my script but can't figure out where.
I want to select the Integer that falls between a pair of ( ) begining from the right of a cell? Reason being, there might be another pair of brackets containing characters
and what if some records are w/o close brackets for some reason..
e.g.
Period | ProgrammeName |
Jan | ABC (Children) (30) |
Feb | Helloworld (20T (20) |
result: 30 20
select
Period,
ProgrammeName,
substring(ProgrammeName,(len(ProgrammeName) - (patindex('%(%', Reverse(ProgrammeName)))+2),(len(ProgrammeName)-1))
from
Table
but it only displays
30)
20)
i have been manipulating it so that it doesn't extract ')', but can't get the expected results.
So, you need to grab whatever's between the final set of open and closing brackets at the end of a string, right?
First off, find the first opening bracket from the end of the string. I'd use CHARINDEX, as you're just looking for a single character; you don't need to use pattern matching.
SELECT LEN(ProgrammeName) + 1 - CHARINDEX('(', REVERSE(ProgrammeName)) FROM Table
Then, find the first closing bracket from the end of the string:
SELECT LEN(ProgrammeName) + 1 - CHARINDEX(')', REVERSE(ProgrammeName)) FROM Table
Then, put those together. To use SUBSTRING, you need the position of the first character, then the length of the string you want, so you need the first result (the position of the '('), and then the second result minus the first result, to get the length of the bracketed bit, as a starting point:
SELECT (LEN(ProgrammeName) + 1 - CHARINDEX(')', REVERSE(ProgrammeName))) - (LEN(ProgrammeName) + 1 - CHARINDEX('(', REVERSE(ProgrammeName))) FROM Table
You also need to do a bit of fiddling to extract the part between the brackets, leaving the brackets alone. That's explained in the comments in this final example, where the final expression should be doing the job you want:
SELECT
-- Position of first bracket
LEN(ProgrammeName) + 1 - CHARINDEX('(', REVERSE(ProgrammeName)),
-- Position of second bracket
LEN(ProgrammeName) + 1 - CHARINDEX(')', REVERSE(ProgrammeName)),
-- Position of second bracket minus position of first bracket gives length
(LEN(ProgrammeName) + 1 - CHARINDEX(')', REVERSE(ProgrammeName))) - (LEN(ProgrammeName) + 1 - CHARINDEX('(', REVERSE(ProgrammeName))),
-- If we want to extract the bit between the brackets, we need to start from the bracket position
-- plus one character, and knock one off the length, to avoid grabbing the closing bracket.
SUBSTRING(ProgrammeName, 1 + LEN(ProgrammeName) + 1 - CHARINDEX('(', REVERSE(ProgrammeName)), (LEN(ProgrammeName) + 1 - CHARINDEX(')', REVERSE(ProgrammeName))) - (LEN(ProgrammeName) + 1 - CHARINDEX('(', REVERSE(ProgrammeName))) - 1)
FROM
Table
I've broken my answer down so you can see how I approach problems like these -- do them one bit at a time, checking the results as you go along, and it's easier to get your head around.

Resources