convert the numbers - sql

First I am converting the value from the table as integer like
cast(convert(int, isnull(b.temp,0)) as varchar(500))
and then I would like to output values as written below for example
1 as 001
12 as 012
123 as 123
-1 as -001
-15 as -015
-234 as -234
and if length of the integer value is more than 3 then do not display any value or remove it.
If integer has Minus(-) sign then it is not part of the length
so -001 is consider as length 3
so 001 and -001 is acceptable as length 3
How can I do that?

It looks like you are trying to 0 pad numbers in a range. This is one way I do it:
select (case when val between 0 and 999
then right('000'+cast(<col> as varchar(100)), 3)
when val between -999 and 0
then '-'+right('000'+cast(abs(<col>) as varchar(100)), 3)
else ''
end)
from t

There really is no efficient way to do this, but I understand there are situations where this needs to be done. I would probably go about it with something like this turned into a function.
DECLARE #myInt as INT
SET #myInt = -9
DECLARE #padding AS VARCHAR(1)
SET #padding = '0'
DECLARE #length AS INT
SET #length = 3 - LEN(ABS(#myInt))
DECLARE #result AS VARCHAR(5)
SET #result = REPLICATE(#padding, #length) + cast(ABS(#myInt) as VARCHAR(3))
IF #myInt < 0
SET #result = '-' + #result
SELECT #result
This really should be done in code and not sql.

Solution below works. Thanks
declare #num1 as varchar(50)
set #num1 = '1'
select (case
when #num1 between 0 and 999 then right('000'+cast(#num1 as varchar(100)), 3)
when #num1 between -999 and 0 then '-'+right('000'+cast(abs(#num1) as varchar(100)), 3)
else ''
end) as t

Related

in SQL, how can I find duplicate string values within the same record?

Sample table
Record Number | Filter | Filters_Applied
----------------------------------------------
1 | yes | red, blue
2 | yes | green
3 | no |
4 | yes | red, red, blue
Is it possible to query all records where there are duplicate string values? For example, how could I query to pull record 4 where the string "red" appeared twice? Except in the table that I am dealing with, there are far more string values that can populate in the "filters_applied" column.
CLARIFICATION I am working out of Periscope and pulling data using SQL.
I assume that you have to check that in the logical page.
You can query the table with like '%red%'.
select Filters_Applied from table where Filters_Applied like '%red%';
You will get the data which has red at least one. Then, doing some string analysis in logic page.
In php, You can use the substr_count function to determine the number of occurrences of the string.
//the loop to load db query
while(){
$number= substr_count("Filters_Applied",red);
if($number>1){
echo "this".$Filters_Applied.">1"
}
}
for SQL-SERVER or other versions which can run these functions
Apply this logic
declare #val varchar(100) = 'yellow,blue,white,green'
DECLARE #find varchar(100) = 'green'
select #val = replace(#val,' ','') -- remove spaces
select #val;
select (len(#val)-len(replace(#val,#find,'')))/len(#find) [recurrence]
Create this Function which will parse string into rows and write query as given below. This will works for SQL Server.
CREATE FUNCTION [dbo].[StrParse]
(#delimiter CHAR(1),
#csv NTEXT)
RETURNS #tbl TABLE(Keys NVARCHAR(255))
AS
BEGIN
DECLARE #len INT
SET #len = Datalength(#csv)
IF NOT #len > 0
RETURN
DECLARE #l INT
DECLARE #m INT
SET #l = 0
SET #m = 0
DECLARE #s VARCHAR(255)
DECLARE #slen INT
WHILE #l <= #len
BEGIN
SET #l = #m + 1--current position
SET #m = Charindex(#delimiter,Substring(#csv,#l + 1,255))--next delimiter or 0
IF #m <> 0
SET #m = #m + #l
--insert #tbl(keys) values(#m)
SELECT #slen = CASE
WHEN #m = 0 THEN 255 --returns the remainder of the string
ELSE #m - #l
END --returns number of characters up to next delimiter
IF #slen > 0
BEGIN
SET #s = Substring(#csv,#l,#slen)
INSERT INTO #tbl
(Keys)
SELECT #s
END
SELECT #l = CASE
WHEN #m = 0 THEN #len + 1 --breaks the loop
ELSE #m + 1
END --sets current position to 1 after next delimiter
END
RETURN
END
GO
CREATE TABLE Table1# (RecordNumber int, [Filter] varchar(5), Filters_Applied varchar(100))
GO
INSERT INTO Table1# VALUES
(1,'yes','red, blue')
,(2,'yes','green')
,(3,'no ','')
,(4,'yes','red, red, blue')
GO
--This query will return what you are expecting
SELECT t.RecordNumber,[Filter],Filters_Applied,ltrim(rtrim(keys)), count(*)NumberOfRows
FROM Table1# t
CROSS APPLY dbo.StrParse (',', t.Filters_Applied)
GROUP BY t.RecordNumber,[Filter],Filters_Applied,ltrim(rtrim(keys)) HAVING count(*) >1
You didn't state your DBMS, but in Postgres this isn't that complicated:
select st.*
from sample_table st
join lateral (
select count(*) <> count(distinct trim(item)) as has_duplicates
from unnest(string_to_array(filters_applied,',')) as t(item)
) x on true
where x.has_duplicates;
Online example: http://rextester.com/TJUGJ44586
With the exception of string_to_array() the above is actually standard SQL

I have a column with datatype nvarchar and I want to sort it in ascending order. How do I achieve it in SSRS?

This is what I'm getting
abc 1
abc 12
abc 15
abc 2
abc 3
And this is how I want
abc 1
abc 2
abc 3
abc 12
abc 15
Query that I use:
select *
from view_abc
order by col1
Use a function to strip out the non numeric characters and leave just the value. Use another function to strip out all the numeric data. You can then sort on the two returned values.
It seems like a bit of work at first but once the functions are in you can re-use them in the future. Here's two functions I use regularly when we get data in from external sources and it's not very normalised.
They may not be the most efficient functions in the world but they work for my purposes
1st a function to just leave the numeric portion.
CREATE FUNCTION [fn].[StripToAlpha]
(
#inputString nvarchar(4000)
)
RETURNS varchar(4000)
AS
BEGIN
DECLARE #Counter as int
DECLARE #strReturnVal varchar(4000)
DECLARE #Len as int
DECLARE #ASCII as int
SET #Counter=0
SET #Len=LEN(#inputString)
SET #strReturnVal = ''
WHILE #Counter<=#Len
BEGIN
SET #Counter = #Counter +1
SET #ascii= ASCII(SUBSTRING(#inputString,#counter,1))
IF(#ascii BETWEEN 65 AND 90) OR (#ascii BETWEEN 97 AND 122)
BEGIN
SET #strReturnVal = #strReturnVal + (SUBSTRING(#inputString,#counter,1))
END
END
RETURN #strReturnVal
END
2nd a function to extract the value from a text field, this also handle percentages (e.g. abc 23% comes out as 0.23) but this is not required in your case.
You'll need to CREATE an 'fn' schema of change the schema name first...
CREATE FUNCTION [fn].[ConvertToValue]
(
#inputString nvarchar(4000)
)
RETURNS Float
AS
BEGIN
DECLARE #Counter as int
DECLARE #strReturnVal varchar(4000)
DECLARE #ReturnVal Float
DECLARE #Len as int
DECLARE #ASCII as int
SET #Counter=0
SET #Len=LEN(#inputString)
SET #strReturnVal = ''
IF #inputString IS NULL
BEGIN
Return NULL
END
IF #Len = 0 OR LEN(LTRIM(RTRIM(#inputString))) = 0
BEGIN
SET #ReturnVal=0
END
ELSE
BEGIN
WHILE #Counter<=#Len
BEGIN
SET #Counter = #Counter +1
SET #ascii= ASCII(SUBSTRING(#inputString,#counter,1))
IF(#ascii BETWEEN 48 AND 57) OR (#ascii IN (46,37))
BEGIN
SET #strReturnVal = #strReturnVal + (SUBSTRING(#inputString,#counter,1))
END
END
if RIGHT(#strReturnVal,1)='%'
BEGIN
SET #strReturnVal = LEFT(#strReturnVal,len(#strReturnVal)-1)
SET #strReturnVal = CAST((CAST(#strReturnVal AS FLOAT)/100) AS nvarchar(4000))
END
SET #ReturnVal = ISNULL(#strReturnVal,0)
END
RETURN #ReturnVal
END
Now we have the two functions created you can simply do
SELECT *
FROM view_abc
ORDER BY fn.StripToAlpha(Col1), fn.ConvertToValue(Col1)
Try this
Edited :
SELECT CAST(SUBSTRING(ColumnNameToOrder, CHARINDEX(' ', ColumnNameToOrder, 0), LEN (ColumnNameToOrder)) AS INT) AS IntColumn, SUBSTRING(ColumnNameToOrder,0, CHARINDEX(' ', ColumnNameToOrder, 0)) AS CharColumn, * FROM view_abc ORDER BY Charcolumn, Intcolumn
Instead of ColumnNameToOrder, you can put your column name which contains the data like 'abc 123'...
Tell me if it works please.
This is what I have come up with. Maybe it can help you, or at least point you in the right direction.
I tested the values. When the values have a zero, the order is like you would like the order to be. Like this:
abc 01
abc 02
abc 03
abc 12
abc 15
So you can run this query to update the existing values, to add the zero.
UPDATE abc
SET col1 = 'abc 0' + SUBSTRING(col1, 5, 1)
WHERE LEN(col1) = 5
Or you can do the above query like this if the first three characters can vary:
UPDATE abc
SET col1 = (SUBSTRING(col1, 1, 3) + ' 0' + SUBSTRING(col1, 5, 1))
WHERE col1 LIKE 'abc__'
This will override the existing value in the col1 column, only when the length of the current String is of length 5.
Then you can run the following query to get the results:
SELECT col1
FROM abc
ORDER BY col1 ASC
=cint(right(Fields!Col1.Value, instrrev(Fields!Col1.Value, " ")-1))
This will work in SSRS and sort correctly, but will only work if Col1 always contains a space, and that the characters after the space can be converted to an integer.

isnumeric function not providing expected results

The dsply_val is a varchar(2000) field. When i run the query below i am getting 0 for the isnumeric columns even though these values appear to be numeric. I am trying to perform a simple calculation on this column but I end up getting conversion error when I try to convert to decimal or float. As you can see by the 15.2 value some actually do come back as numeric.
I exported the dsply_val to excel and verified that there are no letters or anything out of the ordinary.
What else could i attempt with this or what am I not doing correctly?
SELECT obsv_cd_name,
dsply_val,
ISNUMERIC(dsply_val),
ISNUMERIC(dsply_val + 'e0'),
ISNUMERIC(rtrim(Ltrim(dsply_val)))
FROM smsmir.mir_sr_obsv
where obsv_cd_name = 'WBC'
and sort_dtime >= '2015-01-25'
and orgz_cd = 'CFVMC'
and dsply_val NOT like ('%SEE%')
WBC 8.6 0 0 0
WBC 7.8 0 0 0
WBC 13.4 0 0 0
WBC 5.9 0 0 0
WBC 8.2 0 0 0
WBC 5.9 0 0 0
WBC 7.5 0 0 0
WBC 15.2 1 1 1
WBC 15.2 0 0 0
I think you have line feed or carriage return or tab char in your column.
Actually I can reproduce your problem:
SET NOCOUNT ON
GO
Set string to 6 + Carriage Return + Line Feed + Tab
DECLARE #s NVARCHAR(MAX) = '6' + CHAR(13) + CHAR(10) + CHAR(9)
You see just 6
SELECT #s
But the length of string is 4:
SELECT LEN(#s)
Here are results for ISNUMERIC function:
SELECT ISNUMERIC(#s)
Even TRIM doesn't help:
SELECT ISNUMERIC(LTRIM(RTRIM(#s)))
You should replace those chars:
SELECT ISNUMERIC(REPLACE(REPLACE(REPLACE(#s, CHAR(10), ''), CHAR(13), ''), CHAR(9), ''))
You can print out all chars in your string, so you can then replace non-digit chars in string with blank '':
DECLARE #i INT = 1
WHILE #i <= len(#s)
BEGIN
PRINT ASCII(SUBSTRING(#s, #i, 1))
SET #i = #i + 1
END
Use this function instead of ISNUMERIC. Trim functionality has been added in the function.
CREATE FUNCTION dbo.isReallyNumeric
(
#num VARCHAR(64)
)
RETURNS BIT
BEGIN
SET #num = LTRIM(RTRIM(#num))
IF LEFT(#num, 1) = '-'
SET #num = SUBSTRING(#num, 2, LEN(#num))
DECLARE #pos TINYINT
SET #pos = 1 + LEN(#num) - CHARINDEX('.', REVERSE(#num))
RETURN CASE
WHEN PATINDEX('%[^0-9.-]%', #num) = 0
AND #num NOT IN ('.', '-', '+', '^')
AND LEN(#num)>0
AND #num NOT LIKE '%-%'
AND
(
((#pos = LEN(#num)+1)
OR #pos = CHARINDEX('.', #num))
)
THEN
1
ELSE
0
END
END
GO
And use the query
SELECT ColumnName
FROM Yourtable
WHERE DBO.isReallyNumeric(ColumnName)=1

How to update values using case statement

I have created update statement like below
UPDATE dbo.S_Item
SET SalePrice3 = CASE WHEN Price <0 THEN '-1'
when Price=1 then 11
when Price=2 then 22
when Price=3 then 33
when Price=4 then 44
when Price=5 then 55
when Price=6 then 66
when Price=7 then 77
when Price=8 then 88
when Price=9 then 99
when Price=0 then 00
end
but i want update more values using above statement for example if want update price=123 it has to update 112233,if price=456 it has to update 445566,if price=725 it has to update 772255 how can achieve this help me
Create Function ReplicateDigits (
#Number Int)
Returns BigInt
Begin
Declare #Step SmallInt = 1,
#Result nVaRchar(100) = N''
While (#Step <= Len(#Number))
Begin
Select #Result = #Result + Replicate(SubString(Cast(#Number As Varchar), #Step, 1), 2)
Select #Step = #Step + 1
End
Return Cast(#Result As BigInt)
End
Go
Then:
UPDATE dbo.S_Item
SET SalePrice3 = CASE
WHEN Price <0 THEN '-1'
Else dbo.ReplicateDigits(Price)
End
Let me know if it was useful.
If the point is just in duplication of every digit, here's another implementation of the duplication method:
CREATE FUNCTION dbo.DuplicateDigits(#Input int)
RETURNS varchar(20)
AS
BEGIN
DECLARE #Result varchar(20) = CAST(#Input AS varchar(20));
DECLARE #Pos int = LEN(#Result);
WHILE #Pos > 0
BEGIN
SET #Result = STUFF(#Result, #Pos, 0, SUBSTRING(#Result, #Pos, 1));
SET #Pos -= 1;
END;
RETURN #Result;
END;
The method consists in iterating through the digits backwards, extracting each using SUBSTRING and duplicating it using STUFF.
And you would be using this function same as in Meysam Tolouee's answer:
UPDATE dbo.S_Item
SET SalePrice3 = CASE
WHEN Price < 0 THEN '-1'
ELSE dbo.DuplicateDigits(SalePrice3)
END;
To explain a little why the function's returned type is varchar, it is because that guarantees that the function returns the result no matter what the input's [reasonable] length is. The maximum length of 20 has been chosen merely because the input is [assumed to be] int and positive int values consist of up to 10 digits.
However, whether varchar(20) converts to the type of SalePrice3 is another matter, which should be considered separately.
Youy Must Create a Procedure for Achiving the Desired Result Rather Than to Use a Single Query.

How do I convert an int to a zero padded string in T-SQL?

Let's say I have an int with the value of 1. How can I convert that int to a zero padded string, such as 00000001?
Declare #MyInt integer Set #MyInt = 123
Declare #StrLen TinyInt Set #StrLen = 8
Select Replace(Str(#MyInt, #StrLen), ' ' , '0')
Another way is:
DECLARE #iVal int = 1
select REPLACE(STR(#iVal, 8, 0), ' ', '0')
as of SQL Server 2012 you can now do this:
format(#int, '0000#')
This work for me:
SELECT RIGHT('000' + CAST(Table.Field AS VARCHAR(3)),3) FROM Table
...
I created this user function
T-SQL Code :
CREATE FUNCTION CIntToChar(#intVal Int, #intLen Int) RETURNS nvarchar(24) AS BEGIN
IF #intlen > 24
SET #intlen = 24
RETURN REPLICATE('0',#intLen-LEN(RTRIM(CONVERT(nvarchar(24),#intVal))))
+ CONVERT(nvarchar(24),#intVal) END
Example :
SELECT dbo.CIntToChar( 867, 6 ) AS COD_ID
OUTPUT
000867
Use FORMAT(<your number>,'00000000') use as many zeroes as you need to have digits in your final outcome.
Here is official documentation of the FORMAT function
If I'm trying to pad to a specific total length, I use the REPLICATE and DATALENGTH functions, like so:
DECLARE #INT INT
DECLARE #UNPADDED VARCHAR(3)
DECLARE #PADDED VARCHAR(3)
SET #INT = 2
SET #UNPADDED = CONVERT(VARCHAR(3),#INT)
SET #PADDED = REPLICATE('0', 3 - DATALENGTH(#UNPADDED)) + #UNPADDED
SELECT #INT, #UNPADDED, #PADDED
I used variables here for simplicity, but you see, you can specify the final length of the total string and not worry about the size of the INT that you start with as long as it's <= the final string length.
I always use:
SET #padded = RIGHT('z0000000000000'
+ convert(varchar(30), #myInt), 8)
The z stops SQL from implicitly coverting the string into an int for the addition/concatenation.
If the int can go negative you have a problem, so to get around this I sometimes do this:
DECLARE #iVal int
set #iVal = -1
select
case
when #ival >= 0 then right(replicate('0',8) + cast(#ival as nvarchar(8)),8)
else '-' + right(replicate('0',8) + cast(#ival*-1 as nvarchar(8)),8)
end
Very straight forward way to think about padding with '0's is, if you fixed your #_int's to have 4 decimals, you inject 4 '0's:
select RIGHT( '0000'+ Convert(varchar, #_int), 4) as txtnum
; if your fixed space is 3, you inject 3'0's
select RIGHT( '000'+ Convert(varchar, #_int), 3) as txtnum
; below I inject '00' to generate 99 labels for each bldg
declare #_int int
set #_int = 1
while #_int < 100 Begin
select BldgName + '.Floor_' + RIGHT( '00'+ Convert(varchar, #_int), 2)
+ '.balcony' from dbo.tbl_FloorInfo group by BldgName
set #_int = #_int +1
End
Result is:
'BldgA.Floor_01.balcony'
'BldgB.Floor_01.balcony'
'BldgC.Floor_01.balcony'
..
..
'BldgA.Floor_10.balcony'
'BldgB.Floor_10.balcony'
'BldgC.Floor_10.balcony'
..
..
..
'BldgA.Floor_99.balcony'
'BldgB.Floor_99.balcony'
'BldgC.Floor_99.balcony'
Or if you really want to go hard-core... ;-)
declare #int int
set #int = 1
declare #string varchar(max)
set #string = cast(#int as varchar(max))
declare #length int
set #length = len(#string)
declare #MAX int
set #MAX = 8
if #length < #MAX
begin
declare #zeros varchar(8)
set #zeros = ''
declare #counter int
set #counter = 0
while (#counter < (#MAX - #length))
begin
set #zeros = #zeros + '0'
set #counter = #counter + 1
end
set #string = #zeros + #string
end
print #string
And then there's this one, using REPLICATE:
SELECT REPLICATE('0', 7) + '1'
Of course, you can replace the literals 7 and '1' with appropriate functions as needed; the above gives you your example. For example:
SELECT REPLICATE('0', 8 - LEN(CONVERT(nvarchar, #myInt))) + CONVERT(nvarchar, #myInt)
will pad an integer of less than 8 places with zeros up to 8 characters.
Now, a negative number in the second argument of REPLICATE will return NULL. So, if that's a possibility (say, #myInt could be over 100 million in the above example), then you can use COALESCE to return the number without leading zeros if there are more than 8 characters:
SELECT COALESCE(REPLICATE('0', 8 - LEN(CONVERT(nvarchar, #myInt))) + CONVERT(nvarchar, #myInt), CONVERT(nvarchar, #myInt))
I think Charles Bretana's answer is the simplest and fastest. A similar solution without using STR is:
SELECT REPLACE(REVERSE(
CONVERT(CHAR(5 /*<= Target length*/)
, REVERSE(CONVERT(VARCHAR(100), #MyInt)))
), ' ', '0')