Querying SQL IN for list of strings - sql

I have the following query which returns 0 results which I know is wrong. However not sure what is off with my syntax.
select * from SJT_USER where SJT_USER_NAME in
( select USER_NAME from NON_MEMBER);
SJT_USER_NAME type NCHAR(255 CHAR)
USER_NAME type NVARCHAR2(255 CHAR)
I'm guessing I need to do some conversion from NVARCHAR2 to NCHAR.

Try a SQL Cast so you're comparing apples to apples. I'm not certain which DBMS you're using, but the syntax should be similar to this:
select * from SJT_USER where SJT_USER_NAME in ( select CAST(USER_NAME AS NVARCHAR2) from NON_MEMBER);

A CHAR or NCHAR is fixed length so it the SJT_USER_NAME is padded by spaces so it fills up the 255 chars. When comparing the two there are two options. You can either TRIM or use RPAD:
select * from SJT_USER where TRIM(SJT_USER_NAME) in ( select USER_NAME from NON_MEMBER);
or
select * from SJT_USER where TRIM(SJT_USER_NAME) in ( select RPAD(USER_NAME,255) from NON_MEMBER);
The later might be preferable if you have an index SJT_USER_NAME. IF performance is not concern I usually prefer to have a TRIM on both sides of the comparison just to be on the safe side.

Related

DB2 efficient select query with like operator for many values (~200)

I have written the following query:
SELECT TBSPACE FROM SYSCAT.TABLES WHERE TYPE='T' AND (TABNAME LIKE '%_ABS_%' OR TABNAME LIKE '%_ACCT_%')
This gives me a certain amount of results. Now the problem is that I have multiple TABNAME to select using the LIKE operator (~200). Is there an efficient way to write the query for the 200 values without repeating the TABNAME LIKE part (because there are 200 such values which would result in a really huge query) ?
(If it helps, I have stored all required TABNAME values in a table TS to retrieve from)
If you are just looking for substrings, you could use LOCATE. E.g.
WITH SS(S) AS (
VALUES
('_ABS_')
, ('_ACCT_')
)
SELECT DISTINCT
TABNAME
FROM
SYSCAT.TABLES, SS
WHERE
TYPE='T'
AND LOCATE(S,TABNAME) > 0
or if your substrings are in table CREATE TABLE TS(S VARCHAR(64))
SELECT DISTINCT
TABNAME
FROM
SYSCAT.TABLES, TS
WHERE
TYPE='T'
AND LOCATE(S,TABNAME) > 0
You could try REGEXP_LIKE. E.g.
SELECT DISTINCT
TABNAME
FROM
SYSCAT.TABLES
WHERE
TYPE='T'
AND REGEXP_LIKE(TABNAME,'.*_((ABS)|(ACCT))_.*')
Just in case.
Note, that the '_' character has special meaning in a pattern-expression of the LIKE predicate:
The underscore character (_) represents any single character.
The percent sign (%) represents a string of zero or more characters.
Any other character represents itself.
So, if you really need to find _ABS_ substring, you should use something like below.
You get both rows in the result, if you use the commented out pattern instead, which may not be desired.
with
pattern (str) as (values
'%\_ABS\_%'
--'%_ABS_%'
)
, tables (tabname) as (values
'A*ABS*A'
, 'A_ABS_A'
)
select tabname
from tables t
where exists (
select 1
from pattern p
where t.tabname like p.str escape '\'
);

Select the rows where variable x starts with 65 (teradata)

I have a table with a column named x that includes numbers for all my observations. I now want to select only the variables that start with 65.
I've tried:
SELECT * FROM table
WHERE x REGEXP '^[65]'
and different versions of like/isnumeric, but I cant figure a clean way out.
If this is actually a Teradata DBMS your inital query will result in an error message because there's no REGEXP (but there's a REGEXP_SIMILAR).
You don't need a regular expression to compare the first two digits. If the datatype of x is numeric you must cast it to a string first:
WHERE TRIM(x) LIKE '65%'
WHERE CAST(x AS VARCHAR(20)) LIKE '65%'
If it's a VarChar you might have some leading spaces (which are really bad):
WHERE TRIM(x) LIKE '65%'
You may use like or left to find start with prefix
SELECT * FROM TABLE_NAME WHERE COLUMN_NAME LIKE '65%'
or
SELECT * FROM TABLE_NAME WHERE LEFT(COLUMN_NAME, 2) = '65'
Tested and working.
SELECT * FROM someTable WHERE concat("_",x) like '_65%'
Could be slow if your table is very big, because it does not use the indexes and performs full table scan.

Conversion failed. SELECT * from Person.Address WHERE ISNUMERIC(PostalCode) =1 AND PostalCode<7000

It is Microsoft SQL Server.
In this column PostalCode from the AdventureWorks 2012 Person.Address table, there are numeric and string values.
I want to get table with rows WHERE PostalCode < 7000
This does not work as expected:
USE [AdventureWorks2012]
SELECT *
FROM Person.Address
WHERE ISNUMERIC(PostalCode) = 1
AND PostalCode < 7000
because I get this error:
Conversion failed when converting the nvarchar value 'K4B 1T7' to data type int.
I can make it, by creating temporally table like this:
/* creating of temp table */
USE AdventureWorks2012
SELECT *
INTO temp2
FROM Person.Address
WHERE ISNUMERIC(PostalCode) = 1
/* get data from temp table */
SELECT *
FROM temp2
WHERE PostalCode < 7000
But it is a bad way, cause of low productivity and needless temp-table.
What is the better way to get table with rows WHERE PostalCode < 7000 but data has not only numeric values?
If you're in SQL Server 2012 or newer you should use try_convert instead of isnumeric. Isnumeric has some funny issues that it returns 1 even for strings that can't be converted into a number. So something like this should work:
SELECT *
FROM Person.Address
WHERE try_convert(int, PostalCode) < 7000
If the string can't be converted, try_convert returns null.
MSDN: https://msdn.microsoft.com/en-us/library/hh230993.aspx
The error is being returned because the conditions being evaluated are not short-circuiting - the condition PostalCode<7000 is being evaluated even where the postal code is non-numeric.
Instead, try:
SELECT *
from Person.Address
WHERE CASE WHEN PostalCode NOT LIKE '%[^0-9]%'
THEN CAST(PostalCode AS NUMERIC)
ELSE CAST(NULL AS NUMERIC)
END <7000
(Updated following comments)
The text is from 70-461 Training kit
(Exam 70-461: Querying Microsoft SQL Server 2012):
Recall from Chapter 1 that all expressions that appear in the same
logical query processing phase—for example, the WHERE phase—are
conceptually evaluated at the same point in time. For example,
consider the following filter predicate.
WHERE propertytype = 'INT' AND CAST(propertyval AS INT) > 10
Suppose that the table being queried
holds different property values. The propertytype column represents
the type of the property (an INT, a DATE, and so on), and the
propertyval column holds the value in a character string. When
propertytype is 'INT', the value in propertyval is convertible to INT;
otherwise, not necessarily.
Some assume that unless precedence rules
dictate otherwise, predicates will be evaluated from left to right,
and that short circuiting will take place when possible. In other
words, if the first predicate propertytype = 'INT' evaluates to false,
SQL Server won’t evaluate the second predicate CAST(propertyval AS
INT) > 10 because the result is already known. Based on this
assumption, the expectation is that the query should never fail trying
to convert something that isn’t convertible.
The reality, though, is
different. SQL Server does internally support a short-circuit concept;
however, due to the all-at-once concept in the language, it is not
necessarily going to evaluate the expressions in left-to-right order.
It could decide, based on cost-related reasons, to start with the
second expression, and then if the second expression evaluates to
true, to evaluate the first expression as well. This means that if
there are rows in the table where propertytype is different than
'INT', and in those rows propertyval isn’t convertible to INT, the
query can fail due to a conversion error.
The only safe way of doing this is by getting first the Ids of the fields you are interested in and then join with them in different statements, otherwise the query planner could decide it want to do first the numeric comparison. I started to get a lot of this problems when we upgraded to SQL Server 2008 that didn't happened before.
You can however do a conversion:
USE [AdventureWorks2012]
SELECT *
from Person.Address
WHERE ISNUMERIC(PostalCode) =1 AND CAST(CAST(PostalCode AS INT) AS VARCHAR)<'7000'
I have done the castings to try to avoid any data that could be numeric but with 0 padding on the left that could screw up the ordering.
Beware that the performance of this won't be the best and Indexes on PostalCode aren't going to be used.
Here in Denmark, postal code always have the same length, so I would use this script to avoid strange issues* with isnumeric and conversion issues.
It will check that postalCode has 4 digits and compare the string value.
SELECT *
FROM temp2
WHERE
PostalCode < '7000' and
PostalCode like '[0-9][0-9][0-9][0-9]'
*An example of strange issues with isnumeric
SELECT isnumeric('£1.1')
SELECT isnumeric('-')
Both returns 1
You can use subquery to do that :
select * from (
SELECT * from Person.Address WHERE ISNUMERIC(PostalCode) =1 ) t
where PostalCode<7000

DB2 : issue with a subquery that contains a cast operator on clob field

I have an issue whith this query which doesn't work :
select count(*)
from MYTABLE where
MYFIELD in (select trim(cast(CLOBFIELD as varchar(20000))) from TABLE2) ;
=>0 rows
The subquery return right results :
select trim(cast(CLOBFIELD as varchar(20000))) from TABLE2 ;
=>1202,1203,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1226
This query which doesn't have the subquery returns right reusults.
select count(*)
from MYTABLE where
MYFIELD in (1202,1203,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1226) ;
The column CLOBFIELD is a CLOB field VS the column is a char(4) field.
In my opinion, this a cast issue in the subquery because of the cast on the clob field. I don't know what's wrong, I am not very familar with DB2, does anybody can help me ?
As comments above say, it isn't right to mess with casting large datatypes like this, but here is some code to try:
select count(*)
from MYTABLE
where LOCATE_IN_STRING((select ','||trim(cast(CLOBFIELD as varchar(20000)))||',' from TABLE2), ','||trim(MYFIELD)||',' ) > 0 ;
Can have problems if your values contain commas though.
Perhaps you could investigate applying a text search index? http://pic.dhe.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=%2Fcom.ibm.db2.luw.admin.ts.doc%2Fdoc%2Ft_creatingafulltextindex.html
However, if you need to access the values in the CLOB, perhaps they shouldn't be in a CLOB?

Flatten national characters in SQL Server

I have a column that contains pet names with national characters. How do I write the query to match them all in one condition?
|PetName|
Ćin
ćin
Ĉin
ĉin
Ċin
ċin
Čin
čin
sth like FLATTEN funciton here:
...WHERE LOWER(FLATTEN(PetName)) = 'cin'
Tried to cast it to from NVARCHAR to VARCHAR but it didn't help. I'd like to avoid using REPLACE for every character.
this should work because cyrillic collation base cases all diacritics like Đ,Ž,Ć,Č,Š,etc...
declare #t table(PetName nvarchar(100))
insert into #t
SELECT N'Ćin' union all
SELECT N'ćin' union all
SELECT N'Ĉin' union all
SELECT N'ĉin' union all
SELECT N'Ċin' union all
SELECT N'ċin' union all
SELECT N'Čin' union all
SELECT N'čin'
SELECT *
FROM #t
WHERE lower(PetName) = 'cin' COLLATE Cyrillic_General_CS_AI
You can change the collation used for the comparison:
WHERE PetName COLLATE Cyrillic_General_CI_AI = 'cin'
There isn't really a way or built-in function that will strip accents from characters.
If you are doing comparisons (LIKE, IN, PATINDEX etc), you can just force COLLATE if the column/db is not already accent insensitive.
Normally, a query like this
with test(col) as (
select 'Ćin' union all
select 'ćin')
select * from test
where col='cin'
will return both columns, since the default collation (unless you change it) is insensitive. This won't work for FULLTEXT indexes though.