Given the following values (float data type), I want to ROUND them in the following way:
+----------------+--------+
| Original Value | Result |
+----------------+--------+
| 53.36 | 53.40 |
| 53.34 | 53.30 |
| 53.35 | 53.35 | --Do not round up when 5
+----------------+--------+
Is there is a way to do this using T-SQL?
Since you need your value to remain xx.x5 when found but ROUND otherwise, the following will work for you:
(IIF available in SQL Server 2012+)
DECLARE #val FLOAT = 53.35;
SELECT IIF ((RIGHT(#val,1) = 5), #val, ROUND(#val,1)) result
SET #val = 53.34
SELECT IIF ((RIGHT(#val,1) = 5), #val, ROUND(#val,1)) result
SET #val = 53.36
SELECT IIF ((RIGHT(#val,1) = 5), #val, ROUND(#val,1)) result
Here is a good resource to read about differences of types, specifically read about float types. Seems that's possibly not a good datatype for the values you have. Just something to consider.
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
I am trying to convert one of my measure column values having below from varchar to decimal(20,3). The 3rd value is a null value without any space and to make you understand I enclosed with quotes. I have tried with CAST but CAST is not able to change datatype as having negative sign. But I want to keep negative value.
I tried using TRY_CONVERT and TRY_CAST but that is not giving desired result. If anyone can help will be really helpful. I have tried below
CAST(COALESCE((NULLIF(SalesColumn,'')),'0') AS NUMERIC(20,12))
-992.0
0
I use SQL Server 2017 and CAST works just fine and maintains the "-"-sign, below is an example. Beware of the rounding, you might need to use ROUND() before converting it to decimal(20,3) by first converting it to a decimal with higher precision, using ROUND() and then casting it to decimal(20,3).
Using CAST to numeric or decimal works just fine on NULL as well.
DECLARE
#Val1 VARCHAR(10) = '-992.123'
,#Val2 VARCHAR(10) = '-45678'
,#Val3 VARCHAR(10) = NULL
,#Val4 VARCHAR(10) = ''
,#Val5 VARCHAR(10) = '321'
,#Val6 VARCHAR(10) = ' '
SELECT ISNULL(CAST(NULLIF(A, '') as decimal(20,3)), 0)
FROM (
VALUES (#Val1), (#Val2), (#Val3), (#Val4), (#Val5), (#Val6)
) Sub (A)
Which gives the result..
---------------------------------------
-992.123
-45678.000
0.000
0.000
321.000
0.000
(6 rows affected)
You can add another coalesce() within nullif() to handle null value. Please look into below examples.
declare #var as varchar(50);
set #var=null;
select cast(COALESCE((NULLIF(coalesce(trim(#var),0),'')),'0') AS NUMERIC(20,12))
GO
| (No column name) |
| ---------------: |
| 0.000000000000 |
declare #var as varchar(50);
set #var=' ';
select cast(COALESCE((NULLIF(coalesce(trim(#var),0),'')),'0') AS NUMERIC(20,12))
GO
| (No column name) |
| ---------------: |
| 0.000000000000 |
declare #var as varchar(50);
set #var='- 992 ';
select cast(COALESCE((NULLIF(coalesce(trim(#var),0),'')),'0') AS NUMERIC(20,12))
GO
| (No column name) |
| ----------------: |
| -992.000000000000 |
db<>fiddle here
I'm having an issue with the MS SQL case statement that has cast inside. Here is the example I cam up with.
DECLARE #bla as varchar(10) = '001234'
DECLARE #vb AS varchar(20) = 'bla'
SELECT CASE when (#vb <> 'bla') THEN CAST(#bla AS int) ELSE #bla END vbla
The result is very strange. It should be 001234. What am I missing?
+------+
| vbla |
+------+
| 1234 |
+------+
A case EXPRESSION (not statement) returns a single type. When one of the branches is a number, then the return value is a number.
The value you are seeing is the number that the string converts to. If the string started with a non-digit, then the value would be 0.
If you want to see the leading zeros, leave the value as a string.
I have the following code
DECLARE #m FLOAT=213456789.55
DECLARE #sql VARCHAR(MAX)='INSERT INTO Test VALUES('+CONVERT(VARCHAR,#m,1)+')'
EXEC(#sql)
but the result is 213456790 instead of 213456789.55
When I try to write CONVERT(VARCHAR,213456789.55,1) it then returns 213456789.55 not 213456790
How do I solve this?
EDITS
Declaring #m as Decimal like following DECLARE #m DECIMAL(18,2)=213456789.55 solved the issue but I want to know if there is another solution for using float. Thanks
You can use STR instead of CONVERT. STR allows to specify number of decimal places to the right of the decimal point.
DECLARE #m FLOAT=213456789.55;
SELECT
#m AS [Float]
,CONVERT(VARCHAR(100),#m,0) AS Convert0
,CONVERT(VARCHAR(100),#m,1) AS Convert1
,CONVERT(VARCHAR(100),#m,2) AS Convert2
,LTRIM(STR(#m, 20, 2)) AS [Str]
Result (SQL Server 2008)
+--------------+--------------+----------------+------------------------+--------------+
| Float | Convert0 | Convert1 | Convert2 | Str |
+--------------+--------------+----------------+------------------------+--------------+
| 213456789.55 | 2.13457e+008 | 2.1345679e+008 | 2.134567895500000e+008 | 213456789.55 |
+--------------+--------------+----------------+------------------------+--------------+
CONVERT always uses scientific notation for float types.
try this:
DECLARE #m FLOAT=213456789.55
DECLARE #sql VARCHAR(MAX)='INSERT INTO Test VALUES('+CONVERT(VARCHAR,CAST(#m AS MONEY),1)+')'
EXEC(#sql)
Ok so I have a database row with a specified string in for example i am here.
I want to know how I could match this row (in a T-SQL query) if for example my input was hello i am here in this bright room.
To be clearer and get a better answer hopefully, here is a rough example:
Table:
1 | i am there |
2 | i am here |
3 | i am not here |
Problem:
I have the input hello i am here in this bright room - this should return a match to row 2 above only as only row 2 contains i am here definitively whilst the others contain the characters for i am here but with subtle differences.
If anyone can help it would be much appreciated. I would like to do this all in SQL so I can create a stored procedure for the above.
DECLARE #InputString VARCHAR(100);
SET #InputString = 'hello i am here in this bright room';
SELECT *
FROM YourTable
WHERE CHARINDEX(YourColumn, #InputString) <> 0;
declare #input as varchar
set #input = 'hello i am here in this bright room'
select *
from MyTable
where #input like '%' + MyCol + '%'