DB2 sql query run - sql

Trying to run some query for DB2, but get no results.
SELECT APPLICATION_ID,
CLIENT_WRKSTNNAME
FROM TABLE(MON_GET_CONNECTION(cast(NULL as bigint), -2)) AS t
WHERE APPLICATION_ID IN (SELECT ''''||APPLICATION_ID||''''
FROM SYSIBM.SYSDUMMY1)
The problem is in subquery in WHERE clause. If I'll run only the
SELECT ''''||APPLICATION_ID||''''
FROM SYSIBM.SYSDUMMY1
part and copy/paste the result into the big query - I would get needed result. Result of sub-query looks like this: '92.81.111.13.51632.13022516453', it must be String/varchar.
What am I doing wrong?

Your query does not make sense. Here is the version with table aliases:
SELECT t.APPLICATION_ID, t.CLIENT_WRKSTNNAME
FROM TABLE(MON_GET_CONNECTION(cast(NULL as bigint), -2)) AS t
WHERE t.APPLICATION_ID IN (SELECT ''''||t.APPLICATION_ID||'''' FROM SYSIBM.SYSDUMMY1);
One possibility is that the field APPLICATION_ID is being compared to itself, with quotes. SYSIBM.SYSDUMMY1 does not have a column called APPLICATION_ID. So, this query is equivalent to:
SELECT t.APPLICATION_ID, t.CLIENT_WRKSTNNAME
FROM TABLE(MON_GET_CONNECTION(cast(NULL as bigint), -2)) AS t
WHERE t.APPLICATION_ID = ''''||t.APPLICATION_ID||'''' ;
Another possibility is that APPLICATION_ID is a variable. In that case, you should name the variable something like v_APPLICATION_ID so it is not confused with the column name.
It looks like you want something like:
WHERE '.'||t.APPLICATION_ID||'.' like '%.'||v_APPLICATION_IDS||'.%' ;
This is assuming the list in v_APPLICATION_IDS is separated by periods. Usually, it would be separated by commas and you would use ',' instead of '.'.

WITH s AS (SELECT APPLICATION_ID AS application_id FROM SYSIBM.SYSDUMMY1)
SELECT CLIENT_WRKSTNNAME
FROM TABLE(MON_GET_CONNECTION(cast(NULL as bigint), -2)) AS t
INNER join s as s on s.application_id=t.APPLICATION_ID

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 TableData where ColumnData start with list of strings

Following is the query to select column data from table, where column data starts with a OR b OR c. But the answer i am looking for is to Select data which starts with List of Strings.
SELECT * FROM Table WHERE Name LIKE '[abc]%'
But i want something like
SELECT * FROM Table WHERE Name LIKE '[ab,ac,ad,ae]%'
Can anybody suggest what is the best way of selecting column data which starts with list of String, I don't want to use OR operator, List of strings specifically.
The most general solution you would have to use is this:
SELECT *
FROM Table
WHERE Name LIKE 'ab%' OR Name LIKE 'ac%' OR Name LIKE 'ad%' OR Name LIKE 'ae%';
However, certain databases offer some regex support which you might be able to use. For example, in SQL Server you could write:
SELECT *
FROM Table
WHERE NAME LIKE 'a[bcde]%';
MySQL has a REGEXP operator which supports regex LIKE operations, and you could write:
SELECT *
FROM Table
WHERE NAME REGEXP '^a[bcde]';
Oracle and Postgres also have regex like support.
To add to Tim's answer, another approach could be to join your table with a sub-query of those values:
SELECT *
FROM mytable t
JOIN (SELECT 'ab' AS value
UNION ALL
SELECT 'ac'
UNION ALL
SELECT 'ad'
UNION ALL
SELECT 'ae') v ON t.vame LIKE v.value || '%'

select where substring

SQL newbie here, but I can't find the solution to something that looks easy:
The following query does not seem to have a valid syntax (ORA-00904: invalid identifier), but its logic should be clear. How can I achieve this in a query that needs to be speedy?
SELECT * FROM table WHERE LEFT(column,4)="abcd"
For this purpose, you should use like rather than left(). First, Oracle doesn't support left() (you need substr() instead). Second, like can make use of indexes because the wildcard is not at the beginning of the string:
SELECT *
FROM table
WHERE column like 'abcd%';
Oracle and some other products have substr.
SELECT * FROM tablename WHERE substr(columnname, 1, 4) = 'abcd'
I.e. single quotes for string literals!
ANSI SQL has substring:
SELECT * FROM tablename WHERE substring(columnname from 1 for 4) = 'abcd'
And others have left:
SELECT * FROM tablename WHERE LEFT(columnname,4) = 'abcd'

Compare Items in the "IN" Clause and the resultset

I'd like to achieve something as follows, I have the following query (As simple as this),
SELECT ENT_ID,TP_ID FROM TC_LOGS WHERE ENT_ID IN (1,2,3,4,5).
Now the table TC_LOGS may not have all the items in the IN clause. So assuming that the table TC_LOGS has only 1,2. I'd like to compare the items in the IN clause i.e. 1,2,3,4,5 with 1,2(the resultset) and get a result as FOUND - 1,2 NOT FOUND - 3,4,5. I've have implemented this by applying an XSL transformation on the resultset in the application code, but I'd like to achieve this in a query, which I feel is more of an elegant solution to this problem. Also, I tried the following query with NVL, just to separate out the FOUND and NOT FOUND items as,
SELECT NVL(ENT_ID,"NOT FOUND") FROM TC_LOGS WHERE ENT_ID IN(1,2,3,4,5)
I was expecting a result as 1,2,NOT FOUND,NOT FOUND,NOT FOUND
But the above query doesn't return any result.. I'd appreciate if someone can guide me in the right path here.. Thanks much in advance.
Assuming that the items in your IN list can (or can come) from another query, you can do something like
WITH src AS (
SELECT level id
FROM dual
CONNECT BY level <= 5)
SELECT nvl(ent_id, 'Not Found' )
FROM src
LEFT OUTER JOIN tc_logs ON (src.id = tc_logs.ent_id)
In my case, the src query is just generating the numbers 1 through 5. You could just as easily fetch that data from a different table, load the numbers into a collection that you query using the TABLE operator, load the numbers into a temporary table that you query, etc. depending on how the IN list data is determined.
NVL isn't going to work because no values (including NULLS) are returned when there is no match with the IN statement.
What you can do is something like this:
SELECT NVL(ENT_ID, "NOT FOUND")
FROM TC_LOGS
RIGHT OUTER JOIN (
SELECT 1 AS 'TempID' UNION
SELECT 2 UNION
SELECT 3 UNION
SELECT 4 UNION
SELECT 5) AS Sub ON ENT_ID = TempID
The outer join will return NULLS for ENT_ID where there are no matches. Note, I'm not an Oracle person so I can't guarantee that this syntax is perfect.
if you have a table (let's use table src )contains all (1,2,3,4,5) values, you can use full join.
You can use (WITH src AS ( SELECT level id FROM dual CONNECT BY level <= 5) as the src table also)
SELECT
ent_id,tl.tp_id,src.tp_id
FROM
src
FULL JOIN
tc_logs tl
USING (ent_id)
ORDER BY
ent_id
Here is the web site for oracle full join.http://psoug.org/snippet/Oracle-PL-SQL-ANSI-Joins-FULL-JOIN_738.htm

Using LIKE in an Oracle IN clause

I know I can write a query that will return all rows that contain any number of values in a given column, like so:
Select * from tbl where my_col in (val1, val2, val3,... valn)
but if val1, for example, can appear anywhere in my_col, which has datatype varchar(300), I might instead write:
select * from tbl where my_col LIKE '%val1%'
Is there a way of combing these two techniques. I need to search for some 30 possible values that may appear anywhere in the free-form text of the column.
Combining these two statements in the following ways does not seem to work:
select * from tbl where my_col LIKE ('%val1%', '%val2%', 'val3%',....)
select * from tbl where my_col in ('%val1%', '%val2%', 'val3%',....)
What would be useful here would be a LIKE ANY predicate as is available in PostgreSQL
SELECT *
FROM tbl
WHERE my_col LIKE ANY (ARRAY['%val1%', '%val2%', '%val3%', ...])
Unfortunately, that syntax is not available in Oracle. You can expand the quantified comparison predicate using OR, however:
SELECT *
FROM tbl
WHERE my_col LIKE '%val1%' OR my_col LIKE '%val2%' OR my_col LIKE '%val3%', ...
Or alternatively, create a semi join using an EXISTS predicate and an auxiliary array data structure (see this question for details):
SELECT *
FROM tbl t
WHERE EXISTS (
SELECT 1
-- Alternatively, store those values in a temp table:
FROM TABLE (sys.ora_mining_varchar2_nt('%val1%', '%val2%', '%val3%'/*, ...*/))
WHERE t.my_col LIKE column_value
)
For true full-text search, you might want to look at Oracle Text: http://www.oracle.com/technetwork/database/enterprise-edition/index-098492.html
A REGEXP_LIKE will do a case-insensitive regexp search.
select * from Users where Regexp_Like (User_Name, 'karl|anders|leif','i')
This will be executed as a full table scan - just as the LIKE or solution, so the performance will be really bad if the table is not small. If it's not used often at all, it might be ok.
If you need some kind of performance, you will need Oracle Text (or some external indexer).
To get substring indexing with Oracle Text you will need a CONTEXT index. It's a bit involved as it's made for indexing large documents and text using a lot of smarts. If you have particular needs, such as substring searches in numbers and all words (including "the" "an" "a", spaces, etc) , you need to create custom lexers to remove some of the smart stuff...
If you insert a lot of data, Oracle Text will not make things faster, especially if you need the index to be updated within the transactions and not periodically.
No, you cannot do this. The values in the IN clause must be exact matches. You could modify the select thusly:
SELECT *
FROM tbl
WHERE my_col LIKE %val1%
OR my_col LIKE %val2%
OR my_col LIKE %val3%
...
If the val1, val2, val3... are similar enough, you might be able to use regular expressions in the REGEXP_LIKE operator.
Yes, you can use this query (Instead of 'Specialist' and 'Developer', type any strings you want separated by comma and change employees table with your table)
SELECT * FROM employees em
WHERE EXISTS (select 1 from table(sys.dbms_debug_vc2coll('Specialist', 'Developer')) mt
where em.job like ('%' || mt.column_value || '%'));
Why my query is better than the accepted answer: You don't need a CREATE TABLE permission to run it. This can be executed with just SELECT permissions.
In Oracle you can use regexp_like as follows:
select *
from table_name
where regexp_like (name, '^(value-1|value-2|value-3....)');
The caret (^) operator to indicate a beginning-of-line character &
The pipe (|) operator to indicate OR operation.
This one is pretty fast :
select * from listofvalue l
inner join tbl on tbl.mycol like '%' || l.value || '%'
Just to add on #Lukas Eder answer.
An improvement to avoid creating tables and inserting values
(we could use select from dual and unpivot to achieve the same result "on the fly"):
with all_likes as
(select * from
(select '%val1%' like_1, '%val2%' like_2, '%val3%' like_3, '%val4%' as like_4, '%val5%' as like_5 from dual)
unpivot (
united_columns for subquery_column in ("LIKE_1", "LIKE_2", "LIKE_3", "LIKE_4", "LIKE_5"))
)
select * from tbl
where exists (select 1 from all_likes where tbl.my_col like all_likes.united_columns)
I prefer this
WHERE CASE WHEN my_col LIKE '%val1%' THEN 1
WHEN my_col LIKE '%val2%' THEN 1
WHEN my_col LIKE '%val3%' THEN 1
ELSE 0
END = 1
I'm not saying it's optimal but it works and it's easily understood. Most of my queries are adhoc used once so performance is generally not an issue for me.
select * from tbl
where exists (select 1 from all_likes where all_likes.value = substr(tbl.my_col,0, length(tbl.my_col)))
You can put your values in ODCIVARCHAR2LIST and then join it as a regular table.
select tabl1.* FROM tabl1 LEFT JOIN
(select column_value txt from table(sys.ODCIVARCHAR2LIST
('%val1%','%val2%','%val3%')
)) Vals ON tabl1.column LIKE Vals.txt WHERE Vals.txt IS NOT NULL
You don't need a collection type as mentioned in https://stackoverflow.com/a/6074261/802058. Just use an subquery:
SELECT *
FROM tbl t
WHERE EXISTS (
SELECT 1
FROM (
SELECT 'val1%' AS val FROM dual
UNION ALL
SELECT 'val2%' AS val FROM dual
-- ...
-- or simply use an subquery here
)
WHERE t.my_col LIKE val
)