SQL query Where clause problem - sql

I am having trouble finding a query.
I have a table 'NotificationExcludes' that contains 1 column 'Name'.
I have a table 'NotificationEvents' that contains columns: Id, Description.
Now I need to select all the NotificationEvents where the description doesn't start with the values contained in 'NotificationExcludes'.
Small example:
NotificationExcludes contains:
Name
The instance was terminated by
NotificationEvents:
ID Description
1 There was a failure on ..
2 The instance was terminated by administrator
Now I need to select everything except if the description starts with a value that is kept in the 'NotificationExcludes'.
I have tried
Select Id, Description
from NotificationEvent
WHERE Description NOT IN (select Name form NotificationExcludes)
But 2 problems with that:
1 The query obviously fails because 'select Name form NotificationExcludes' returns more than 1 record
2 The statement should contain a Like statement where I can use the '%' key. So where description not like 'The instance was terminated by%' can be used somehow

SELECT Id,Description
FROM NotificationEvents ne
WHERE NOT EXISTS(SELECT *
FROM NotificationExcludes nx
WHERE ne.Description
LIKE nx.name + '%') /*<--Might need Concat or || here
dependant upon RDBMS*/

One solution is to JOIN with a LIKE clause on name, appended with %.
SELECT *
FROM NotificationEvents ne
LEFT OUTER JOIN NotificationExcludes nex
ON ne.Description LIKE nex.Name + '%'
WHERE nex.Name IS NULL

Related

How can you use a string variable that has SQL inside a SQL LIKE wildcard pattern expression?

I have a SELECT statement with a WHERE clause that uses a LIKE wildcard with an expression coming from a variable string that I have built using values from a table. However, although there are no errors, the query is not evaluating correctly to give the expected results, as it is returning all the results records and not applying the condition in the LIKE wildcard. The desired result should be fewer records returned as they will be filtered against the LIKE wildcard expression.
The variable I have built to use in the SQL query's LIKE wildcard is the following, along with the value of the string:
Declare #TrimmedAgeType Varchar(450);
The value is this: '%J%' AND PERM.AgeFilter NOT LIKE '%JS%'
The SQL query looks like this:
SELECT * FROM #MembershipInfo #PSP
INNER JOIN TRP_ME_PriceStructure PERM
ON #PSP.MembershipPriceStructurePK = PERM.MembershipPriceStructurePK
WHERE PERM.AgeFilter NOT LIKE + #TrimmedAgeType
When I hardcode the query with the string value below, I get the expected results returned back.
SELECT * FROM #MembershipInfo #PSP
INNER JOIN TRP_ME_PriceStructure PERM
ON #PSP.MembershipPriceStructurePK = PERM.MembershipPriceStructurePK
WHERE PERM.AgeFilter NOT LIKE + '%J%' AND PERM.AgeFilter NOT LIKE '%JS%'
If you want to know how I am initially building the string variable value, see below:
Declare #AgeType Varchar(450);
Declare #AgeReference varchar(450)
SET #AgeType = CONCAT(#AgeType, '''%' + #AgeReference + '%''') + ' AND PERM.AgeFilter NOT LIKE '
Additional Info:
This #AgeType variable is being generated inside a while loop
that is looping through a table of Age References. I later change the
name of the variable to #TrimmedAgeType as I do some additional work on it to remove the last
occurrence of ' AND PERM.AgeFilter NOT LIKE '
More Info:
I have a table of memberships with the AgeFilter column containing letter references ('A,U,J,C,JS', etc). I want to return all results that do not match the given references in the LIKE wildcard pattern. This is because the SELECT query is actually going to be a DELETE query and I will delete all records that are returned and do not match the given references in the LIKE wildcard pattern.
Hope someone can help. Thank you.
Let's say we have some filters stored here:
CREATE TABLE dbo.FilterPatterns
(
PatternID int PRIMARY KEY,
FilterPattern varchar(32) NOT NULL UNIQUE
);
To simulate the question, let's say we know the PatternID values we're after are 1 and 3:
INSERT dbo.FilterPatterns(PatternID, FilterPattern)
VALUES(1,'%J%'),(2,'%Q%'),(3,'%JS%');
We've got some members stored in a #temp table for reasons unknown (how is that populated?):
CREATE TABLE #MembershipInfo
(
MembershipPriceStructurePK int PRIMARY KEY
);
Let's insert a few rows to match and not match (note: 30 doesn't exist in the core table).
INSERT #MemberShipInfo VALUES(5),(10),(15),(20),(30);
Two of these will have matching age filters in the core table, the other two will not. We'll also add a row not in the temp table (25):
CREATE TABLE dbo.TRP_ME_PriceStructure
(
MembershipPriceStructurePK int PRIMARY KEY,
AgeFilter varchar(256)
);
INSERT dbo.TRP_ME_PriceStructure VALUES
(5,'foo'),(10,'BobJoined'),(15,'blat'),(20,'NodeJS'),(25,'funky');
Now our query can just do a NOT EXISTS against the filter patterns table using whatever logic you're currently using to pull values from that table to build the string:
SELECT * FROM #MembershipInfo #PSP
INNER JOIN dbo.TRP_ME_PriceStructure PERM
ON #PSP.MembershipPriceStructurePK = PERM.MembershipPriceStructurePK
WHERE NOT EXISTS
(SELECT 1 FROM
dbo.FilterPatterns AS fp
WHERE fp.PatternID IN (1,3)
AND PERM.AgeFilter LIKE fp.FilterPattern);
members 5 and 15 are returned
members 10 and 20 are left out because they matched the filter
members 25 and 30 are left out because they miss the join
Example db<>fiddle
Try to hard code the wildcard
SELECT * FROM #MembershipInfo #PSP
INNER JOIN TRP_ME_PriceStructure PERM
ON #PSP.MembershipPriceStructurePK =
PERM.MembershipPriceStructurePK
WHERE PERM.AgeFilter NOT LIKE + '%'+ #TrimmedAgeType + '%'
Using Dynamic SQL I have successfully written the query, returning me the expected results:
DECLARE #DeleteUnsuitableMemberships varchar(MAX)
SET #DeleteUnsuitableMemberships =
'DELETE #MembershipInfo FROM #MembershipInfo #PSP
INNER JOIN TRP_ME_PriceStructure PERM
ON #PSP.MembershipPriceStructurePK = PERM.MembershipPriceStructurePK
WHERE PERM.AgeFilter NOT LIKE ' + #TrimmedAgeType
EXEC(#DeleteUnsuitableMemberships)
I did was the following:
Declare a new variable.
Set that variable to the SQL query which I have wrapped in apostrophe (').
Appended the variable using the + operator.
Used the EXEC() function with the variable placed inside as a parameter.
The value of #TrimmedAgeType is still '%J%' AND PERM.AgeFilter NOT LIKE '%JS%'
Thank you all for helping.

HSQL execute condition LIKE ANY

I'm trying to execute an SQL statement, with a where clause that does something like:
WHERE col LIKE ANY (values...)
According to the HSQLDB documentation it seems to me that I should be able to do it:
condition
{ ...
| value [NOT] LIKE value [ESCAPE] value }
value
[+ | -] { term [{ + | - | * | / | || } term]
| ( condition )
| function ( [parameter] [,...] )
| selectStatement giving one value
| {ANY|ALL} (selectStatement giving single column)
However, this does not seem to work.
I can execute this:
SELECT * FROM table WHERE col LIKE (selectStatement giving 1 column with single value)
But any of these will give me an error:
SELECT * FROM table WHERE col LIKE (selectStatement giving 1 column with multiple values)
-> cardinality violation
SELECT * FROM table WHERE col LIKE ANY (selectStatement giving 1 column with single value)
SELECT * FROM table WHERE col LIKE ANY (selectStatement giving 1 column with multiple values)
-> unexpected token: SELECT
Can you help me understand what I'm doing wrong?
Is this not supported, or am I misunderstanding the documentation?
Thanks!
Depending on what you want to achieve, you can use the following:
This query uses the value returned by the subquery for LIKE comparison. The value normally has a escape character, for example super%, which matches all words beginning with super:
SELECT * FROM table WHERE col LIKE (selectStatement giving 1 column with single value)
This query uses the values returned by the subquery as a list. Each of the list values is compared to the col value and when the first exact match is found, the result is true. This type of query is used to return a subset of the rows from the table that have a value that is in the list returned by the subquery:
SELECT * FROM table WHERE col = ANY (selectStatement giving 1 column with multiple values)
I am late to the game here, but would like to add the idea of a colleague of mine to use EXISTS() to allow multiple LIKE/ILIKE conditions.
So that query simulates the "x LIKE ANY('{}')"
SELECT
tables.table_name
FROM
information_schema.tables
WHERE
EXISTS(SELECT *
FROM
UNNEST (ARRAY['a%', 'b%', 'c%']) AS t(like_value)
WHERE
LOWER(tables.table_name) LIKE LOWER(like_value))
ORDER BY
tables.table_name
is equivalent to that in Postgresql
SELECT
tables.table_name
FROM
information_schema.tables
WHERE
tables.table_name ILIKE ANY ('{a%, b%, c%}')
ORDER BY
tables.table_name
Additionally, if you would like to use that from Java using prepared statements and to prevent Hsqldb from throwing a "General error" you have to cast the placeholder like so:
SELECT
tables.table_name
FROM
information_schema.tables
WHERE
EXISTS(SELECT *
FROM
UNNEST (CAST(? as VARCHAR(2048) ARRAY)) AS t(like_value)
WHERE
LOWER(tables.table_name) LIKE LOWER(like_value))
ORDER BY
tables.table_name

Is it possible to have a where with a select statement which you add wildcards to

I have a situation where I need to use a select statement in a where but then also append and prepend wildcards to the value it returns. E.g something like:
select * from [Customers.customervisibility] where userId like '%,' (Select Id from [Users.Users] where name ='MyName') ',%'
but running this gives:
Incorrect syntax near ',%'.
Now the Select Statement is only ever going to return 1 id, so I don't know if there is a better way to write it maybe using a function.
The overall goal is so that I can select the rows from [customer.customervisibility] where the id is contained in a comma seperated string column [UserId]
e.g. if id = 8
I need to get the rows where *,8,*...
It has to be inline, I cannot use variable, and you will have to excuse the TERRIBLE database design. this is so that it will work with third party software
Try this where clause
If your DBMS support Concat the use this.
userId like concat('%' ,(Select top 1 cast(Id as varchar(50)) from [Users.Users] where name ='MyName') ,'%')
Else
userId like '%' +(Select top 1 cast(Id as varchar(50)) from [Users.Users] where name ='MyName') +'%'
I have used Top 1 to avoid sub-query returns more than one row error if in case your subquery returns more than one row
You seem to have forgotten the concatenation character + for strings. Try below query:
select * from [Customers.customervisibility] where userId like '%,'+(Select Id from [Users.Users] where name ='MyName')+',%'
This will give results whose userId contains your Id where userId is a comma separated string.
SELECT *
FROM [Customers.customervisibility]
WHERE (userId LIKE '% , Select Id from [Users.Users] where status="MyName" %')
Try this:
select * from [Customers.customervisibility] where convert(VARCHAR(100),userId) like '%'+(Select Id from [Users.Users] where name ='MyName')+'%'

Where the value of one column is contained in the value of another column

I'm trying to write a query which compares two tables and finds all entries where one field is contained in another field. For example one field contains a single 5 digit login ID eg 12345. The second field contains one or multiple IDs seperated by commas but with the characters text^ in front eg text^12345 or text^12345,54321,13579,97531
If I try
Select * from table1.login_id a
join table2.login_id b
on b.login_id LIKE '%' + a.login_id + '%'
I am finding is that it is only joining on the last entry in the list. So if a.login_id = 12345 it only brings back where b.login_id = text^12345 or text^54321,12345 but not text^12345,54321
Am I just missing something?
Note: I am using SQL Server 2008, so the query can't use CONCAT.
You need to use CONCAT() to assemble your string:
Select * from table1.login_id a
join table2.login_id b
on b.login_id LIKE CONCAT('%', a.login_id, '%')
Perhaps a where exists is appropriate:
select * from table1 as a where exists (
select b.login_id from table2 as b where a.login_id like concat('%', b.login_id, '%')
);
You are missing something. Your issue is not reproducible.
When I run the following:
DECLARE #Table1 TABLE (login_id varchar(255));
DECLARE #Table2 TABLE (login_id varchar(255));
INSERT INTO #Table1 VALUES ('12345');
INSERT INTO #Table2 VALUES ('text^12345,54321');
Select * from #Table1 a
join #Table2 b
on b.login_id LIKE '%' + a.login_id + '%';
I get:
login_id | login_id
12345 | text^12345,54321
So when you say
it only brings back where b.login_id = text^12345 or text^54321,12345
but not text^12345,54321
You are wrong. It does bring that text back. Find the difference between the query you posted in your question, and the actual query you are using, and you will find what you are missing. Or if there is no difference in the query, then the difference is in the data. The data in your question may not be comparable to your actual data.

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 = '*'