query inside like operator - sql

Can I use query inside the like operator.
I used the query below, but it returns error.
select *
from customers
where cust_name like '%'||select name from members||'%'

Something like the following should work :
SELECT
*
FROM
customers c
WHERE 1=1
AND EXISTS
(SELECT 1
FROM members m
WHERE 1=1
AND c.cust_name LIKE '%'||m.name||'%'
)

In PLSQL if you want to run a Query then you need to decalre a variable to hold the result of the query. So you can do it as :
DECLARE
var customers%ROWTYPE;
BEGIN
SELECT c.*
INTO var
FROM customers c
INNER JOIN members m ON c.cust_name LIKE '%' || m.name || '%';
END;

it is sufficient to enclose the subquery in parentheses
like as
cust_name like '%'||(select name from members)||'%'
but this only works when the table "members" has only one record

You should define the name part of members in subselect (works with only 1 row):
select *
from customers
where cust_name like (select '%'||name||'%' from members);
Same can be done with JOIN (works with multiple rows):
select C.*
from customers C
INNER JOIN MEMBERS M ON (C.CUST_NAME LIKE '%'||M.NAME||'%');

Related

SQL query to get rows contains value of another query

I have 2 tables transaction and query. Transaction table have unique tid and the query table has tid_(subtransactionid).
I want to get the list of all subtransactions by using tid.
I tried this
select *
from queries, transactions
where queries.id like 'transactions.tid%' and transactions.uid = 'NfPgWM1igYh2y2hDKrLWLOxyI6u1'
You can join the tables and use the operator LIKE in the ON clause:
select q.*
from queries q inner join transactions t
on q.tid like concat(t.tid, '%')
where t.uid = 'NfPgWM1igYh2y2hDKrLWLOxyI6u1'
If your database does not support the function concat() then you can use either:
on q.tid like t.tid || '%'
or:
on q.tid like t.tid + '%'

How to search if a row is a substring of another row of the same column in Oracle

I have a table that contains millions of rows for names of customers as a column. I want to find if a part of a name exists within another row in the same column.
E.g. If a row has value 'Roger Federer' and there are other rows with values, 'Roger' and 'Federer', I want the corresponding primary keys of all the three rows.
You can leverage the use of REGEXP_LIKE
SELECT *
FROM customers
WHERE REGEXP_LIKE (cust_name, 'roger|federer','i')
SQL Fiddle Demo
More examples of REGEXP_LIKE usages can be found here
Another option would be the use of OR
SELECT *
FROM customers
WHERE LOWER(cust_name) LIKE LOWER('%roger%')
OR LOWER(cust_name) LIKE LOWER('%federer%')
SQL Fiddle Demo
Edit
With the use of JOIN, the search string is dynamic. If proper indexes are in place, then it would not have much impact.
SELECT DISTINCT
c1.*
FROM
customers c1
JOIN
customers c2
ON ( LOWER(c1.cust_name) LIKE LOWER(c2.cust_name || '%')
AND c1.cust_id != c2.cust_id)
SQL Fiddle Demo
Edit 2
Perhaps something like the below
SELECT DISTINCT
c1.cust_id,
c1.cust_name,
CASE
WHEN
LOWER(c1.cust_name) LIKE LOWER(c2.cust_name || '%')
THEN
'Matched'
ELSE
'Unmatched'
END
ident
FROM
customers c1
JOIN
customers c2
ON ( LOWER(c1.cust_name) LIKE LOWER(c2.cust_name || '%')
AND c1.cust_id != c2.cust_id)
SQL Fiddle Demo
If you want to construct a logic related to rows, union concepts may suit well,
by the way, in string operations we'd better use collations with patterns through upper or lower functions to satisfy case-insensitivity for letters :
select id from customers where lower(name) like '%roger%' union all
select id from customers where lower(name) like '%federer%';
and no need to add already included complete name ( e.g. Roger Federer ).
Edit :
An Alternative method maybe the following :
select distinct id
from (select lower(regexp_substr('&str', '[^[:space:]-]+', 1, 1)) frst,
lower(regexp_substr('&str', '[^[:space:]-]+', 1, 2)) lst,
lower('&str') nm
from customers) c1
cross join customers c2
where c1.frst like '%' || lower(c2.name) || '%'
or c1.lst like '%' || lower(c2.name) || '%'
or c1.nm like '%' || lower(c2.name) || '%';
by adding a search string('&str') to make the query more dynamic as you wish.
( when prompted enter Roger Federer for str substitution variable )
I think you can use join same table twice (self join) to get output with below query,
select a.*, b.*
from tab1 a
, tab1 b
where ( a.fname like b.fname||'%' or a.lname like b.lname||'%')
and a.id <> b.id

SQL Join and contains

I'm struggling with this query:
SELECT *
FROM Transactions
WHERE CustomerID IN (SELECT ID FROM Customers
WHERE Name LIKE '%Test%')
It takes 10 seconds to run, however if I create the query manually by taking the 4 values returned by the sub query it runs in milliseconds, for example:
SELECT *
FROM Transactions
WHERE (CustomerID = 1 OR CustomerID = 2 OR
CustomerID = 3 OR CustomerID = 4)
To clarify, running
SELECT ID FROM Customers WHERE Name LIKE '%Test%'
returns the values 1,2,3,4 immediately
Any ideas? What am I missing?
As you already said, when you have the customer id's it runs in milliseconds so the filtering of the customer name is the problem.
The first wildcard (WHERE name LIKE '%Test%') is the suspect here because sql server needs to read all the strings in the name column like a regular expression and find if there is any "Test" in there for every row in the table!
If the names you are filtering for would always start with a "Test" and you could do a WHERE name LIKE 'Test%' it would work much better because sql server only needs to read the start of each string.
Edit:
Here is a little bit different version of the original query if you want to try:
SELECT * FROM Transactions t
WHERE EXISTS (
SELECT 1 FROM
Customers c
WHERE c.ID = t.CustomerID
AND c.Name LIKE '%Test%'
)
What happens with a join?
SELECT t.*
FROM Transactions t JOIN
Customers c
ON t.CustomerID = c.ID
WHERE c.Name Like '%Test%';
Sometimes, JOINs optimize better than IN.

SQL NOT LIKE Wildcard Condition on Inner Join

I have a table called hr_grades that contains employee pay grades such as:-
ID hr_grade
1 PR07
2 AC04
I run two stored procedures. One that returns employees whose grades are in this table, and one that does not. These stored procedures carry out a number of different tasks to prepare the data for loading into the end system.
I want the query to carry out a wildcard search on the rows in the grades table. So for example for employees whose grades are in the table
SELECT DISTINCT
Employee_ID,
FROM
#tmp_vo_hr_acp_staff v
INNER JOIN
hr_grades g ON v.hr_grade LIKE g.HR_Grade + '%' -- wildcard search
The reason for the wildcard is that the hr_grades can be like AC04(1) , AC04(2) etc.
This works fine. However I am struggling to get the reverse of this working.
SELECT DISTINCT
Employee_ID,
FROM
#tmp_vo_hr_acp_staff v
INNER JOIN
hr_grades g ON v.hr_grade NOT LIKE g.HR_Grade + '%'
Any ideas how I could get this to wildcard search to work on a NOT LIKE condition?
Change it to
ON NOT (v.hr_grade LIKE g.HR_Grade + '%' )
EDIT:
Removed the ON inside the brackets.
As almost always in SQL, there are some ways to do it:
-- 1. using outer join where the outer table don't match
SELECT DISTINCT Employee_ID
FROM #tmp_vo_hr_acp_staff v
LEFT JOIN hr_grades g ON (v.hr_grade LIKE g.HR_Grade + '%') -- wildcard search
WHERE g.id IS NULL -- use any non nullable column from hr_grades here
-- 2. using EXISTS for set difference
SELECT DISTINCT Employee_ID
FROM #tmp_vo_hr_acp_staff v
WHERE NOT EXISTS (
SELECT 'x' FROM hr_grades g WHERE v.hr_grade LIKE g.HR_Grade + '%'
)
-- 3. using the less popular ANY operator for set difference
SELECT DISTINCT Employee_ID
FROM #tmp_vo_hr_acp_staff v
WHERE NOT v.hr_grade LIKE ANY (
SELECT g.HR_Grade + '%' FROM hr_grades g
)
Personally, I don't like using joins for filtering, so I would probably use option 2. If hr_grades is a much smaller than #tmp_vo_hr_acp_staff, though, you can benefit from using the option 3 (as the set can be determined beforehand and than cached with a single read operation).

How to select all columns, and a count(*) in the same query

In often use in TSQL the following query :
SELECT COUNT(*), *
FROM CUSTOMER c
WHERE c.Name like 'foo%';
When I try to execute this query in Oracle SQL Developer it doesn't work and throws me an error:
"Missing expression"
What is the good syntax ?
Thanks in advance.
This will perform better:
SELECT COUNT(*) OVER (), c.*
FROM CUSTOMER c
WHERE c.Name like 'foo%';
One approach is to do something like the following. This will result in a count(*) result for each line. But beware, there is a Cartesianjoin; if you have many rows like 'foo%' this will perform badly.
select a.cntr, c.*
from CUSTOMER c
, (select count(*) cntr
from customer b
where b.name like 'foo%' ) a
where c.name like 'foo%'
here below MySQL code is the way to get both select * from and total rows returned in a single query.
$result = $db->get_results("SELECT a.total, c.* FROM tableName c,
(select count(*) total from tableName b where b.post=25) a
where c.post=25");
then you can get variable total to get count, and * can use for based on your table column.
But how to get the total without foreach() or directly into a vaiable?
I go it total without foreach Here:
echo "Total: ".count($result);