SQL Server - Select integer that falls between brackets ( ) - sql

HI, how can i 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
i have this script,
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 get the expected
results.

Quick and dirty if you want to prep the data for normalization;
select substring(fld, patindex('%([0-9]%)', fld) + 1, len(fld) - case patindex('%([0-9]%)', fld) when 0 then 0 else patindex('%([0-9]%)', fld) + 1 end)

Your database needs normalisation.
Whatever that (30) and (20) represent should be in their own column.

Hopefully this is a migration task. You could try it with a RegEx:
Link
EDIT: or this blog post
http://justgeeks.blogspot.com/2008/08/adding-regular-expressions-regex-to-sql.html

Related

How to use the SQL REPLACE Function, so that it will replace some text between a certain range, rather than one specific value

I have a table called Product and I am trying to replace some of the values in the Product ID column pictured below:
ProductID
PIDLL0000074853
PIDLL000086752
PIDLL00000084276
I am familiar with the REPLACE function and have used this like so:
SELECT REPLACE(ProductID, 'LL00000', '/') AS 'Product Code'
FROM Product
Which returns:
Product Code
PID/74853
PIDLL000086752
PID/084276
There will always be there letter L in the ProductID twice LL. However, the zeros range between 4-6. The L and 0 should be replaced with a /.
If anyone could suggest the best way to achieve this, it would be greatly appreciate. I'm using Microsoft SQL Server, so standard SQL syntax would be ideal.
Please try the following solution.
All credit goes to #JeroenMostert
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, ProductID VARCHAR(50));
INSERT INTO #tbl (ProductID) VALUES
('PIDLL0000074853'),
('PIDLL000086752'),
('PIDLL00000084276'),
('PITLL0000084770');
-- DDL and sample data population, end
SELECT *
, CONCAT(LEFT(ProductID,3),'/', CONVERT(DECIMAL(38, 0), STUFF(ProductID, 1, 5, ''))) AS [After]
FROM #tbl;
Output
+----+------------------+-----------+
| ID | ProductID | After |
+----+------------------+-----------+
| 1 | PIDLL0000074853 | PID/74853 |
| 2 | PIDLL000086752 | PID/86752 |
| 3 | PIDLL00000084276 | PID/84276 |
| 4 | PITLL0000084770 | PIT/84770 |
+----+------------------+-----------+
This isn't particularly pretty in T-SQL, as it doesn't support regex or even pattern replacement. Therefore you method is to use things like CHARINDEX and PATINDEX to find the start and end positions and then replace (don't read REPLACE) that part of the text.
This uses CHARINDEX to find the 'LL', and then PATINDEX to find the first non '0' character after that position. As PATINDEX doesn't support a start position I have to use STUFF to remove the first characters.
Then, finally, we can use STUFF (again) to replace the length of characters with a single '/':
SELECT STUFF(V.ProductID,CI.I+2,ISNULL(PI.I,0),'/')
FROM (VALUES('PIDLL0000074853'),
('PIDLL000086752'),
('PIDLL00000084276'),
('PIDLL3246954384276'))V(ProductID)
CROSS APPLY(VALUES(NULLIF(CHARINDEX('LL',V.ProductID),0)))CI(I)
CROSS APPLY(VALUES(NULLIF(PATINDEX('%[^0]%',STUFF(V.ProductID,1,CI.I+2,'')),1)))PI(I);
If you are always starting with "PIDLL", you can just remove the "PIDLL", cast the rest as an INT to lose the leading 0's, then append the front of the string with "PID/". One line of code.
-- Sample Data
DECLARE #t TABLE (ProductID VARCHAR(40));
INSERT #t VALUES('PIDLL0000074853'),('PIDLL000086752'),('PIDLL00000084276');
-- Solution
SELECT t.ProductID, NewProdID = 'PID/'+LEFT(CAST(REPLACE(t.ProductID,'PIDLL','') AS INT),20)
FROM #t AS t;
Returns:
ProductID NewProdID
------------------ ----------------
PIDLL0000074853 PID/74853
PIDLL000086752 PID/86752
PIDLL00000084276 PID/84276

Add Trailing Zeroes After Decimal

I am working with sku numbers that have the following 9 character structure:
a. a 3 digit number,
b. a period,
c. a five digit number.
An example: 505.12345.
A considerable % of the sku's end in 0. Examples: 505.12340, 505.12300, 505.12000.
I had no trouble keeping the trailing zeroes in SQL Server by setting the datatype to varchar after the migration from S3 -> SQL Server. I used a new machine learning model in AWS Sagemaker that cut off the trailing zeroes prior to the migration to S3.
The example sku's above now look like: 505.1234, 505.123, 505.12
My question: what is the best way to add trailing zeroes to all sku's where LEN([sku]) < 9? I would prefer to keep the sku datatype as varchar.
If you have a string, you can right-pad it with 0s as follows:
left(sku + replicate('0', 9), 9)
Alternatively:
sku + replicate('0', 9 - len(sku))
Demo on DB Fiddle:
select sku,
left(sku + replicate('0', 9), 9) new_sku,
sku + replicate('0', 9 - len(sku)) new_sku2
from (values ('505.1234'), ('505.123'), ('505.12'), ('505.12345')) x(sku)
sku | new_sku | new_sku2
:-------- | :-------- | :--------
505.1234 | 505.12340 | 505.12340
505.123 | 505.12300 | 505.12300
505.12 | 505.12000 | 505.12000
505.12345 | 505.12345 | 505.12345
One simple way would be to CAST back to DECIMAL(9, 5) and then CAST again to CHAR(9)
Data
drop table if exists #tTable;
go
create table #tTable(
dec_num varchar(20) not null);
Insert into #tTable values
('505.1234'),
('505.123'),
('505.12');
Query
select cast(cast(dec_num as decimal(9,5)) as char(9)) char_9
from #tTable;
Output
char_9
505.12340
505.12300
505.12000

Split a column in two based based on variable lenght field

Hi: I have a table made with rows like this:
ID_CATEGORIA CATEGORIA_DRG
------------ ---------------------------------------------------------------
1 001-002-003-543 Craniotomia
2 004-531-532 Interventi midollo spinale
3 005-533-534 Interventi vasi extracranici
4 006 Decompressione tunnel carpale
I'd like to get something like this:
ID CATEGORIA DESCRIZIONE
------------ ------------------ --------------------------------------
1 001-002-003-543 Craniotomia
2 004-531-532 Interventi midollo spinale
3 005-533-534 Interventi vasi extracranici
4 006 Decompressione tunnel carpale
I don't need to alter the table, a 'formatted' query can be enough.
I Think SUBSTRING() is the right function for me, but I don't know how to mesaure the lenght of the first (numbers, dash-separated) field.
In Python I'll find that size with len("005-533-534 Interventi vasi extracranici".split(' ')[0])', but I don't have idea about how to write it in SQL
Something like this should do -
SELECT ID_CATEGORIA AS ID ,SUBSTRING(CATEGORIA_DRG,1,CHARINDEX(' ',CATEGORIA_DRG)) as CATEGORIA,SUBSTRING(CATEGORIA_DRG,CHARINDEX(' ',CATEGORIA_DRG),LEN(CATEGORIA_DRG)) AS DESCRIZIONE
FROM TABLENAME
Try this:
select id_categoria ID,
substring(categoria_drg, 1, idx) CATEGORIA,
substring(categoria_drg, idx + 1, 1000) DESCRIZIONE
from (
select id_categoria, categoria_drg, charindex(' ', categoria_drg) idx from my_table
) a
It uses charindex to detect when the code is finished, because it is followed by first space in the string, which the function finds :)

Unique 8 digit incremental number

I'm trying to generate a number which will ultimately be stored as string(varchar). e.g.
First - ABC00000001
Second- ABC00000002
.........................
I am able to generate character string as expected. Now the problem is,incremental number.
What i am trying to do is get the last number stored e.g. ABC00000009 and generate the next number that is ABC00000010. How to do the same?
If i extract integers from this than i will get 1 or 10,how to make it according to 8 digit format.
Any help would really be appreciated.
Of course if changing the table structure is not an option, you can try this:
DECLARE #lastValue VARCHAR(15) = 'ABC00000001'
SELECT CONCAT('ABC', RIGHT(100000000 + CAST(RIGHT(#lastValue, 8) AS INT) + 1, 8))
Result
-----------
ABC00000002
I would suggest that you create an identity column. This will increment (usually by 1, but not always). Then create a computed column:
alter table t add generated_number as
('ABC' + right(replicate('0', 8) + cast(idcol as varchar(255)), 8));
Almost the same approach Gordon Linoff has taken, I just prefer to use math where possible instead of string concatenation. My answer is different only because I add id value to 100000000 instead of using replicate.
CREATE TABLE dbo.test (
id int IDENTITY(1, 1) PRIMARY KEY
, some_value sysname UNIQUE
, super_column AS 'ABC' + RIGHT(100000000 + id, 8));
GO
INSERT INTO dbo.test (some_value)
VALUES ('some_value_1'), ('some_value_2');
SELECT *
FROM dbo.test AS T;
Result:
+----+--------------+--------------+
| id | some_value | super_column |
+----+--------------+--------------+
| 1 | some_value_1 | ABC00000001 |
| 2 | some_value_2 | ABC00000002 |
+----+--------------+--------------+

show value from text..if delimited by ; show only first value

I have table with values. It is ntext because of ; delimited. Values can be empty, 1 number and numbers delimited by semicolon (as shown)
+-----------+
| room |
+-----------+
| 64 |
+-----------+
| 60008 |
+-----------+
| |
+-----------+
| 127;50047 |
+-----------+
I have this code. Substring is looking for ; and show first value. It is working only where the values are delimited. So how can I change it, that it will show first value when ; and single value also. So from table bellow I will get 64,60008, ,127.
SELECT
T0.U_Scid as 'id',
T3.U_Boarding as 'start',
T3.U_Boarding as 'end',
SUBSTRING(T5.U_Partner, 0, CHARINDEX(';', T5.U_Partner)) AS 'room_id',
CASE WHEN datalength(T5.U_Partner)=0 THEN '9999' ELSE T5.U_Partner END AS 'room_id' ,
CASE WHEN datalength(T5.U_Partner) > 4 THEN T5.U_Partner ELSE '9999' END AS 'partners_id' ,
This is just bonus question. CASE are looking for length of value, if the value is longer than 4 ( 600008 ) write to room_id 9999 and save 600008 to partners_id. If it is empty write 9999 to room_id.
How to make it works together?.so getting value from T_Partner..save it into temporary table T1.TempRoom ( I suppose ).. so T1.TempRoom (is filled with numbers like 64, ,60008,127) then CASE is checking T1.TempRoom for values and save it into room_id and partners_id.
Am I right?
Here is a simple method:
SUBSTRING(T5.U_Partner, 1, CHARINDEX(';', T5.U_Partner + ';')) AS room_id,
That is, concatenate the semicolon to the argument for CHARINDEX(). That will prevent any error occurring.
In addition, indexing for SUBSTRING() starts at 1, not 0.
And, don't use single quotes for column names. Only use them for string and date literals.
EDIT:
You can always use the verbose form:
(CASE WHEN T5.U_Partner LIKE '%;%'
THEN SUBSTRING(T5.U_Partner, 1, CHARINDEX(';', T5.U_Partner + ';'))
ELSE T5.U_Partner
END) AS room_id