A small Help needed in a _Sql Converstion of Decimal_ using **CASE** - sql

I am need to convert a value in to decimal.Before that I am checking a condition.I want to eliminate the decimal values if #tbt=1.
Eg if #tbt=1 then 15
if #tbt=0 then 15.233
declare #tbt int =1
1) select
CASE WHEN #tbt=1 THEN CONVERT(DECIMAL(24,0),15.23335)
ELSE CONVERT(DECIMAL(24,3),15.23335) END
2) select
CASE WHEN #tbt=1 THEN '1'
ELSE '2' END
The first Query will returns 15.000.
1. Is it possible to get 15?
2. If CONVERT(DECIMAL(24,0),15.23335) returns 15.then why it is coming 15.000 in the query.
For checking I used another query and it will prints 2.
Thanks

you could use your current solution and add additional cast to Varchar(30) on both.

You can't force it to return 2 separate datatypes like this depending on the CASE.
If you insert that result into a table using SELECT INTO syntax, you'll actually see the datatype is not DECIMAL(24,0) but DECIMAL(27,3)
i.e.
declare #tbt int =1
select
CASE WHEN #tbt=1 THEN CONVERT(DECIMAL(24,0),15.23335)
ELSE CONVERT(DECIMAL(24,3),15.23335) END AS Col
INTO SomeTestTable
--Now check the SomeTestTable schema
So what SQL Server has done, is rationalised it down to a single datatype definition that can fulfil BOTH cases.

WITH T(tbt, val) AS
(
select 1,15.23335 UNION ALL
select 0,15.23335
)
Select
CASE WHEN tbt=1 THEN cast( CONVERT(DECIMAL(24,0),val) as sql_variant)
ELSE CONVERT(DECIMAL(24,3),val) END
FROM T
returns
15
15.233

Thanks to bw_üezi
I got the answer after considering his advice. thanks for all others .
Here my answer..
declare #tbt int =0
select
CASE WHEN #tbt=1 THEN CAST(CONVERT(DECIMAL(24,0),15.23335)AS NVARCHAR)
ELSE CAST(CONVERT(DECIMAL(24,3),15.23335)AS NVARCHAR) END

Related

SQL COALESCE and IS NULL are not returning a space when when the query returns NULL

I am trying to optimize a humongous SQL query that was written by a self taught developer that used a ton of functions instead of JOINS. Anyway, I am having trouble displaying a space or a empty string('') when there is no value in the field selected. I've included only the SELECT in question. I am having the weirdest problem or just overlooking the correct answer in troubleshooting. Whenever I use COALESCE, when the field is supposed to be a blank string, it displays a zero. And when I use IS NULL, I get back NULL. All info online seems to point toward using COALESCE(value, '') as depicted in the code. But I am getting a 0 instead of ''. Does anyone see what I'm doing wrong? I'm using SSMS.
SELECT
pss8.dbo.xml_StripIllegalChars(dbo.rpt_get_series_volume(b.bookkey)) AS p_seriesvol --SELECT to be replaced that works but is slow due to function use I am told
,COALESCE(bd.seriesvolume, '') AS p_seriesvol --my SELECT that won't work!
FROM
bookdetail bd
WHERE
--bd.bookkey='303177'
bd.bookkey='6002'
The bookkeys at the bottom are for testing as I know the top one returns a 1 and the bottom one returns a '' previously when it worked. The SELECT above my commented SELECT is the code that works but is slow... According to what I read online, I am saying 'if there isn't a series volume number, then it equals an empty string.' Does COALESCE not work like this? Can it only return a 0 if the field has no value, or in this case, has no volume number? All help much appreciated. I'm very curious to hear a solution!
Here's more intel. This is how the this SELECT works:
pss8.dbo.xml_StripIllegalChars(dbo.rpt_get_series_volume(b.bookkey)) AS p_seriesvol
The
.rpt_get_series_vol
function manages to create an empty string with this code... Does this reveal anything?
DECLARE #RETURN
VARCHAR(5)
DECLARE #v_desc
VARCHAR(5)
DECLARE #i_volumenumber INT
SELECT #i_volumenumber = volumenumber
FROM bookdetail
WHERE bookkey = #i_bookkey and volumenumber <> 0
IF #i_volumenumber > 0
BEGIN
SELECT #RETURN = CAST(#i_volumenumber as varchar(5))
END
ELSE
BEGIN
SELECT #RETURN = ''
END
RETURN #RETURN
END
As you are looking for a '0' not a NULL COALESCE()is not useful, instead use a simple CASE:
select
...,
case bd.seriesvolume when '0' then '' else bd.seriesvolume end as p_seriesvol
from
...
Or if you want '' for 0 or NULL
case when bd.seriesvolume is null or bd.seriesvolume = '0' then '' else bd.seriesvolume end as p_seriesvo
COALESCE() function returns the 1st non null value
SELECT COALESCE(NULL, NULL, 'third_value', 'fourth_value'); returns the third value because the third value is the first value that is not null.
So in your case COALESCE(bd.seriesvolume, '') AS p_seriesvol if seriesvolume colum value is null then it will return blank string

I'm trying to convert a base 10 number in sql to base 2 / binary but what's being returned ins't ones and zero's

I'm just using some simple sql to try and get it working and then I will implement it into my program.
So my code is below:
select convert(varbinary(16), cast('63' as int)))
My result from this query is 0x000003F which is not what I wanted, I was expecting 000111111.
Does anyone know why it does this and how I can get it to display the number as 1's and 0's, it would be greatly appreciated, Thanks. This is using MSSql.
In MSSQL I think you could try this:
DECLARE #var1 AS int;
SET #var1=12;
WITH A AS (
SELECT 0 AS ORD, #var1 AS NUMBER, CAST('' AS VARCHAR(20)) AS BITS
UNION ALL
SELECT ORD+1, NUMBER/2, CAST(BITS+CAST(NUMBER%2 AS VARCHAR(20)) AS VARCHAR(20))
FROM A
WHERE NUMBER>0)
SELECT RIGHT('000000000000000'+ CASE WHEN BITS='' THEN '0' ELSE REVERSE(BITS) END,16) AS BIN_VALUE
FROM A
WHERE NUMBER=0;
Ouput:
BIN_VALUE
0000000000001100
As collapsar notes in MySQL, you need to specify base 2, which is what you are missing here. Without that, MySQL defaults to hexadecimal encoding here but you need to provide a number (63), a starting base (10), and a final base (2).
Putting this together you get select conv(63, 10, 2) sqlfiddle

Remove only zero after decimal sql server 2012

Consider the following numbers.
7870.2
8220.0
I need to remove decimal points if the value ends with .0. If it ends with .2 then it should keep the value as it is.
I have used ceiling but it removes all the values after decimal.
How can I write a select query in which I can add some condition for this?
Generally speaking you should not do this in your dB. This is an app or reporting side operation. The dB is made to store and query information. It is not made to format/string manipulate information.
use right within a case statement and:
DECLARE #val decimal(5,1)
SET #val = 7870.0
Select
Case
When right(#val,1)<> '0' then
cast(#val as varchar)
else
cast(cast(#val as int) as varchar)
End
output: 7870
EDIT: I could write :
Case
When right(#val,1)<> '0' then
#val
else
cast(#val as int) -- or floor(#val)
End
but because return type of case statement is the highest precedence type from the set of given types, so the output for second version is: 7870.0 not 7870, that's why I convert it to i.e varchar in when clauses, and it can be converted outside of case statement, I mean cast ((case when...then...else... end) as datatype)
Cast the number as a float, using float(24) to increase precision:
DECLARE #t table(number decimal(10,1))
INSERT #t values(7870.2),(8220.0)
SELECT cast(number as float(24))
FROM #t
Result:
7870,2
8220
Here below goes a sample:
declare #1 decimal(4,3)
select #1 = 2.9
select case when SUBSTRING (PARSENAME(#1,1), 1, 1) = 0 then FLOOR(#1) else #1 end
Change the #1 in the select statement with your database field name.
sqlfiddle
The solution seems to be simple:
SELECT CONVERT (FLOAT, PAYLOAD)

SQL Between Begins With

I'm attempting to use an alpha between in SQL; however, I want it to be based on the beginnings of the words only. I am using T-SQL on Microsoft SQL Server 2005.
My current SQL is:
SELECT * FROM table WHERE LEFT(word,1) BETWEEN 'a' AND 't
However, this only works for first letter. I'd like to expand this to work for any beginnings of words. For instance, between 'a' and 'ter'.
Now, I am building this dynamically, so I could do:
SELECT * FROM table WHERE LEFT(word,1) >= 'a' AND LEFT(word,3) <= 'ter'
However, I'd like to know if there is a simpler way in SQL to make a dynamic beginning-of-word between.
EDIT:::
Follow up question, words less than the length of the checked value should be considered less than in the between. For instance, me is less than mem so word < 'mem' should include me.
EDIT:::
Attempting using padding, as suggested. The below does work; however, the added 'a's can cause issue. For instance, if we want words between 'a' and 'mera' and the word being checked is 'mer', this will be included because the left trim of 'mer' becomes 'mera' with added characters. I would like a solution that does not include this issue.
DECLARE #lb varchar(50)
DECLARE #ub varchar(50)
SET #lb='ly'
SET #ub='z'
SELECT name
FROM table
WHERE
LEFT(
CASE
WHEN LEN(name) < LEN(#lb) THEN name+REPLICATE('a',LEN(#lb)-LEN(name))
ELSE name
END,
LEN(#lb)
) >= #lb
AND
LEFT(CASE
WHEN LEN(name) < LEN(#ub) THEN name+REPLICATE('a',LEN(#ub)-LEN(name))
ELSE name
END,
LEN(#ub)
) <= #ub
EDIT:::
Attempted solution, although CASE heavy. Mack's solution is better, though this works as well. LEFT('andy', 200000) will return 'andy', not an error as an OO language would, behavior I did not expect.
DECLARE #lb varchar(50)
DECLARE #ub varchar(50)
SET #lb='a'
SET #ub='lyar'
SELECT *
FROM testtable
WHERE
CASE
WHEN LEN(word) < LEN(#lb) THEN 0
WHEN LEFT(word, LEN(#lb)) >= #lb THEN 1
ELSE 0
END = 1
AND
CASE
WHEN LEN(word) < LEN(#ub) THEN
CASE
WHEN LEFT(#ub,LEN(word)) = word THEN 1
ELSE 0
END
WHEN LEFT(word, LEN(#ub)) <= #ub THEN 1
ELSE 0
END = 1
Thanks in advance!
This should work:
SELECT * FROM table WHERE LEFT(word,3) BETWEEN 'a' AND 'ter'
There's no reason why BETWEEN shouldn't be able to compare your three-letter data string to the one-letter 'a'. Any 'axx' will be "greater than" just 'a' by itself, and so will be included.
You need to use the STUFF function to achieve what you are looking for explicitly.
If you follow the link says it deletes a specified number of characters at the end of the string and replaces them with another string. Combine the with the LEN function and we can get you on the road.
--Test Data
DECLARE #table AS TABLE (word char(10))
INSERT INTO #table VALUES ('me')
INSERT INTO #table VALUES ('mem')
INSERT INTO #table VALUES ('tap')
INSERT INTO #table VALUES ('t')
DECLARE #minword char(5)
DECLARE #maxword char(5)
SET #minword='ai'
SET #maxword='t'
--SET #maxword='tb'--(remove the rem at the start of this line to unlock an extra test for comparison...)
--Query
SELECT word
FROM #table
WHERE STUFF(word, LEN(word)+1, 5, 'aaaaa') BETWEEN STUFF(#minword, LEN(#minword)+1, 5, 'aaaaa')
AND STUFF(#maxword, LEN(#maxword)+1, 5, 'aaaaa')
Alternative solution based on your revised requirements:
DECLARE #testtable AS TABLE (word varchar(20))
INSERT INTO #testtable VALUES ('ly')
INSERT INTO #testtable VALUES ('Ly')
INSERT INTO #testtable VALUES ('Zoo')
INSERT INTO #testtable VALUES ('r')
INSERT INTO #testtable VALUES ('traci')
DECLARE #minword varchar(20)
DECLARE #maxword varchar(20)
SET #minword='ly'
SET #maxword='zol'
SELECT word, LEFT(word,LEN(#minword)), LEFT(word,LEN(#maxword)), #minword, #maxword
FROM #testtable
WHERE LEFT(word,LEN(#minword))>=#minword
AND LEFT(word,LEN(#maxword))<=#maxword
If I understand you right you are trying to make this into a proc. If so, what you have will work in a proc with very little change. Something like the following (untested)...
CREATE PROC myProc(#low varchar(30), #high varchar(30)) AS
SELECT * FROM table WHERE
(LEN(word) >= LEN(#low)
AND
(LEN(word) >= LEN(#high)
AND
(LEFT(word, LEN(#low)) >= #low)
AND
LEFT(word, LEN(#high)) <= #high
There are additional conditions to exclude records when 'word' is shorter than either of your parameters. Otherwise, you will get errors on the LEFT function. This may not be 100% but it should get you close.
I believe I've found a working solution. I'm not sure of the speed sacrifices here, but the DB will remain small, so it's a non-issue in my specific case.
I am using C# to build my SQL string with parameters. #lb is the lower bound word-part. #rb is the upper bound word-part. The where clause is inclusive, but could easily be change to exclusive as needed.
SELECT * FROM table
WHERE
CASE
WHEN LEN(word) < LEN(#lb) THEN 0
WHEN LEFT(word, LEN(#lb)) >= #lb THEN 1
ELSE 0
END = 1
AND
CASE
WHEN LEN(word) < LEN(#rb) THEN 1
WHEN LEFT(word, LEN(#rb)) <= #rb THEN 1
ELSE 0
END = 1

How to check if a string is a uniqueidentifier?

Is there an equivalent to IsDate or IsNumeric for uniqueidentifier (SQL Server)?
Or is there anything equivalent to (C#) TryParse?
Otherwise I'll have to write my own function, but I want to make sure I'm not reinventing the wheel.
The scenario I'm trying to cover is the following:
SELECT something FROM table WHERE IsUniqueidentifier(column) = 1
SQL Server 2012 makes this all much easier with TRY_CONVERT(UNIQUEIDENTIFIER, expression)
SELECT something
FROM your_table
WHERE TRY_CONVERT(UNIQUEIDENTIFIER, your_column) IS NOT NULL;
For prior versions of SQL Server, the existing answers miss a few points that mean they may either not match strings that SQL Server will in fact cast to UNIQUEIDENTIFIER without complaint or may still end up causing invalid cast errors.
SQL Server accepts GUIDs either wrapped in {} or without this.
Additionally it ignores extraneous characters at the end of the string. Both SELECT CAST('{5D944516-98E6-44C5-849F-9C277833C01B}ssssssssss' as uniqueidentifier) and SELECT CAST('5D944516-98E6-44C5-849F-9C277833C01BXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' as uniqueidentifier) succeed for instance.
Under most default collations the LIKE '[a-zA-Z0-9]' will end up matching characters such as À or Ë
Finally if casting rows in a result to uniqueidentifier it is important to put the cast attempt in a case expression as the cast may occur before the rows are filtered by the WHERE.
So (borrowing #r0d30b0y's idea) a slightly more robust version might be
;WITH T(C)
AS (SELECT '5D944516-98E6-44C5-849F-9C277833C01B'
UNION ALL
SELECT '{5D944516-98E6-44C5-849F-9C277833C01B}'
UNION ALL
SELECT '5D944516-98E6-44C5-849F-9C277833C01BXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
UNION ALL
SELECT '{5D944516-98E6-44C5-849F-9C277833C01B}ssssssssss'
UNION ALL
SELECT 'ÀD944516-98E6-44C5-849F-9C277833C01B'
UNION ALL
SELECT 'fish')
SELECT CASE
WHEN C LIKE expression + '%'
OR C LIKE '{' + expression + '}%' THEN CAST(C AS UNIQUEIDENTIFIER)
END
FROM T
CROSS APPLY (SELECT REPLACE('00000000-0000-0000-0000-000000000000', '0', '[0-9a-fA-F]') COLLATE Latin1_General_BIN) C2(expression)
WHERE C LIKE expression + '%'
OR C LIKE '{' + expression + '}%'
Not mine, found this online... thought i'd share.
SELECT 1 WHERE #StringToCompare LIKE
REPLACE('00000000-0000-0000-0000-000000000000', '0', '[0-9a-fA-F]');
SELECT something
FROM table1
WHERE column1 LIKE '[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]';
UPDATE:
...but I much prefer the approach in the answer by #r0d30b0y:
SELECT something
FROM table1
WHERE column1 LIKE REPLACE('00000000-0000-0000-0000-000000000000', '0', '[0-9a-fA-F]');
I am not aware of anything that you could use "out of the box" - you'll have to write this on your own, I'm afraid.
If you can: try to write this inside a C# library and deploy it into SQL Server as a SQL-CLR assembly - then you could use things like Guid.TryParse() which is certainly much easier to use than anything in T-SQL....
A variant of r0d30b0y answer is to use PATINDEX to find within a string...
PATINDEX('%'+REPLACE('00000000-0000-0000-0000-000000000000', '0', '[0-9a-fA-F]')+'%',#StringToCompare) > 0
Had to use to find Guids within a URL string..
HTH
Dave
Like to keep it simple. A GUID has four - in it even, if is just a string
WHERE column like '%-%-%-%-%'
Though an older post, just a thought for a quick test ...
SELECT [A].[INPUT],
CAST([A].[INPUT] AS [UNIQUEIDENTIFIER])
FROM (
SELECT '5D944516-98E6-44C5-849F-9C277833C01B' Collate Latin1_General_100_BIN AS [INPUT]
UNION ALL
SELECT '{5D944516-98E6-44C5-849F-9C277833C01B}'
UNION ALL
SELECT '5D944516-98E6-44C5-849F-9C277833C01BXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
UNION ALL
SELECT '{5D944516-98E6-44C5-849F-9C277833C01B}ssssssssss'
UNION ALL
SELECT 'ÀD944516-98E6-44C5-849F-9C277833C01B'
UNION ALL
SELECT 'fish'
) [A]
WHERE PATINDEX('[^0-9A-F-{}]%', [A].[INPUT]) = 0
This is a function based on the concept of some earlier comments. This function is very fast.
CREATE FUNCTION [dbo].[IsGuid] (#input varchar(50))
RETURNS bit AS
BEGIN
RETURN
case when #input like '[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]'
then 1 else 0 end
END
GO
/*
Usage:
select [dbo].[IsGuid]('123') -- Returns 0
select [dbo].[IsGuid]('ebd8aebd-7ea3-439d-a7bc-e009dee0eae0') -- Returns 1
select * from SomeTable where dbo.IsGuid(TableField) = 0 -- Returns table with all non convertable items!
*/
DECLARE #guid_string nvarchar(256) = 'ACE79678-61D1-46E6-93EC-893AD559CC78'
SELECT
CASE WHEN #guid_string LIKE '________-____-____-____-____________'
THEN CONVERT(uniqueidentifier, #guid_string)
ELSE NULL
END
You can write your own UDF. This is a simple approximation to avoid the use of a SQL-CLR assembly.
CREATE FUNCTION dbo.isuniqueidentifier (#ui varchar(50))
RETURNS bit AS
BEGIN
RETURN case when
substring(#ui,9,1)='-' and
substring(#ui,14,1)='-' and
substring(#ui,19,1)='-' and
substring(#ui,24,1)='-' and
len(#ui) = 36 then 1 else 0 end
END
GO
You can then improve it to check if it´s just about HEX values.
I use :
ISNULL(convert(nvarchar(50), userID), 'NULL') = 'NULL'
I had some Test users that were generated with AutoFixture, which uses GUIDs by default for generated fields. My FirstName fields for the users that I need to delete are GUIDs or uniqueidentifiers. That's how I ended up here.
I was able to cobble together some of your answers into this.
SELECT UserId FROM [Membership].[UserInfo] Where TRY_CONVERT(uniqueidentifier, FirstName) is not null
Use RLIKE for MYSQL
SELECT 1 WHERE #StringToCompare
RLIKE REPLACE('00000000-0000-0000-0000-000000000000', '0', '[0-9a-fA-F]');
In a simplest scenario. When you sure that given string can`t contain 4 '-' signs.
SELECT * FROM City WHERE Name LIKE('%-%-%-%-%')
In BigQuery you can use
SELECT *
FROM table
WHERE
REGEXP_CONTAINS(uuid, REPLACE('^00000000-0000-0000-0000-000000000000$', '0', '[0-9a-fA-F]'))