How to De-Concatenate a Field - sql

I have a field in our SQL Server database that is basically two fields concatenated together. It has a descriptor and a number. I want to build a view with just the number so that I can relate it to other tables. The number is actually typed as a nvarchar on the other tables. So from data like this I want to query for just the number portion:
ProgramField with values:
tst_desc:1
tst_desc:124
tst_desc:1495
tst_desc:20483
So I'd like my query to return a result of:
ProgramNumField
1
124
1495
20483
The number is variable in length growing over time and needs to be nvarchar so I can relate it to the other tables in the database.

If your prefix is always tst_desc: then you can simply strip it off with replace:
select
replace(ProgramField, 'tst_desc:', '') as ProgramNum
from yourTable
If prefix can be different but always separated from value with colon, you can use something like:
select
right(ProgramField, len(ProgramField) - charindex(':', ProgramField)) as ProgramNum
from yourTable

Easiest way is using STUFF
SELECT STUFF(ProgramField, 1, charindex(':', ProgramField), '')
FROM yourtable
If you have dirty data with more than one colon in some row or colon is missing, you can search from right to left for the first none numeric character, you could use this method, This can handle all sorts of funny data:
SELECT
STUFF(RIGHT('#'+ProgramField, PATINDEX('%[^0-9]%',REVERSE(ProgramField)+'#')),1,1,'')

#Andy answer is correct, still you can check this answer.
Declare #t table(data varchar(50))
insert into #t values ('tst_desc:1'), ('tst_desc:2'), ('tst_desc:124'), ('tst_desc:1495'), ('tst_desc:20483')
select
Right( data, charindex (':',reverse(data))-1)
from #t

Related

How to Extract only numbers from the String without using function in SQL

Table contains data as below
Table Name is REGISTER
Column Name is EXAM_CODE
Values like ('S6TJ','S7','S26','S24')
I want answer like below
Result set - > (6,7,26,24)
Please suggest solution - since regexp_replace is not recognized built in function name in SQL.
The complexity of the answer depends on two things: the RDBMS used and whether the numbers in the EXAM_CODE are contiguous.
I have assumed that the RDBMS is SQL Server and the numbers in EXAM_CODE are always contiguous. If not, please advise and I can revise the answer.
The following SQL shows a way of accomplishing the above using PATINDEX.:
CREATE TABLE #REGISTER (EXAM_CODE VARCHAR(10));
INSERT INTO #REGISTER VALUES ('S6TJ'),('S7'),('S26'),('S24');
SELECT LEFT(EXAM_CODE, PATINDEX('%[^0-9]%', EXAM_CODE) - 1)
FROM (
SELECT RIGHT(EXAM_CODE, LEN(EXAM_CODE) - PATINDEX('%[0-9]%', EXAM_CODE) + 1) + 'A' AS EXAM_CODE
FROM #REGISTER
) a
DROP TABLE #REGISTER
This outputs:
6
7
26
24
PATINDEX matches a specified pattern against a string (or returns 0 if there is no match).
Using this, the inner query fetches all of the string AFTER the first occurence of a number. The outer query then strips any text that may appear on the end of the string.
Note: The character A is appended to the result of the inner query in order to ensure that the PATINDEX check in the outer query will make a match. Otherwise, PATINDEX would return 0 and an error would occur.

Change Datatype of json_value during select into so I can sum column

I have a column in a table that is json. It contains several columns within it.
Example:
Row1: "sTCounts":[{"dpsTypeTest":"TESTTRIAL","cnt":3033244.0}
Row2: "sTCounts":[{"dpsTypeTest":"TESTTRIAL","cnt":3.3}
I need to sum the cnt value for all rows in table. For instance, the above would produce a result of 3033247.3
I'm not familiar with stored procs enough to master. I thought the easiest route would be to create a temp table and extract the value into a column, and then write a query to sum the column values.
The problem is that it creates a column with datatype nvarchar(4000). It won't let me sum that column. I thought of changing the datatype but not sure how. I am trying CAST without luck.
select CAST(json AS varchar) AS JSON_VALUE(jsontext,
'$.sTCounts.cnt') AS PerfCount, TitleNumber
INTO dbo_Testing_Count0
from PerformanceTest
select sum(PerfCount)
from dbo_Testing_Count
Group by PerfCount
The error message is:
Incorrect syntax near 'jsontext'.
Any ideas? I am open to another method to sum the column or changing the datatype whichever the experts can aid on. I appreciate it.
The JSON you provide in your question is not valid... This seems to be just a fragment of a larger JSON. As your data starts with a [ you have to think of it as an array, so the simple json path '$.serviceTierCounts.cnt' won't work probably...
Try this, I've added the opening { and the closing brackets at the end:
DECLARE #mockupTable TABLE(ID INT IDENTITY, YourJson NVARCHAR(MAX));
INSERT INTO #mockupTable VALUES
(N'{"serviceTierCounts":[{"dpsType":"TRIAL","cnt":3033244.0}]}')
,(N'{"serviceTierCounts":[{"dpsType":"TRIAL","cnt":3.3}]}');
--You can read one scalar value using JSON_VALUE directly with a cast. But in this case I need to add [0]. This will tell the engine to read the first (zero-based index!) object's cnt property.
SELECT CAST(JSON_VALUE(YourJson,'$.serviceTierCounts[0].cnt') AS DECIMAL(14,4))
FROM #mockupTable
--But I think, that it's this what you are looking for:
SELECT *
FROM #mockupTable
CROSS APPLY OPENJSON(YourJson,'$.serviceTierCounts')
WITH(dpsType varchar(100)
,cnt decimal(14,4));
The WITH clause will return the object in typed columns side-by-side.
For easy proceeding, you can wrap this as a CTE and continue with the set in the following SELECT.

Get the greatest value in a nvarchar column

I'm developing a database with SQL Server 2012 SP2.
I have a table with a NVARCHAR(20) column, and it will have numbers: "000001", "000002", etc.
I need to get the greatest value in that column and convert it to int. How can I do it?
I have found that I can convert a nvarchar to int with this sql sentence:
SELECT CAST(YourVarcharCol AS INT) FROM Table
But I don't know how can I get the max value in that column because the numbers are nvarchar.
UPDATE:
By the way, this column is NVARCHAR because I need to store text on it. I'm testing my solution and I need to store ONLY numbers to test it.
If your numbers are padded like in the example given and all have the same width, you can just sort them alphanumerically and then cast the max-value to INT or BIGINT (depending on your numbers range).
If there are very many rows it was much faster, especially if there is an index on this column...
Something like
SELECT TOP 1 * FROM YourTable
ORDER BY NumberColumn DESC
or, if you need the max-value only:
SELECT MAX(NumberColumn) FROM YourTable
If you have to deal with negative numbers or differently padded numbers you have to cast them first
SELECT TOP 1 * FROM YourTable
ORDER BY CAST(NumberColumn AS INT) DESC
or
SELECT MAX(CAST(NumberColumn AS INT)) FROM YourTable
Please note:
If you've got very many rows, the second might get rather slow. Read about sargable
If your NumberColumn might include invalid values, you have to check, Read about ISNUMERIC().
The best solution - in any case - was to use an indexed numeric column to store these values
Try this one...
I think MAX is enough.
SELECT max(CAST(YourVarcharCol AS INT)) FROM Table
Try this
SELECT MAX(t.Y) from (SELECT CAST(YourVarcharCol AS INT) as Y FROM Table) t
You should try this on finding the highest value:
SELECT MAX(CAST(YourVarcharCol AS INT)) AS FROM Table
If all the data follow the same padding and formatting pattern, a simple max(col) would do.
However, if not, you have to cast the values to int first. Searching on a columns cast to some other datatype will not use an index, if there's any, but will scan the whole table instead. It may or may not be OK for you, depending on requirements and number of rows in the table. If performance is what you need, then create a calculated column as try_cast( col as int), and create an index on it.
Note that you should not use cast, but try_cast instead, to guard against values that can't be cast (if you use a datatype to store something which is essencially of another datatype, it always opens up a possibility for errors).
Of couse, if you can change the original column's type to int, it would be the best.
This will return max int value
SELECT MAX(IIF(ISNUMERIC(YourVarcharCol) = 1, YourVarcharCol, '0') * 1) FROM Table
You can use like this
select max(cast(ColumnName AS INT ))from TableName

Should I ever need to call RTRIM() on a varchar or nvarchar value?

I believe the answer to this question is "no" but I'm interested in the community opinion. A varchar or nvarchar value should automatically trim trailing whitespace, so I don't believe I should ever have to call RTRIM() on such a value. Does any expert have a reason that I would need to?
(In case the tags do not make it clear, I'm referring specifically to Microsoft SQL Server.)
If ANSI_PADDING is ON then trailing spaces will be stored even with varchar/nvarchar data types, so yes.
You may not need to rtrim to get the values out in a simple select, but if you want to concatentate the values (such as combining first and last names to show the full name) you may need to.
Run this test to see what I mean:
create table #temp (test varchar (10))
insert #temp
values ('test ')
insert #temp
values ('test2 ')
insert #temp
values ('test ')
insert #temp
values ('test')
select test + '1' from #temp
select rtrim(test) +'1' from #temp
select * from #temp where test = 'test'
In theory, yes, because of SET ANSI_PADDING which is ON by default and will ON always in future.
To be honest, I tend to RTRIM on write because of this to avoid having on read which happens far more often. It only has to happen once to spoil your day...
SQL Server (and most other SQL DBMSs) really suck when it comes to stuff like this:
insert into Blah values ('careful ');
insert into Blah values ('careful');
Presume there's an id column or something
The values will compare to be the same, will reportedly have the same length, but will not actually have the same data. A concatenation
select Bar + 'something' from Blah
and one will have a space, the other will not.
The (n)varchar only utilizes the amount of space used, so it should not include white space. It is typically used when removing the extra space from a char field that is over allocated, i.e. a char(30) with only 10 characters.
There is a strange case with the LIKE operator. For example:
select 1 where convert(nvarchar(10), 'a') like convert(nvarchar(10), '%a ')
won't return a result.
It depends, for example the Delphi Client dataset and midas.dll used with it (at least version 7 and prior (don't know now) used to have bug that if a the length of the data in a Nvarchar field was less than the one specified, they used to get padded.
Wasn't so much a problem in the database side, but in clients it caused us no little amount of trouble.

Get first or second values from a comma separated value in SQL

I have a column that stores data like (42,12). Now I want to fetch 42 or 12 (two different select queries). I have searched and found some similar but much more complex scenarios. Is there any easy way of doing it? I am using MSSQL Server 2005.
Given there will always be only two values and they will be integer
The reason you have this problem is because the database (which you may not have any control over), violates first normal form. Among other things, first normal form says that each column should hold a single value, not multiple values. This is bad design.
Now, having said this, the first solution that pops into my head is to write a UDF that parses the value in this column, based on the delimiter and returns either the first or second value.
You can try something like this
DECLARE #Table TABLE(
Val VARCHAR(50)
)
INSERT INTO #Table (Val) SELECT '42,12'
SELECT *,
CAST(LEFT(Val,CHARINDEX(',',Val)-1) AS INT) FirstValue,
CAST(RIGHT(Val,LEN(Val) - CHARINDEX(',',Val)) AS INT) SecondValue
FROM #Table
You can use something like this:
SELECT SUBSTRING_INDEX(field, ',', 1)
Note: Its not the efficient way of doing things in rdbms. Consider normalizing your Database.