SQL select with 'in' casting from string to tinyint - sql

I have a table from which I want to select data. One coloumn 'myCol' has datatype tinyint. It has values from 1 to 8.
In my select I have a variable #myVar with datatype varchar(), that has values like '1,2' or '3,4'.
Now I am trying to do something like this:
select * from myTable
where myCol in (#myVar)
Unfortunately I get the following error:
Conversion failed when converting the varchar value '2,3' to data type tinyint.
How to change the select that it works like it should?!
It's very important to keep the select performance as high as possible!

Since you only have values from 1 to 8 you can use a string search method. Something like
select * from myTable
where CHARINDEX(cast(mycol as varchar), #myVar) > 0
SQLFiddle demo

If you create a function similar to the accepted answer in Splitting of comma separated values, you will then be able to do:
select * from myTable t
inner join dbo.fnSplitStringAsTable(#myVar, ',') s on t.myCol = s.Value
Note that I'm assuming SQL Server, based on your syntax and the error message.

Change your data to contain flagged enum
[Flags]
public enum ContactMethod
{
Value1 = 1,
Value2 = 2,
Value3 = 4,
Value4 = 8,
Value5 = 16,
Value6 = 32,
Value7 = 64,
Value8 = 128
}
select * from mytable where myCol | 3 = 3
Will then return you all rows with values 1 or 2

Related

use cast in SQL case statement

SELECT
CASE
WHEN column1 = 43 THEN CAST('abcde' as varchar(30))
WHEN column1 = 44 THEN CAST('fghij' as varchar(30))
ELSE 'N/A'
END AS value
Is the above case and cast statement correct? I need to convert the int to a varchar. column1 is a value that comes from another table.
Question 2: I have two values coming from two different tables (table1 and table2) and they need to go to the final table data type varchar
value 1 = CONVERT(VARCHAR(10),CAST(c.table1 * 100 AS DECIMAL(5,2))) + ' %' AS value1
value 2 = CONVERT(VARCHAR(10),c.table2,101) AS value2
c.table1 is decimal coming from table1
c.table2 is int coming from table2 and both need to be varchar at the final table
how do I combine both statements so that it can show up in the final table, its not an OR its an AND.
result set:

Dynamic CASE expression [duplicate]

This question already has answers here:
Check if a varchar is a number (T-SQL)
(12 answers)
Closed 5 years ago.
Is there anyway to have a case expression that produces different results based upon a value being an integer or a character.
Tables
ID CODE
1 ABC
2 123
3 YHU
4 456
5 ikl
I was looking for an expression that separated the int and char.
Result e.g.
ID CODE Category
1 ABC Char
2 123 Int
3 YHU Char
4 456 Int
5 ikl Char
my general logic
CASE WHEN CODE = INT THEN 'Int' Else 'Char' end as Category
But i didnt know if this was possible in SQL?
I am looking mainly for a way to recognise whether its int or char
UPDATE:
What is the best way to separate the numbers from char, * and - into 2 different categories using case expression
ID CODE Category
1 * No_NUM
2 123 NUM
3 YHU No_NUM
4 456 NUM
5 ikl No_NUM
6 - No_NUM
You can use SQL ISNUMERIC function.
SELECT ID, CODE, CASE ISNUMERIC(CODE) WHEN 1 THEN 'NUM' ELSE 'No_NUM' END AS Category FROM my_table;
Another Variation with REGEX
SELECT ID, CODE, CASE WHEN CODE LIKE '%[0-9]%' THEN 'NUM' ELSE 'No_NUM' END AS Category FROM my_table;
You could use TRY_CAST (SQL Server 2012+)
SELECT *,
CASE WHEN TRY_CAST(CODE AS INT) IS NOT NULL THEN 'Int' ELSE 'Char' END
FROM tab;
I've assumed that column is NOT NULL.
Rextester Demo
EDIT:
It is just text inside CASE:
SELECT *,
CASE WHEN TRY_CAST(CODE AS INT) IS NOT NULL THEN 'NUM' ELSE 'No_NUM' END
FROM tab;
Rextester Demo 2
Use PATINDEX:
create table #temp ([ID] int, [CODE] nvarchar(5))
insert into #temp values (1, '*')
insert into #temp values (2, '123')
insert into #temp values (3, 'YHU')
insert into #temp values (4, '456')
insert into #temp values (5, 'ikl')
Select ID
, CASE when PATINDEX('%[0-9]%', [code]) = 1 then 'num'
-- when PATINDEX('%[^0-9]%', [code]) = 1 then 'no_num'
-- when PATINDEX('%[A-Z]%', [code]) = 1 then 'char'
-- when PATINDEX('%[^A-Z]%', [code]) = 1 then 'no_char' /*etc..*/
ELSE 'no_num' END AS 'Category'
from #temp

SQL Server: Compare two columns

I have two columns in a SQL table as follow. I need to compare these two columns for mismatches but due to extra decimals i am getting false results. When i try to convert the first column it gives the error
"Error converting data type varchar to numeric."
How to solve this issue? The length of first column varies.
Column01(varchar) Column02(Decimal)
0.01 0.010000
0.255 0.255000
You have data in Column01 that cannot be casted to DECIMAL.
With SQL Server 2012+ I would use TRY_PARSE:
SELECT *
FROM your_table
WHERE Column02 = TRY_PARSE(Column01 AS DECIMAL(38,18));
LiveDemo
When value from column cannot be casted safely you get NULL.
For SQL Server 2008 you can use:
SELECT *
FROM #tab
WHERE (CASE
WHEN ISNUMERIC(Column01) = 1 THEN CAST(Column01 AS DECIMAL(38,18))
ELSE NULL
END) = Column02;
EDIT:
If you need it at column level use:
SELECT Column01, Column02,
CASE WHEN Column02 = TRY_PARSE(Column01 AS DECIMAL(38,18))
OR (Column02 IS NULL AND Column01 IS NULL)
THEN 'true'
ELSE 'false'
END AS [IsEqual]
FROM #tab;
LiveDemo2
You can do this using self join and conversion function
SELECT x.Column01, y.Column02
FROM table1 x, table1 y
WHERE x.Column02 = try_parse(y.Column01 as decimal(38,18))
Since I cannot comment, I like to thank lad2025 for showing live demo and introducing to data.stackexchange for composing queries
One other way of doing it:
create table #temp(col1 varchar(10),col2 decimal(10,6))
insert into #temp values(0.01,0.010000 ),(0.255,0.255000),(0.25,25),(0.555,10.0)
select * from #temp where REPLACE(REPLACE(col2,col1,''),0,'') = ''
select * from #temp where REPLACE(REPLACE(col2,col1,''),0,'') <> ''

Tidiest way to filter out rows where all columns = a value

I have a query with loads of columns. I want to select rows where not all the columns are equal to 0.
select * from table
where
not
( column1 = 0 and
column2 = 0 and
column3 = 0 and
...
column45 = 0)
Is this really the tidiest way to do it?
Supposing I then need to change it to ignore when all columns are 1, or negative.. Its a lot of cut and paste..
It appears as though the 45 individual columns have a similar meaning. As such, I would encourage you to properly normalize this table. If you did, the query would be simpler and would likely perform better.
You could parameterize the query and put it in a stored procedure or table-valued function. You'd only need to write the query a fixed number of times (once per operation type) regardless of the value(s) you choose.
create function dbo.fn_notequal_columns
(
#value int
)
returns table
as
(
select * from [table]
where column1 <> #value and column2 <> #value ...
)
select * from dbo.fn_notequal_columns(0)
You could use CHECKSUM. However, I don't know the internals of CHECKSUM so can't guarantee it would work over large datasets.
CREATE TABLE dbo.FooBar (
keyCol int NOT NULL IDENTITY (1, 1),
col1 int NOT NULL,
col2 int NOT NULL,
col3 int NOT NULL
)
INSERT FooBar (col1, col2, col3)
SELECT -45, 0, 45
UNION ALL
SELECT 0, 23, 0
UNION ALL
SELECT 0, 0, 0
UNION ALL
SELECT 1, 0, 0
SELECT
CHECKSUM(col1, col2, col3)
FROM
dbo.FooBar
SELECT
*
FROM
dbo.FooBar
WHERE
CHECKSUM(col1, col2, col3) = 0
(1) You have the wrong connective in the condition - you need OR and not AND.
With the question amended, the observation above is no longer correct.
(2) If you have 45 columns that you need to filter on, you are going to be hard pressed to do any better than what you have written. Pain though it be...
This observation remains true.
You could add a computed column that does the calculation for you. It is not technically any tidier, except that now when you use it in any query you only have to check the computed column as opposed to repeating the calculation.
CREATE TABLE dbo.foo
(
col1 INT,
col2 INT,
col3 INT,
all_0 AS
(
CONVERT(BIT, CASE
WHEN col1 = 0 AND col2 = 0 AND col3 = 0
THEN 1 ELSE 0
END)
)
);
If your numbers are constrained in some way to be >= 0, you could do something slightly tidier, such as:
WHERE col1 + col2 + col3 = 0 -- or 45, if there are 45 such columns
-- and you are looking for each column = 1
you could create a view of a normalized structure and use that as your source for this query:
SELECT all other fields, 'Column1', COL1 FROM tableName
UNION
SELECT all other fields, 'Column2, COL2 FROM TableName
UNION ...
SELECT all other fields, 'Column45', COL45 FROM tableName

sql like operator to get the numbers only

This is I think a simple problem but not getting the solution yet. I would like to get the valid numbers only from a column as explained here.
Lets say we have a varchar column with following values
ABC
Italy
Apple
234.62
2:234:43:22
France
6435.23
2
Lions
Here the problem is to select numbers only
select * from tbl where answer like '%[0-9]%' would have done it but it returns
234.62
2:234:43:22
6435.23
2
Here, obviously, 2:234:43:22 is not desired as it is not valid number.
The desired result is
234.62
6435.23
2
Is there a way to do this?
You can use the following to only include valid characters:
SQL
SELECT * FROM #Table
WHERE Col NOT LIKE '%[^0-9.]%'
Results
Col
---------
234.62
6435.23
2
You can try this
ISNUMERIC (Transact-SQL)
ISNUMERIC returns 1 when the input
expression evaluates to a valid
numeric data type; otherwise it
returns 0.
DECLARE #Table TABLE(
Col VARCHAR(50)
)
INSERT INTO #Table SELECT 'ABC'
INSERT INTO #Table SELECT 'Italy'
INSERT INTO #Table SELECT 'Apple'
INSERT INTO #Table SELECT '234.62'
INSERT INTO #Table SELECT '2:234:43:22'
INSERT INTO #Table SELECT 'France'
INSERT INTO #Table SELECT '6435.23'
INSERT INTO #Table SELECT '2'
INSERT INTO #Table SELECT 'Lions'
SELECT *
FROM #Table
WHERE ISNUMERIC(Col) = 1
Try something like this - it works for the cases you have mentioned.
select * from tbl
where answer like '%[0-9]%'
and answer not like '%[:]%'
and answer not like '%[A-Z]%'
With SQL 2012 and later, you could use TRY_CAST/TRY_CONVERT to try converting to a numeric type, e.g. TRY_CAST(answer AS float) IS NOT NULL -- note though that this will match scientific notation too (1+E34). (If you use decimal, then scientific notation won't match)
what might get you where you want in plain SQL92:
select * from tbl where lower(answer) = upper(answer)
or, if you also want to be robust for leading/trailing spaces:
select * from tbl where lower(answer) = trim(upper(answer))