Get every string before character in SQL Server - sql

I got two record in table which is as below -:
1.123-21
2.123-21-30
How to query for all string before certain place of character . Below shown expected output
1. 123-21 -> 123
2. 123-21-30 ->123-21
How can I solve it?

DECLARE #T TABLE (Vals VARCHAR(100))
INSERT INTO #T(Vals) VALUES ('123-21') , ('123-21-30')
SELECT LEFT(Vals, LEN(Vals) - CHARINDEX('-', REVERSE(Vals)) )
FROM #T

Related

SQL - Replace a particular part of column string value (between second and third slash)

In my SQLServer DB, I have a table called Documents with the following columns:
ID - INT
DocLocation - NTEXT
DocLocation has values in following format:
'\\fileShare1234\storage\ab\xyz.ext'
Now it seems these documents are stored in multiple file share paths.
We're planning to migrate all documents in one single file share path called say 'newFileShare' while maintaining the internal folder structure.
So basically '\\fileShare1234\storage\ab\xyz.ext' should be updated to '\\newFileShare\storage\ab\xyz.ext'
Two questions:
How do I query my DocLocation to extract DocLocations with unique file share values? Like 'fileShare1234' and 'fileShare6789' and so on..
In a single Update query how do I update my DocLocation values to newFileShare ('\\fileShare1234\storage\ab\xyz.ext' to '\\newFileShare\storage\ab\xyz.ext')
I think the trick would be extract and replace text between second and third slashes.
I've still not figured out how to achieve my first objective. I require those unique file shares for some other tasks.
As for the second objective, I've tried using replace between it will require multiple update statements. Like I've done as below:
update Documents set DocLocation = REPLACE(Cast(DocLocation as NVarchar(Max)), '\\fileShare1234\', '\\newFileShare\')
The first step is fairly easy. If all your paths begin with \\, then you can find all the DISTINCT servers using SUBSTRING. I will make a simple script with a table variable to replicate some data. The value of 3 is in the query and it is the length of \\ plus 1 since SQL Server counts from 1.
DECLARE #Documents AS TABLE(
ID INT NOT NULL,
DocLocation NTEXT NOT NULL
);
INSERT INTO #Documents(ID, DocLocation)
VALUES (1,'\\fileShare56789\storage\ab\xyz.ext'),
(2,'\\fileShare1234\storage\ab\cd\xyz.ext'),
(3,'\\share4567890\w\x\y\z\file.ext');
SELECT DISTINCT SUBSTRING(DocLocation, 3, CHARINDEX('\', DocLocation, 3) - 3) AS [Server]
FROM #Documents;
The results from this are:
Server
fileShare1234
fileShare56789
share4567890
For the second part, we can just concatenate the new server name with the path that appears after the first \.
UPDATE #Documents
SET DocLocation = CONCAT('\\newfileshare\',
SUBSTRING(DocLocation, 3, LEN(CAST(DocLocation AS nvarchar(max))) - 2));
SELECT * FROM #Documents;
For some reason I cannot create a table with the results here, but the values I see are this:
\\newfileshare\fileShare56789\storage\ab\xyz.ext
\\newfileshare\fileShare1234\storage\ab\cd\xyz.ext
\\newfileshare\share4567890\w\x\y\z\file.ext
Please try the following solution based on XML and XQuery.
Their data model is based on ordered sequences. Exactly what we need while processing fully qualified file path: [position() ge 4]
When you are comfortable, just run the UPDATE statement by updating the DocLocation column with the calculated result.
It is better to use NVARCHAR(MAX) instead of NText data type.
SQL
-- DDL and sample data population, start
DECLARE #tbl AS TABLE(ID INT IDENTITY PRIMARY KEY, DocLocation NVARCHAR(MAX));
INSERT INTO #tbl(DocLocation) VALUES
('\\fileShare56789\storage\ab\xyz.ext'),
('\\fileShare1234\storage\ab\cd\xyz.ext'),
('\\share4567890\w\x\y\z\file.ext');
-- DDL and sample data population, end
DECLARE #separator CHAR(1) = '\'
, #newFileShare NVARCHAR(100) = 'newFileShare';
SELECT ID, DocLocation
, result = '\\' + #newFileShare + #separator +
REPLACE(c.query('data(/root/r[position() ge 4]/text())').value('text()[1]', 'NVARCHAR(MAX)'), SPACE(1), #separator)
FROM #tbl
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(DocLocation, #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t(c);
Output
+----+---------------------------------------+--------------------------------------+
| ID | DocLocation | result |
+----+---------------------------------------+--------------------------------------+
| 1 | \\fileShare56789\storage\ab\xyz.ext | \\newFileShare\storage\ab\xyz.ext |
| 2 | \\fileShare1234\storage\ab\cd\xyz.ext | \\newFileShare\storage\ab\cd\xyz.ext |
| 3 | \\share4567890\w\x\y\z\file.ext | \\newFileShare\w\x\y\z\file.ext |
+----+---------------------------------------+--------------------------------------+
to get the unique list of shared folder path , you can use this query:
SELECT distinct SUBSTRING(DocLocation,0,CHARINDEX('\',DocLocation,3))
from Documents
and your update command should work and yes you can merge copuple of replace update but better to run them seperately
update Documents
set DocLocation = REPLACE(DocLocation,'\\fileShare1234','\\newFileShare')
but I recommend you always record relative address instead of full path like: \storage\ab\xyz.ext'

SQL Server Conditional Count Issue

I am trying to do something apparently simple in sql server but not been able to achieve the desired result yet (I am of course not a sql expert).
My source table:
And I am trying to get the output like below:
I have tried to give the field names meaningful so that the problem becomes self explanatory. I haven't been able to generate the 3rd column of the desired output yet.
Please can someone help??
Thanks & Regards.
You can try below -
select date,count(*) as idcount,count(case when status='Pass' then 1 end) as idpassed
from tablname
group by date
Try this:
Declare #t table( dates varchar(50),id int,status varchar(50))
insert into #t values ('2019/8',1,'Pass')
insert into #t values ('2019/9',1,'fail')
insert into #t values ('2019/9',2,'fail')
insert into #t values ('2019/8',3,'fail')
select dates,count(id) idcount,sum(case when status='pass' then 1 else 0 end) as pascount from #t
group by dates

String End with Character

I have a table in SQL Server 2012 with 2 million records. I am trying to find all those records which is not ending with character as in example.
Code:
DECLARE #TABLE TABLE
(
ID INT IDENTITY(1,1),
MYVAL VARCHAR(50)
)
INSERT #TABLE
VALUES ('4639016:42:'),
('3279022:42:'),
('4605907:42:XY'),
('4190078:42:ZS')
Code I used:
SELECT *
FROM #TABLE
WHERE MYVAL NOT LIKE '%:[A-Z]'
but it's not returning the correct result.
I also want to pull all those records only which are ending with ':'
Can someone please share your expertise?
Thanks
You could use RIGHT to get last character:
SELECT *
FROM #TABLE
WHERE RIGHT(MYVAL,1) != ':';
-- RIGHT(MYVAL,1) LIKE '[A-Z]'

A query that will search for the highest numeric value in a table where the column has an alphanumeric sequence

I have a column (XID) that contains a varchar(20) sequence in the following format: xxxzzzzzz Where X is any letter or a dash and zzzzz is a number.
I want to write a query that will strip the xxx and evaluate and return which is the highest number in the table column.
For example:
aaa1234
bac8123
g-2391
After, I would get the result of 8123
Thanks!
A bit painful in SQL Server, but possible. Here is one method that assumes that only digits appear after the first digit (which you actually specify as being the case):
select max(cast(stuff(col, 1, patindex('%[0-9]%', col) - 1, '') as float))
from t;
Note: if the last four characters are always the number you are looking for, this is probably easier to do with right():
select max(right(col, 4))
Using Numbers table
declare #string varchar(max)
set #string='abc1234'
select top 1 substring(#string,n,len(#string))
from
numbers
where n<=len(#string)
and isnumeric(substring(#string,n,1))=1
order by n
Output:1234
Using PATINDEX you can achieve it, like this -
DECLARE #test table
(
id INT,
player varchar(100)
)
INSERT #test
VALUES (1,'aaa1234'),
(2,'bac8123'),
(3,'g-2391')
SELECT
MAX(CONVERT(INT, LTRIM(SUBSTRING(player, PATINDEX('%[0-9]%', player), LEN(player)))))
FROM #test
Try:
Select MAX(RIGHT(XID,17))
from table
You can also use this method
CREATE TABLE #Tmp
(
XID VARCHAR(20)
)
INSERT INTO #Tmp(XID)
VALUES ('aaa1234'), ('bac8123'), ('g-2391')
SELECT MAX(RIGHT(XID, LEN(XID) - 3))
FROM #Tmp

Selecting substring x.x.x.x from a string field

Using Sql Server, I have the following data in a column in a table:
NFPA 1: 4.5.8.1, SFM 69A-21
NFPA 101:7.2.1.8.
NFPA 1 14.13.1.1*
NFPA 101 7.2.1.15.8
NFPA 1 13.6.9.3.1.1.1
NFPA 101:7.1.3.2.1 (6)
?NFPA ?1 14?.?6?.?3?*
I would like to select just records with x.x.x.x.(.x)(.x)etc that have a period sequence. I would also like to show the x.x.x.x.(.x)(.x)etc data in the output and not the data before or after the periods. For example from the above data, the following would display as the output of the sql select:
4.5.8.1
7.2.1.8
14.13.1.1
7.2.1.15.8
13.6.9.3.1.1.1
7.1.3.2.1
[THIS RECORD WOULD NOT BE SELECTED BECAUSE THE DATA IS NOT IN THE FORMAT: ?NFPA ?1 14?.?6?.?3?*]
Any help would be appreciated thanks before hand.
UPDATE: Please check the sql fiddle:
SQL FIDDLE HERE
**UPDATE #2 **: No answers so far, hope someone can help.
Considering that you want a variable number of elements that are a variable number of digits, the best way that I am aware of is to use Regular Expressions. Regular Expressions are not natively available in T-SQL so you need to add SQLCLR functions to so that part. After that, it is just a simple Regular Expression to grab data matching that pattern.
DECLARE #TestData TABLE (String NVARCHAR(100));
INSERT INTO #TestData (String) VALUES ('NFPA 1: 4.5.8.1, SFM 69A-21');
INSERT INTO #TestData (String) VALUES ('NFPA 101:7.2.1.8.');
INSERT INTO #TestData (String) VALUES ('NFPA 1 14.13.1.1*');
INSERT INTO #TestData (String) VALUES ('NFPA 101 7.2.1.15.8');
INSERT INTO #TestData (String) VALUES ('NFPA 1 13.6.9.3.1.1.1');
INSERT INTO #TestData (String) VALUES ('NFPA 101:7.1.3.2.1 (6)');
INSERT INTO #TestData (String) VALUES ('?NFPA ?1 14?.?6?.?3?*');
;WITH cte AS
(
SELECT SQL#.RegEx_MatchSimple(tmp.String, N'\d+(?:\.\d+)+', 1, NULL)
AS [Filtered]
FROM #TestData tmp
)
SELECT *
FROM cte
WHERE cte.Filtered <> '';
Output:
4.5.8.1
7.2.1.8
14.13.1.1
7.2.1.15.8
13.6.9.3.1.1.1
7.1.3.2.1
For the example I used the SQL# library (which I am the author of). The RegEx function used here, and others, are available in the Free version.