SQLServer - Select bool if column begins with a string - sql

I would like to select a boolean of whether or not a column begins with a certain string.
SELECT (name LIKE 'foo%') AS isFoo FROM bar;
Is there a way to do this without using an inline CASE?

No
There is neither implicit boolean CAST in SQL Server nor a boolean type
SELECT CAST(CASE WHEN name LIKE 'foo%' THEN 1 ELSE 0 END AS bit) AS isFoo
FROM bar;

You might not even need the cast depending on your usage:
SELECT CAST(PATINDEX('foo%'), name) AS bit) FROM bar
This will return 1 if the col starts with the text otherwise 0. No CASE involved.

A UNION operation would let you skip a CASE statement by combining two result sets. In the first query you filter for all rows that match 'foo%' and in the second you match all rows that do not match 'foo%'
Something like:
SELECT 1 AS [YourBoolean], 'fool' WHERE 'fool' LIKE 'foo%'
UNION
SELECT 0, 'fuel' WHERE 'fuel' NOT LIKE 'foo%'
ORDER BY 1
(Hard-coded example w/o target table.)

Create a User Defined function that you can call inorder to check if the name contains foo.

Not to take away from what gbn suggested but I think this would be more efficient (but essentially the same thing)
SELECT CAST(CASE WHEN LEFT(name, 3)='foo' THEN 1 ELSE 0 END AS bit) AS isFoo
FROM bar;

SELECT
CASE WHEN name LIKE 'foo%'
THEN 1
ELSE 0
END as isFoo
FROM bar

Related

Equivalent of SELECT 0 as something but for strings. Is it SELECT '' as something?

What is the equivalent of:
SELECT 0 as foo;
but for strings, is it:
SELECT '' as bar;
?
For more context, this is for a UNION ALL query
[edit]
SELECT NULL is what I was looking for.
In the top query I was doing: SELECT COUNT(DISTINCT(bar)),
But empty strings counted as a distinct char, NULL doesn't.
If you want an "equivalent" of SELECT 0 in string form, then it would be SELECT '0'::int.
If you are looking for a non-null string to represent 'no data,' SELECT '' AS something would suffice
When you call UNION ALL, the expectation is that the columns would align and the data sets would be concatenated along their column orders. Since you want to UNION ALL an integer and char, you will get an error:
edb=# select 0 as something union all select '' as something;
ERROR: invalid input syntax for type integer: ""
LINE 1: select 0 as something union all select '' as something;
^
Therefore, in order to UNION ALL, you'll want to cast your 0 as a char:
edb=# select 0::char as something union all select '' as something;
something
-----------
0
(2 rows)
Caveat
I'm not sure if this is really what you want to do, but if you're looking to UNION ALL the two sets, that's how you'd do it. However, there's a chance this would open up a can of worms -- is '' going to be considered equivalent to 0? And what will you do with non-zero values? Will you still cast those integers into strings? I think you'll need to think through those implications and try to find a way to sanitize your data.
In general, it might be better to work with NULL values if your design allows for it

If-Then Statement In A SQL Query Insists On Trying To Convert To Wrong Type, Then Fails

I have a SQL query, linking table 1 to table 2 via an inner join, containing this part in the select part of the statement:
select
table1.field1,
table2.field1,
CASE (table2.field1)
WHEN -2 THEN ''
ELSE table2.field2
END as table2Field2,
table3.field4
from...
I want to be able to return table2Field2 when it has a relevant value, ie: when the object represented in table2 is not null, so that table2.field1 does not have a value of -2. In this case, the value of table2Field2 should be blank instead of a meaningless value.
However, this returns 0 instead of the blank text. If I change this line:
WHEN -2 THEN ''
to this:
WHEN -2 THEN 'someText'
then it complains at me that it's trying to convert an int to a string, which I'm not. table2field1 is an int, but table2Field2 is a string, which is what we're actually returning here.
How do I state (even more specifically) in this query that I'm returning the string field as a string, and not something else as a string that isn't (a) a string, and (b) the thing I specified I'm returning please?
All suggestions welcome, many thanks in advance for any help :)
In a CASE expression, all of the possible return values must be of the same data type. As written, the expression is trying to return one string and one integer.
If you want an empty string for your first output, you can CAST or CONVERT your second output to a character type value:
select
table1.field1,
table2.field1,
CASE (table2.field1)
WHEN -2 THEN ''
ELSE CAST(table2.field2 AS varchar(12)) --< 12 will cover any value of integer.
END as table2Field2,
table3.field4
from...
Is it possible you have your as table2field2 in the wrong location?
maybe try:
select
table1.field1,
table2.field1,
CASE (table2.field1)
WHEN -2 THEN ''
ELSE table2.field2
END as table2Field2,
table3.field4
from...
Because you do not want to answer me what is the database you use then I have to do it like this hehehe:
SQL Server: DEMO
select
t.col1,
CASE
WHEN convert(char,t.col1) = '-2' THEN 'aaa'
ELSE convert(char,(t.col2))
END test
from Tab1 t;
Oracle DEMO
select
t.col1,
CASE
WHEN to_char(t.col1) = '-2' THEN 'aaa'
ELSE to_char(t.col2)
END test
from tab1 t;

Check if any substring from array appear in string?

I have the following query:
select case when count(*)>0 then true else false end
from tab
where param in ('a','b') and position('T' in listofitem)>0
This checks if 'T' exists in the column listofitem and if it does the count is > 0. Basically it's a search for sub string.
This works well in this private case. However my real case is that I have text[] called sub_array meaning multiple values to check. How can I modify the query to handle the sub_array type? I prefer to have it in a query rather than a function with a LOOP.
What I actualy need is:
select case when count(*)>0 then true else false end
from tab
where param in ('a','b') and position(sub_array in listofitem)>0
This is not working since sub_array is of type Text[]
Use the unnest() function to expand your array & bool_and() (or bool_or() -- this depends on what you want match: all array elements, or at least one) to aggregate:
select count(*) > 0
from tab
where param in ('a','b')
and (select bool_and(position(u in listofitem) > 0)
from unnest(sub_array) u)
A brute force method would be to convert the array to a string:
select (count(*) > 0) as flag
from tab
where param in ('a','b') and
array_to_string(listofitem, '') like '%T%';
I should note that comparing count(*) is not the most efficient way of doing this. I would suggest instead:
select exists (select 1
from tab
where param in ('a','b') and
array_to_string(listofitem, '') like '%T%'
) as flag;
This stops the logic at the first match, rather than counting all matching rows.

How to quickly compare many strings?

In SQL Server, I have a string column that contains numbers. Each entry I need is only one number so no parsing is needed. I need some way to find all rows that contain numbers from 400 to 450. Instead of doing:
...where my stringcolumn like '%400%' or stringcolumn like '%401%' or stringcolumn like '%402%' or ...
is there a better that can save on some typing?
There are also other values in these rows such as: '5335154', test4559#me.com', '555-555-5555'. Filtering those out will need to be taken into account.
...where stringcolumn like '4[0-4][0-9]' OR stringcolumn = '450'
You don't need the wildcard if you want to restrict to 3 digits.
Use regex to accomplish this.
...where stringcolumn like '4[0-4][0-9]' OR stringcolumn like '450'
one way
WHERE Column like '%4[0-4][09]%'
OR Column LIKE '%500%'
keep in mind that this will pick anything with the number in it, so 5000 will be returned as well
I would do the following:
select t.*
from (select t.*,
(case when charindex('4', col) > 0
then substrint(col, charindex('4', col), charindex('4', col) + 2)
end) as col4xx
from t
) t
where (case when isnumeric(col4xx) = 1
then (case when cast(col4xx as int) between 400 and 450 then 'true'
end)
end) = 'true'
I'm not a fan of having case statements in WHERE clauses. However, to ensure conversion to a number, this is needed (or the conversion could become a column in another subquery). Note that the following is not equivalent:
where col4xx between '400' and '450'
Since the string '44A' would match.

Specify order of (T)SQL execution

I have seen similar questions asked elsewhere on this site, but more in the context of optimization.
I am having an issue with the order of execution of the conditions in a WHERE clause. I have a field which stores codes, most of which are numeric but some of which contain non-numeric characters. I need to do some operations on the numeric codes which will cause errors if attempted on non-numeric strings. I am trying to do something like
WHERE isnumeric(code) = 1
AND CAST(code AS integer) % 2 = 1
Is there any way to make sure that the isnumeric() executes first? If it doesn't, I get an error...
Thanks in advance!
The only place order of evaluation is guaranteed is CASE
WHERE
CASE WHEN isnumeric(code) = 1
THEN CAST(code AS integer) % 2
END = 1
Also just because it passes the isnumeric test doesn't guarantee that it will successfully cast to an integer.
SELECT ISNUMERIC('$') /*Returns 1*/
SELECT CAST('$' AS INTEGER) /*Fails*/
Depending upon your needs you may find these alternatives preferable.
Why not simply do it using LIKE?:
Where Code Not Like '%[^0-9]%'
Btw, either using my solution or using IsNumeric, there are some edge cases which might lead one to using a UDF such as 1,234,567 where IsNumeric will return 1 but Cast will throw an exception.
Why not use a CASE statement to say something like:
WHERE
CASE WHEN isnumeric(code) = 1
THEN CAST(code AS int) % 2 = 1
ELSE /* What ever else if not numeric */ END
You could do it in a case statement in the select clause, then limit by the value in an outer select
select * from (
select
case when isNum = 1 then CAST(code AS integer) % 2 else 0 end as castVal
from (
select
Case when isnumeric(code) = 1 then 1 else 0 end as isNum
from table) t
) t2
where castval = 1