LIKE using subquery returning multiple rows - sql

There 2 tables emailinfo(id,email) and keywordinfo(id,keyword).
emailinfo contains 80,000 rows and keywordinfo contains 2000 rows.
I want emails from emailinfo table which does not contains keywords from keywordinfo table.
I want not like condition on multiple rows
I have kept all keywords in keywordinfo table
Now I have to fetch all the emails from emailinfo table which not containing any keywords from keywordinfo table.
I want query like following,
select email
from emailinfo
where email not like % (select keyword from keywordinfo)
I have tried following query
SELECT email
FROM emailinfo
join keywordinfo on email like '%' + keyword +'%'**
but its not giving me proper results and is very slow.

How about a slight variation of your second query...?
SELECT Email
FROM EmailInfo
LEFT JOIN KeywordInfo ON Email LIKE '%' + Keyword + '%'
WHERE KeywordInfo.ID IS NULL
Example Data:
CREATE TABLE #EmailInfo (ID INT, Email VARCHAR(50))
INSERT INTO #EmailInfo (ID, Email) VALUES (1, 'test#example.com')
INSERT INTO #EmailInfo (ID, Email) VALUES (2, 'someone#sample.com')
INSERT INTO #EmailInfo (ID, Email) VALUES (3, 'testing#sample.com')
INSERT INTO #EmailInfo (ID, Email) VALUES (4, 'blahblah#blah.com')
INSERT INTO #EmailInfo (ID, Email) VALUES (5, 'example#email.com')
INSERT INTO #EmailInfo (ID, Email) VALUES (6, 'another#goodemail.com')
CREATE TABLE #KeywordInfo (ID INT, Keyword VARCHAR(50))
INSERT INTO #KeywordInfo (ID, Keyword) VALUES (1, 'sample')
INSERT INTO #KeywordInfo (ID, Keyword) VALUES (2, 'test')
SELECT Email
FROM #EmailInfo EmailInfo
LEFT JOIN #KeywordInfo KeywordInfo ON Email LIKE '%' + Keyword + '%'
WHERE KeywordInfo.ID IS NULL
DROP TABLE #EmailInfo
DROP TABLE #KeywordInfo

The following query will returns all the records from emailinfo table which don't have any keyword defined in keywordinfo table.
It's advisable to have an index on emailinfo.email fields to make the query execution faster.
SELECT * FROM emailinfo
where not exists (Select 1 from
keywordinfo where emailinfo.email like '%' + keywordinfo.keyword +'%')

An alternative formulation eliminates the like:
Select
From emailinfo ie
Where not exists (select *
From ki
Where charindex(ki.keyword, ie.email) > 0)
I apologize for the formatting, I'm on a mobile device.
I would also recommend that you change your table structures so each keyword is in a separate row. Then you won't need the like operator.

Instead of trying to come up with a scenario using LIKE, have you considered using FULL TEXT INDEXING?
Pinal Dave has a fairly good introduction on it that can help get you started: http://blog.sqlauthority.com/2008/09/05/sql-server-creating-full-text-catalog-and-index/

Related

SQL view / query to join data between 2 tables via a json field

Example table structure:
create table issues
(id int, title varchar(50), affectedclients varchar(max))
create table clients
(id int, name varchar(50))
insert into issues (id, title, affectedclients) values (1, 'Error when clicking save', '["1","2"]');
insert into issues (id, title, affectedclients) values (2, '404 error on url', '[3]');
insert into clients (id, name) values (1, 'Tesco');
insert into clients (id, name) values (2, 'Costa');
insert into clients (id, name) values (3, 'Boots');
insert into clients (id, name) values (4, 'Nandos');
I want to run a query so that I can get the data in the following format:
Id Title AffectedClients
1 Error when clicking save Tesco, Costa
2 404 error on url Boots
How can I achieve this please in the most performant way possible?
If this will be very easy with a properly normalized database then please provide an example.
You need to use OPENJSON() with explicit schema definition to parse the JSON text in the affectedclients column. After that you need to aggregate the names (using FOR XML PATH for SQL Server 2016+ or STRING_AGG() for SQL SQL Server 2017+).
Data:
create table issues
(id int, title varchar(50), affectedclients varchar(max))
create table clients
(id int, name varchar(50))
insert into issues (id, title, affectedclients) values (1, 'Error when clicking save', '["1","2"]');
insert into issues (id, title, affectedclients) values (2, '404 error on url', '[3]');
insert into clients (id, name) values (1, 'Tesco');
insert into clients (id, name) values (2, 'Costa');
insert into clients (id, name) values (3, 'Boots');
insert into clients (id, name) values (4, 'Nandos');
Statement for SQL Server 2016+:
SELECT
i.id,
i.title,
[affectedclients] = STUFF(
(
SELECT CONCAT(', ', c.[name])
FROM OPENJSON(i.affectedclients) WITH (id int '$') j
LEFT JOIN clients c on c.id = j.id
FOR XML PATH('')
), 1, 2, '')
FROM issues i
Statement for SQL Server 2017+:
SELECT i.id, i.title, STRING_AGG(c.name, ', ') AS affectedclients
FROM issues i
CROSS APPLY OPENJSON(i.affectedclients) WITH (id int '$') j
LEFT JOIN clients c ON c.id = j.id
GROUP BY i.id, i.title
ORDER BY i.id, i.title
Results:
-----------------------------------------------
id title affectedclients
-----------------------------------------------
1 Error when clicking save Tesco, Costa
2 404 error on url Boots

How to insert conditionally in Oracle?

I've read here that the syntax looks like this:
INSERT
WHEN ([Condition]) THEN
INTO [TableName] ([ColumnName])
VALUES ([VALUES])
ELSE
INTO [TableName] ([ColumnName])
VALUES ([VALUES])
SELECT [ColumnName] FROM [TableName];
But I don't want to provide values from another table. I just want to type them, so I've got:
INSERT
WHEN EXISTS (SELECT 1 FROM FOO WHERE NAME = 'JOE')
THEN
INTO BAR (NAME, AGE)
VALUES ('JOE', 50)
and this produces exception: ORA-00928: missing SELECT keyword.
I want to perform an insert if given value is found in another table.
Using with select works. Your query wasn't working because there is a problem with values keyword when inserting conditionally.
INSERT
WHEN EXISTS (SELECT 1 FROM FOO WHERE NAME = 'JOE')
THEN
INTO BAR (NAME, AGE)
SELECT 'JOE', 50 FROM DUAL
So, I've found an indirect way here and solution for my question would be:
INSERT INTO BAR (NAME, AGE)
SELECT 'JOE', 50
FROM DUAL
WHERE EXISTS (SELECT 1 FROM FOO WHERE NAME = 'JOE')
but it doesn't explain why I have to use SELECT statement in INSERT WHEN

The select list for the INSERT statement contains fewer items than the insert list (but is identical)

I am trying to develop a procedure that has this basic structure:
select a.*
into #temp1
from OPENQUERY(otherDB,'SELECT ... FROM ...')a
INSERT INTO [dbo].[Data]
(....)
select *
from #temp1
DROP TABLE #temp1
The amount of columns in the results from the OPENQUERY is identical to the INSERT columns
How could I be catching this error :
The select list for the INSERT statement contains fewer items than the insert list. The number of SELECT values must match the number of INSERT columns.
What if you try to make more specific the select? Example:
insert into dbo.data (col1,col2) select col1,col2.....

Insert a row if it doesn't exist via query

I am trying to write a query that will insert a group of people into a table if that person does not exist. For example, I have table full of people and I need to add more people into the database and I don't know if they are already there. I do know that the social security number (ssn) will never be the same for two people. Could a query be used to check if the ssn is in the table and if not insert the person into the table? If the ssn is in the table then go to the next person and check?
I was thinking about using a stored procedure, but I do not have any rights to create a store procedure.
You can insert your data into a table variable or temp table and then INSERT INTO table from temp table where it does not exists in your table.
DECLARE #Inserted AS TABLE
(
NAME VARCHAR(50)
,SSN DECIMAL(10, 0)
)
INSERT INTO #Inserted
( NAME, SSN )
VALUES ( 'Bob', 123456789 )
, ( 'John', 123546789 )
, ( 'James', 123456798 )
INSERT INTO MyTable
SELECT *
FROM #Inserted AS i
LEFT OUTER JOIN MyTable AS m
ON i.SSN = m.SSN
WHERE m.SSN IS NULL
Here are a couple ideas to get you started. I use MERGE a lot because it offers so much control. You could also look into the IN clause as part of a WHERE predicate in the INSERT SELECT statement.
MERGE
DECLARE #PERSONTABLE TABLE (ID INT PRIMARY KEY IDENTITY(1,1), FirstName VARCHAR(max))
INSERT INTO #PERSONTABLE (FirstName) VALUES ('Bill'),('Sally'),('Bob')
DECLARE #NEWPEOPLE TABLE (FirstName VARCHAR(max))
INSERT INTO #NEWPEOPLE (FirstName) VALUES ('Jim'), ('Sally')
--MERGE
MERGE INTO #PERSONTABLE AS T
USING #NEWPEOPLE AS S
ON (T.FirstName = S.FirstName)
WHEN NOT MATCHED BY TARGET THEN
INSERT (FirstName) VALUES (S.FirstName);
SELECT * FROM #PERSONTABLE
EXCEPT
DECLARE #PERSONTABLE TABLE (ID INT PRIMARY KEY IDENTITY(1,1), FirstName VARCHAR(max))
INSERT INTO #PERSONTABLE (FirstName) VALUES ('Bill'),('Sally'),('Bob')
DECLARE #NEWPEOPLE TABLE (FirstName VARCHAR(max))
INSERT INTO #NEWPEOPLE (FirstName) VALUES ('Jim'), ('Sally')
--EXCEPT
INSERT INTO #PERSONTABLE (FirstName)
SELECT FirstName FROM #NEWPEOPLE
EXCEPT
SELECT FirstName FROM #PERSONTABLE
SELECT * FROM #PERSONTABLE
You could do it like this if the new people are in another table. If not, then use Vladimir's solution.
INSERT INTO People(ssn, firstname, lastname)
SELECT ssn, firstname, lastname
FROM newpeople
WHERE ssn not in (select ssn from people )
INSERT INTO People(ssn, firstname, lastname)
SELECT np.ssn, np.firstname, np.lastname
FROM newpeople np
LEFT JOIN People p on np.ssn = p.ssn
WHERE p.ssn IS NULL
Here's another option I use a lot. Normally joins are better than sub-selects... if the joined table value is null you know you don't have a hit in the joined table.

INSERT IF NOT EXISTS with NULL value

I have two tables: tags and linking table photos_tags. I want to add a new tag, so I check if the tag is already in the tags table and if not I insert one. My tables look something like this: tags(id, name), photos_tags(photos_id, tags_id). Now I tried to do this with:
IF NOT EXISTS (SELECT * FROM tags WHERE name=*tagsName*)
INSERT INTO tags VALUES (NULL, *tagsName*); --NULL used for autonumbering
I've also tried:
INSERT INTO tags (
SELECT NULL, *tagsName*
WHERE NOT EXISTS (
SELECT * FROM tags
WHERE name=*tagsName*
)
);
Both statements result in syntax errors:
in the first statement near if
in the second statement near select
What should my query look like?
Create a UNIQUE constraint on tags.name and use this:
INSERT OR IGNORE
INTO tags (id, name)
VALUES (NULL, 'tagsName')
If for some reason you can't or don't want to do this, use this:
INSERT
INTO tags (id, name)
SELECT NULL, 'tagsName'
WHERE NOT EXISTS
(
SELECT NULL
FROM tags
WHERE name = 'tagsName'
)
INSERT INTO tags (name)
SELECT 'tagsName'
WHERE NOT EXISTS (SELECT 1 FROM tags WHERE name = 'tagsName');
OR
INSERT OR IGNORE
INTO tags (id, name)
VALUES (NULL, 'tagsName')
if you have a unique constraint