"NOT IN" subquery with a leading wildcard - sql

I have two tables:
Table tablefoo contains a column fulldata.
Table tablebar contains a column partialdata.
I want find a list of tablefoo.fulldata that do NOT have partial matches in tablebar.partialdata.
The following provides a list of tablefoo.fulldata with partial matches in tablebar, but I want the negative of this.
select fulldata from tablefoo
where fulldata like any (select '%' || partialdata from tablebar);
This lists every record in partialdata:
select fulldata from tablefoow
where partialdata not in (select '%' || partialdata from tablebar);
Any idea how to get only the results tablefoo.fulldata that do not contain matches to a leading wildcarded tablebar.partialdata?
I found this link: PostgreSQL 'NOT IN' and subquery which seems like it's headed down the right path, but I'm not getting it to work with the wildcard.
Sure, I could write a script to pull this out of psql and do the comparisons, but it would be much nicer to handle this all as part of the query.

SELECT fulldata
FROM tablefoo f
WHERE NOT EXISTS (
SELECT 1
FROM tablebar b
WHERE f.fulldata LIKE ('%' || b.partialdata)
);

Related

Can you explain the following SQL (postgres) code?

I asked SO for a query to find all rows in a table with a 'code' entry that is a substring of the search string, with the added condition that it appears at the end of the search string.
So a query for '12345' should return '2345', '345', '45', and '5'.
I was given this answer, which works. I have read through the documentation but still don't understand the query. Can someone please explain
SELECT * from yourtable
where '12345' like '%' || Code
Normally a LIKE is used in the opposite way.
For example:
SELECT * FROM SomeTable
WHERE SomeColumn LIKE '%xxx%'
So you check if the column matches against a fixed string with a pattern.
But the clever thing about that answer was it did the opposite.
It checks a fixed string again a pattern that's created from a column.
SELECT * FROM SomeTable
WHERE 'bar456' LIKE '%' || SomeColumn;
In this example, if "SomeColumn" contains the value "56"?
Then '%' || SomeColumn forms the string '%56'
So 'bar456' is like '%56', since it ends with '56'
And 'bar456' is also like '%ar456'
There are two relevant documentation links you need:
PostgreSQL Pattern Matching: '12345' like '%'
PostgreSQL CONCATENATE(||) Operator: <match> || Code
The SQL means:
Fetch all columns from the table
IF column "code" is equal to <match> + <value of "code" column>

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 '\'
);

SQL: finding similar rows to other same table in special column

I am using SQLITE for running this query:
SELECT * FROM phrases1, phrases2 WHERE phrases1.word LIKE ('%' +phrases2.word+ '%')
but not works.
two tables phrases1, phrases2 are same and have column name word and I want to filter the first table by rows that word column is similar to the word column of second table . while this works:
SELECT * FROM phrases1, phrases2 WHERE phrases1.word LIKE phrases2.word
but I want to use wildcards.
The SQLite operator for string concatenation is || not +:
SELECT * FROM phrases1, phrases2
WHERE phrases1.word LIKE '%' || phrases2.word || '%'
Also I don't know what the effect of having parentheses around your LIKE expression would be, but you don't need them there. But you should really write your query using explicit joins, better yet use aliases too:
SELECT *
FROM phrases1 p1
INNER JOIN phrases2 p2
ON p1.word LIKE '%' || p2.word || '%'

Completing a given SQL statement so that another column is displayed in the end

I'm given the following statement:
SELECT id FROM record_database WHERE id = <up to me to complete the statement>
The record database has different fields, among which are id and name.
I'm supposed to complete this select statement so that it displays all the ids and all the corresponding names side by side, and this should be done using this one line of SQL code. A hint was given that UNION or OR can be used.
I tried variations of the following:
SELECT id FROM record_database WHERE id = '*'
UNION
SELECT name FROM record_database WHERE name = '*';
But none of these worked. I tried doing this with AND, tried using display columns, but those didn't work either.
Any help would be appreciated.
This smells a great deal like homework, so I won't offer a complete answer, but you can't just union queries that return dissimilar result sets. I'm inferring that ID is an integer while NAME is some varchar, which won't union as you've listed in your hint.
When you say "complete," are you restricted to adding things to the end? If so, its a non-starter. You can't increase the list of fields being returned merely by adding things to the "WHERE" clause. You need to add things to the actual field list to get them to be returned, so you might clarify whether you are truly restricted to appending to the query you;ve given.
If you are looking for:
id
name
id next
name next
Then use this trick:
SELECT col2
FROM (
SELECT id, col2=convert ( varchar (size of name field),id)
FROM table
WHERE ....
UNION ALL
SELECT id, name
FROM table
WHERE ....
)
ORDER BY id
This order by will bring id and name side by side and col2 will contain id in first row and name in second row.
Cheating. Make the select return 0 rows and add another one that will show 2 columns. All in one and the same line:
SELECT id FROM record_database WHERE id = NULL;SELECT id,name FROM record_database;
No more time should be wasted on silly problems like this.
If both id and name are char (or varchar), you could also do this, concatting the two columns into one:
SELECT id FROM record_database WHERE id = NULL
UNION ALL
SELECT id || '--' || name FROM record_database ;
The id || '--' || name part differs from one DBMS to another. In some, the + is the concat operator, in others there are special functions. So you may need to use:
id + '--' + name
or:
CONCAT(id, '--', name)
Try this
SELECT * FROM record_database WHERE id = '*' OR name = '*'

SQL join question

I have a table table_a with a column containing data as follows:
.aaa01932
.asd02343
.lkj03342
So it always starts with a period followed by 3 letters, followed by 2 number (01, 02 etc) followed by some extra numbers.
I have another table table_b with data as follows:
aaa01
asd02
lkj03
So it maps to the data in table_a but with the period and the extra numbers at the end omitted.
How do I select from table_a joining on table_b where the data in the shown columns are "equal". By equal I mean that table_a.the_column like '%table_b.the_column%'. So something like:
Select * from table_a
join table_b on (table_a.the_column like '%table_b.the_column%');
Except I don't know how to format that like clause to accept a column inside. Maybe I need to concatenate it in somehow?
The syntax for the LIKE would be:
table_a.the_column like '%' || table_b.the_column || '%'
An alternative would be SUBSTR:
table_b.the_column = substr(table_a.the_column,2,5)
As some comments have said, the SUBSTR is a better method for 2 reasons:
It can be indexed:
create index on table_a (substr(the_column,2,5));
It is more accurate: you want to match only in that position, not anywhere in the column
Try this:
Select * from table_a
join table_b on (table_a.the_column like '%' || table_b.the_column || '%');
join table_b on substr(table_a.column,1) = table_b.column