SQL Server, Select CASE with different casting - sql

I want to do a select that do a cast only for a specific ID but it doesn't seems to work.
Example :
SELECT
CASE
WHEN(#ID <> 1) THEN Code
WHEN(#ID = 1) THEN Cast(Code AS int)
END Code FROM ....
Any Idea ?

Why do want to do this? A SQL Server expression has a single fixed type. In other words, a single expression can't be varchar(50) or int depending on how the expression is evaluated. You could cast each case to sql_variant, but that may or may not make sense based on what you're trying to do.
EDIT
If you are executing this query from a stored procedure, you could create an IF..ELSE block to execute a different version of the query based on the value of #ID. For example:
IF (#ID = 1) BEGIN
SELECT Cast(Code AS int) AS Code FROM ...
END
ELSE BEGIN
SELECT Code FROM ...
END

It works for me. Check if the #id is of type int and if all values of column Code can be casted to int.
UPDATE If you have a value that can't be casted to int, your query won't work.
So you can write 2 different queries.
Smth like
IF #id = 1 THEN
SELECT code ...
ELSE
SELECT Cast(Code AS int) as Code

You could have also written:
select case when #ID = 1 then CAST(Code as int) else Code end as Code
from...
By the way, any data containing alphabetic characters won't cast to int.
Perhaps could we better help you if you tell us what you want to achieve, with some sample data provided?

Related

SQL HASHBYTES function returns weird output when used in CASE WHEN/IIF

I have written a stored procedure that hashes the value of a certain column. I need to use this HASHBYTES function in a CASE WHEN or IIF statement, like this:
DECLARE #Hash varchar(255) = 'testvalue'
SELECT IIF(1=1, HASHBYTES('SHA1',#Hash), #Hash)
SELECT CASE WHEN 1=1 THEN HASHBYTES('SHA1',#Hash) END AS Hashcolumn
I can't get my head around why I get different outputs from above queries? it seems that whenever I add an ELSE in the CASE WHEN / IIF statement, it returns a string of weird characters (like ü<þ+OUL'RDOk{­\Ìø in above example).
Can anyone tell me why this is happening? I need to use the CASE WHEN or IIF.
Thanks guys
IIF returns the data type with the highest precedence from the types in true_value and false_value. In this case, it's #Hash1 which is varchar(255) so your result is getting cast to varchar(255). See below.
DECLARE #Hash varchar(255) = 'testvalue'
SELECT cast(HASHBYTES('SHA1',#Hash) as varchar(255))
Similarly, CASE works the same way. However, if you don't add an ELSE or another WHEN that would conflict with the data type, it will work. This is because an ELSE NULL is implied. i.e.
SELECT CASE WHEN 1=1 THEN HASHBYTES('SHA1',#Hash) END
However, if you add another check, then precedence kicks in, and it will be converted.
SELECT CASE WHEN 1=1 THEN HASHBYTES('SHA1',#Hash) WHEN 1=2 THEN #Hash END AS Hashcolumn
SELECT CASE WHEN 1=1 THEN HASHBYTES('SHA1',#Hash) ELSE #Hash END AS Hashcolumn
The output of a select query is a virtual table. In a relational db a column of a table is constrained to single data type.. so here what happens is implicit conversion is being done by the server engine inorder to render a sigle type and hence weird characters are returned.
The nature of conversion is as #scsimon says it follows highest precedence order.
The following query should help.
DECLARE #Hash varchar(255) = 'testvalue'
SELECT IIF(1=1, CONVERT(VARCHAR(255),HASHBYTES('SHA1',#Hash),2), #Hash)
SELECT CASE WHEN 1=2 THEN CONVERT(VARCHAR(255),HASHBYTES('SHA1',#Hash),2)
ELSE #Hash END AS Hashcolumn

How to check a comma delimited integer values by "IF" condition T-SQL?

A simple table contains the one column with integer vales.The Figure is given below.
I am using COALESCE to construct the 'numbers' by comma.
So, now there is a problem when i check a above constructed value in IF Condition like below. It shows an error for cannot convert the varchar datatype to integer.
Now how to check the constructed values in IF condition without changing a logic? I am new for T-SQL.Thank you
When you concatenate all the numbers you are converting it a string so it no longer acts like an integer. If you want to check for a value in a list, do it directly like. SQL was made to have different values in different rows and work with them that way. Try this out:
DECLARE #failIds INT = 23;
IF #failIds IN (SELECT numbers FROM model)
BEGIN
PRINT 'YES'
END
ELSE
BEGIN
PRINT 'NO'
END
Instead of the comma separated string, you should use a table variable, temp. table or just the original table. For example, something like this:
declare #Ids table (id int)
insert into #Ids
select numbers
from model
where numbers in (23,234)
declare #failIds int = 23
if (exists (select 1 from #Ids where id = #failIds)) begin
print 'Yes'
end else begin
print 'No'
end
But you could of course do this too:
if (exists (select 1 from model where numbers = #failIds)) begin
print 'Yes'
end else begin
print 'No'
end
I am very lazy to think about it, Finally i get answer like give below. Its very simple.

SELECT statement having where clause with dynamic condition

I have a small select query which picks data from a table as per the parameter passed to a procedure.
DECLARE #flgParam bit
.
.
SELECT *
FROM tablename
WHERE flgRequired like <If #flgparam is 0 then 1 or zero , Else 1>
what is the best way to construct the where clause
I'm thinking something like this:
SELECT *
from tablename
where #flgparam is null or #flgcolumnval = #flgparam;
#flgparam is declared as a bit, so it can only take on the values of NULL, 0, and 1.
EDIT:
I'm trying to understand the logic. Adapted for the right names:
SELECT *
from sample
where (#flgparam = 0 and flgRequired is not null) or
(coalesce(#flgparam, 1) = 1 and flgRequired = 1)
The like is unnecessary; you can do strict equality.
A bit rough, but it should work, based on requirements:
select
S.itemname
,S.flgrequired
from
sample S
where
(S.flgRequired >= #flgParam)
Tested on sqlfiddle.
You cant use variables to substitute columns in the querys, to achieve that you should create your query as a string #QUERY and execute it using exec #QUERY

SQL: SELECT number text base on a number

Background: I have an SQL database that contain a column (foo) of a text type and not integer. In the column I store integer in a text form.
Question: Is it possible to SELECT the row that contains (in foo column) number greater/lesser than n?
PS: I have a very good reason to store them as text form. Please refrain from commenting on that.
Update: (Forgot to mention) I am storing it in SQLite3.
SELECT foo
FROM Table
WHERE CAST(foo as int)>#n
select *
from tableName
where cast(textColumn as int) > 5
A simple CAST in the WHERE clause will work as long as you are sure that the data in the foo column is going to properly convert to an integer. If not, your SELECT statement will throw an error. I would suggest you add an extra step here and take out the non-numeric characters before casting the field to an int. Here is a link on how to do something similar:
http://blog.sqlauthority.com/2007/05/13/sql-server-udf-function-to-parse-alphanumeric-characters-from-string/
The only real modification you would need to do on this function would be to change the following lines:
PATINDEX('%[^0-9A-Za-z]%', #string)
to
PATINDEX('%[^0-9]%', #string)
The results from that UDF should then be castable to an int without it throwing an error. It will further slow down your query, but it will be safer. You could even put your CAST inside the UDF and make it one call. The final UDF would look like this:
CREATE FUNCTION dbo.UDF_ParseAlphaChars
(
#string VARCHAR(8000)
)
RETURNS int
AS
BEGIN
DECLARE #IncorrectCharLoc SMALLINT
SET #IncorrectCharLoc = PATINDEX('%[^0-9]%', #string)
WHILE #IncorrectCharLoc > 0
BEGIN
SET #string = STUFF(#string, #IncorrectCharLoc, 1, '')
SET #IncorrectCharLoc = PATINDEX('%[^0-9]%', #string)
END
SET #string = #string
RETURN CAST(#string as int)
END
GO
Your final SELECT statement would look something like this:
SELECT *
FROM Table
WHERE UDF_ParseAlphaChars(Foo) > 5
EDIT
Based upon the new information that the database is SQLite, the above probably won't work directly. I don't believe SQLite has native support for UDFs. You might be able to create a type of UDF using your programming language of choice (like this: http://www.christian-etter.de/?p=439)
The other option I see to safely get all of your data (an IsNumeric would exclude certain rows from your results, which might not be what you want) would probably be to create an extra column that has the int representation of the string. It is a little more dangerous in that you need to keep two fields in sync, but it will allow you to quickly sort and filter the table data.
SELECT *
FROM Table
WHERE CAST(foo as int) > 2000

Best practice to avoid code replication?

currently I have to change a view, a big part of the view code looks like this:
CAST('My_Tag_' + CASE
WHEN FieldX isnull
THEN ''
WHEN FieldX = '123'
THEN 'some_number'
WHEN FieldX = 'abc'
THEN 'some_text'
ELSE 'strange' ) AS VARCHAR(128) AS myField
)
Just a chunk of code, that puts together a string (the code itself doesn't even matter right now, I have like 50 other examples, where I have a lot of code replication). Now I have exact the same code for 30 more fields in the view, just the 'My_Tag_' and FieldX is changing. If this would be C#, I would just write a little helper function.
Of course I could write a function here, too. But as this is a bigger project with a lot of tables, views, etc, I would have hundreds of functions soon.
Now I am pretty new to SQL and normally my home is the OOP-world. But there has to be a solution to avoid code replication and to avoid having hundreds of helper functions in the database?
What's best practice in this case?
The best practice may be to create a user defined function.
The arguments would be the fields that change and it would return the intended value.
You can use a CTE to add a field to a table:
; with TableWithExtraField as
(
select case ... end as NewField
, table1
)
select NewField
from TableWithExtraField
Or a subquery also works:
select NewField
from (
select case ... end as NewField
, table1
) as TableWithExtraField
CREATE FUNCTION dbo.MyTag(#myfield VARCHAR(MAX))
RETURNS VARCHAR(128)
AS
BEGIN
RETURN CAST('My_Tag_' + CASE
WHEN #myfield IS NULL
THEN ''
WHEN #myfield = '123'
THEN 'some_number'
WHEN #myfield = 'abc'
THEN 'some_text'
ELSE 'strange' END AS VARCHAR(128))
)
END