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
Related
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
Please consider the below table. I am trying to retrieve only the EUR amount within the Tax strings. Some records vary more than the other in size, but the float numbers are always there.
OrderID SKU Price Tax
**** **** **** [<TV<standard#21.0#false#21.36#EUR>VT>]
**** **** **** [<TV<standard#21.0#false#7.21#EUR>VT>]
**** **** **** [<TV<standard#17.0#false#5.17#EUR>VT>]
I wrote a regular expression that matches what I need: \d+\W\d+ returns me both float values within the string. In Oracle SQL I can simply get the second occurrence with a query like:
SELECT REGEXP_SUBSTR(column, '\d+\W\d+',1,2) FROM table
Using the above approach I retrieve 21.36, 7.21 and 5.17 for those three records.
How can I achieve this with SQL Server?
Obviously regex would be the likely tool of choice here. But SQL Server does not have much native regex support. Here is a pure SQL Server solution making use of PATINDEX and CHARINDEX. It is a bit verbose, but gets the job done:
SELECT
SUBSTRING(Tax,
CHARINDEX('#', Tax, PATINDEX('%[0-9]#%', Tax) + 3) + 1,
CHARINDEX('#', Tax, CHARINDEX('#', Tax, PATINDEX('%[0-9]#%', Tax) + 3) + 1) -
CHARINDEX('#', Tax, PATINDEX('%[0-9]#%', Tax) + 3) - 1)
FROM yourTable;
Demo
Please try the following solution.
The approach is using XML for tokenization of the tax column.
It is producing an XML like below for each row:
<root>
<r>[<TV<standard</r>
<r>21.0</r>
<r>false</r>
<r>21.36</r>
<r>EUR>VT>]</r>
</root>
4th r element is a monetary value in question.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, Tax VARCHAR(MAX));
INSERT INTO #tbl (Tax) VALUES
('[<TV<standard#21.0#false#21.36#EUR>VT>]'),
('[<TV<standard#21.0#false#7.21#EUR>VT>]'),
('[<TV<standard#17.0#false#5.17#EUR>VT>]');
-- DDL and sample data population, end
DECLARE #separator CHAR(1) = '#';
SELECT t.*
, c.value('(/root/r[4]/text())[1]', 'DECIMAL(10,2)') AS result
FROM #tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(tax, #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c);
Output
+----+-----------------------------------------+--------+
| ID | Tax | result |
+----+-----------------------------------------+--------+
| 1 | [<TV<standard#21.0#false#21.36#EUR>VT>] | 21.36 |
| 2 | [<TV<standard#21.0#false#7.21#EUR>VT>] | 7.21 |
| 3 | [<TV<standard#17.0#false#5.17#EUR>VT>] | 5.17 |
+----+-----------------------------------------+--------+
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 |
+----+--------------+--------------+
Select len(productid),productid,*
FROM dbo.produts
where Place = 'KA'
and len(productid) <> 10
order by len(productid)
this query filters the data that needs to be updated
-- i need to update the data in 'productid' that is not in the correct format
--(the data should be 10 characters, in 4-2-4 format with leading 0s where they are needed) (productid column is a varchar (256) column)
basically i need to add leading zeros to a varchar column that has a where condition
|productid| |Correct productid value| |
---------------------------------------
|234-55-43||000234-55-43|
|76-7-89||0000076-7-89|
what are the possible solutions for updating these records?
This is very simple, actually:
SELECT productid,
RIGHT('000000000'+productid,10) CorrectProductid
FROM dbo.YourTable
;
If you wanted the corrected format to be in the 4-2-4 format you mentioned:
Using parsename() to parse out the pieces of the string, and right() to add the extra '0's.
select
col
, Corrected = right('0000'+parsename(replace(col,'-','.'),3),4)
+ '-' + right('00'+parsename(replace(col,'-','.'),2),2)
+ '-' + right('0000'+parsename(replace(col,'-','.'),1),4)
from t
where col not like '____-__-____'
rextester demo: http://rextester.com/OXM28014
returns:
+-----------+--------------+
| col | Corrected |
+-----------+--------------+
| 234-55-43 | 0234-55-0043 |
| 76-7-89 | 0076-07-0089 |
+-----------+--------------+
As an update:
update t
set col = right('0000'+parsename(replace(col,'-','.'),3),4)
+ '-' + right('00'+parsename(replace(col,'-','.'),2),2)
+ '-' + right('0000'+parsename(replace(col,'-','.'),1),4)
where col not like '____-__-____'
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