Really simple, I want to select all titles that starts with letter 'A' while ignoring the dash at the beginning of the string.
SELECT * TRIM(LEADING '- ' FROM title) WHERE title LIKE 'A%'
This just doesn't seem to work. Please help. Thanks.
If you want decent speed, you should avoid per-row functions as much as possible. Normally, I'd suggest an insert/update trigger to store modified data so as to amortise the cost of the calculation across all selects (see here for an explanation along with some other guidelines I follow) but, for this particular case, there's an easier way *a.
Just use:
select * from table where title like 'A%' or title like '- A%'
If the execution engine of your DBMS is any good, it will turn that into two very fast (assuming title is indexed) passes of the data without having to process every single row in the table.
If your execution engine is not that smart, try:
select * from table where title like 'A%'
union all select * from table where title like '- A%'
to see if that helps. Make sure you use union all, not just union. The latter will attempt to remove duplicates, unnecessary in this case since a title cannot start with both "A" and "- A".
And, as with all optimisations, measure, don't guess!
*a You may still want to consider using the trigger/extra-column method if there's a chance you want a case-insensitive search. The method in this answer will work okay for case-insensitivity on the first letter (a%/A%/-a%/-A%) but will quickly degrade if you're looking for something like items starting with Bill which would require 32 separate clauses (24 character combinations with and without the hyphen prefix).
SELECT TRIM(LEADING '- ' FROM title) FROM [missing table here] WHERE TRIM(LEADING '- ' FROM title) LIKE 'A%'
SELECT * TRIM(LEADING '- ' FROM title) WHERE title LIKE 'A%'
Your where clause will never work, as you're trying to compare to the POST-trim data, but the database is doing the comparison on pre-TRIM.
There's two choices:
SELECT *
FROM table
WHERE title LIKE '- A%'
or
SELECT *, TRIM(LEADING '- ' FROM title) AS title
FROM table
WHERE title LIKE 'A%'
Of the two, the first one is preferable, as it allows indexes to be used. The second one, since you're comparing against dynamically derived data, will not.
Related
I have tags column in database separated by commas like that: "green, big, strong". I know it's not the best way to store tags in database, and I will change it later, but right now I really need to find out how to get row that has special tag.
For example, in the first row column tags is "green, big, strong". And in the second row is "white, big, strongy".
When I use
"SELECT * FROM tablename WHERE tags LIKE '%strong%'"
it returns the first and the second column (because of strongy), but I need only the first one
I would do this as:
SELECT *
FROM tablename
WHERE ',' || tags || ',' LIKE '%,strong,%';
That is, just add the delimiters so the search is not ambiguous.
Limit output to 1 like so:
SELECT * FROM tablename WHERE tags LIKE '%strong%' LIMIT 1
Could also sort by specific column such as ID, like so:
SELECT * FROM tablename WHERE tags LIKE '%strong%' ORDER BY column_name LIMIT 1
Brackets specify a range when used with LIKE. You can use the ESCAPE keyword.
WHERE mycol LIKE '%\[126\]%' ESCAPE '\';
Of course if you are trying to match an exact string, you don't need LIKE, or you can drop the % characters and LIKE will behave like = (this makes it flexible to pass in wildcards or exact matches to a parameter).
INSERT INTO tab2 NOLOGGING
SELECT
ID,
ORG_NAME
FROM tab3
WHERE (( upper(NVL(org_name,company_given)) LIKE '%MSOFT%'
OR upper(NVL(org_name,company_given)) LIKE 'M SOFT'
OR upper(NVL(org_name,company_given)) LIKE '%MISOFT%'
OR upper(NVL(org_name,company_given)) LIKE 'MSN %'
OR upper(NVL(org_name,company_given)) LIKE '%N APP%'
OR upper(NVL(org_name,company_given)) LIKE '%NAPP%'
OR upper(NVL(org_name,company_given)) LIKE '%NAPPE%'
OR upper(NVL(org_name,company_given)) LIKE '%NAPPS%'
OR upper(NVL(org_name,company_given)) LIKE '%NEK%APPLIANCE%'
the above coding is taking too much time. Table tab3 is very huge.
The above is dynamic. Any alternatives for nvl?
The line below
OR upper(NVL(org_name,company_given)) LIKE 'M SOFT'
could be replaced with
OR ((orgname is not null and upper(org_name) LIKE 'M SOFT')
OR ((orgname is null and upper(company_given) LIKE 'M SOFT')
Not sure it's faster.
Also you can try to run it once with subquery
SELECT *
FROM (
SELECT
ID,
ORG_NAME,
upper(NVL(org_name,company_given)) as name_for_filter
FROM tab3)
WHERE name_for_filter LIKE '%MSOFT%'
OR name_for_filter LIKE 'M SOFT'
...
The best way would be to introduce a name_for_filter column in the table and fill it once with a trigger. Then the column could be used for the filtering
This query is going to execute a full table scan of your table. You say that table is huge, so it's going to take a long time.
A normal index won't help because there are two columns in play. Even a function-based index like this ...
create index fbi3 on tab3( upper(NVL(org_name, company_given) ))
... won't help because indexes are useless against a like filter with a wildcard at the front, and you have those:
LIKE '%NEK%APPLIANCE%'
If this is a one-time exercise I would suggest you swallow the time and wait for the statement to finish. But let's assume you want to do this kind of query often. If so, it's worth building infrastructure to support it.
A new column for the search criteria. Basically a column which is pre-populated with the arguments used in the functions. For 11g or higher make this a virtual column:
alter table tab3 add search_name as ( upper(NVL(org_name, company_given)));
If using an older version of the database you will have to build a normal column and populate it with triggers.
Build a Text index on the search_name column. As it is short you can use a CTXCAT index, which will be maintained transactionally.
Then you need to rewrite the query to use catsearch() syntax instead of like operator. Find out more
As already suggested, it's probably best to create a prepared search column. You could even remove the spaces to avoid a search for both 'N APP' and 'NAPP' for example (but that could lead to false positives in some cases).
On top of that you can remove the check for %NAPPE% and %NAPPS% because you already include records containing %NAPP%
It should be faster when using:
pseudocode:
'MSN %'
or ('%SOFT%' and ('M SOFT' or '%MSOFT%' or '%MISOFT%'))
or ('%APP%' and ('%N APP%' or '%NAPP%' or '%NEK%APPLIANCE%'))
If SOFT or APP is not found there is no need to check for the others containing the same word - the and will avoid that if the first part is already false.
If this is just an example and those parameters are variable, you could write some code to optimize those search terms (unless the SQL server already does that).
I want to find which SP a column named column1 is modified by UPDATE query by searching sys.sql_module, and since the column is also used in SELECT queries, I think its better to use '%Column1 =%' criteria as LIKE predicate.
However, system coding standard is not strictly applied, therefore in our database there exists multiple type of codings: column1=, column1 =,column1 {tab} =, column1 +=, column1 {CR}{LF} = and etc. Definitely i can't use %column1%=% as predicate, but how can I find all (at least most) of them meet my initial predicate?
Assume I accept maximum 10 chars between column1 and = is accepted.
I was in the same situation in the past. What my work around was, I removed every space, new line and tab from sql_modules definition column itself then compared with my searched string.
Select SP_Def from
(SELECT REPLACE(REPLACE(REPLACE(sm.definition, ' ',''), CHAR(13) +CHAR(10),''),CHAR(9),'') as SP_Def
FROM sys.sql_modules AS sm ) a
where SP_Def like '%column1=%'
Well given I have a value I want to check for potential matches in a database (in one varchar field) so I write something like:
SELECT * FROM table WHERE column LIKE "%value%"
Which will work if the value is something like "test" and the column has a value of "this is a test" however if it is reversed then I will not get a match I have tried things along the lines of:
SELECT * FROM table WHERE CONCAT("%",column,"%") LIKE "value"
but don't know exactly how to phrase this to Google to get a response I need, please help!
You can reverse a like statement. Just using the same syntax as a regular like query:
select
*
from
table
where
'value' like concat('%', column, '%')
Of course, if you felt wild and crazy, you could also use instr:
select * from table where instr('value', column) > 0
I don't know which one is faster, since I don't have a MySQL instance to test against, but it's worth trying both to see which wins.
SELECT *
FROM table
WHERE 'value' LIKE CONCAT('%', column, '%')
I am new to SQL programming.
I have a table job where the fields are id, position, category, location, salary range, description, refno.
I want to implement a keyword search from the front end. The keyword can reside in any of the fields of the above table.
This is the query I have tried but it consist of so many duplicate rows:
SELECT
a.*,
b.catname
FROM
job a,
category b
WHERE
a.catid = b.catid AND
a.jobsalrange = '15001-20000' AND
a.jobloc = 'Berkshire' AND
a.jobpos LIKE '%sales%' OR
a.jobloc LIKE '%sales%' OR
a.jobsal LIKE '%sales%' OR
a.jobref LIKE '%sales%' OR
a.jobemail LIKE '%sales%' OR
a.jobsalrange LIKE '%sales%' OR
b.catname LIKE '%sales%'
For a single keyword on VARCHAR fields you can use LIKE:
SELECT id, category, location
FROM table
WHERE
(
category LIKE '%keyword%'
OR location LIKE '%keyword%'
)
For a description you're usually better adding a full text index and doing a Full-Text Search (MyISAM only):
SELECT id, description
FROM table
WHERE MATCH (description) AGAINST('keyword1 keyword2')
SELECT
*
FROM
yourtable
WHERE
id LIKE '%keyword%'
OR position LIKE '%keyword%'
OR category LIKE '%keyword%'
OR location LIKE '%keyword%'
OR description LIKE '%keyword%'
OR refno LIKE '%keyword%';
Ideally, have a keyword table containing the fields:
Keyword
Id
Count (possibly)
with an index on Keyword. Create an insert/update/delete trigger on the other table so that, when a row is changed, every keyword is extracted and put into (or replaced in) this table.
You'll also need a table of words to not count as keywords (if, and, so, but, ...).
In this way, you'll get the best speed for queries wanting to look for the keywords and you can implement (relatively easily) more complex queries such as "contains Java and RCA1802".
"LIKE" queries will work but they won't scale as well.
Personally, I wouldn't use the LIKE string comparison on the ID field or any other numeric field. It doesn't make sense for a search for ID# "216" to return 16216, 21651, 3216087, 5321668..., and so on and so forth; likewise with salary.
Also, if you want to use prepared statements to prevent SQL injections, you would use a query string like:
SELECT * FROM job WHERE `position` LIKE CONCAT('%', ? ,'%') OR ...
I will explain the method i usally prefer:
First of all you need to take into consideration that for this method you will sacrifice memory with the aim of gaining computation speed.
Second you need to have a the right to edit the table structure.
1) Add a field (i usually call it "digest") where you store all the data from the table.
The field will look like:
"n-n1-n2-n3-n4-n5-n6-n7-n8-n9" etc.. where n is a single word
I achieve this using a regular expression thar replaces " " with "-".
This field is the result of all the table data "digested" in one sigle string.
2) Use the LIKE statement %keyword% on the digest field:
SELECT * FROM table WHERE digest LIKE %keyword%
you can even build a qUery with a little loop so you can search for multiple keywords at the same time looking like:
SELECT * FROM table WHERE
digest LIKE %keyword1% AND
digest LIKE %keyword2% AND
digest LIKE %keyword3% ...
You can find another simpler option in a thread here: Match Against.. with a more detail help in 11.9.2. Boolean Full-Text Searches
This is just in case someone need a more compact option. This will require to create an Index FULLTEXT in the table, which can be accomplish easily.
Information on how to create Indexes (MySQL): MySQL FULLTEXT Indexing and Searching
In the FULLTEXT Index you can have more than one column listed, the result would be an SQL Statement with an index named search:
SELECT *,MATCH (`column`) AGAINST('+keyword1* +keyword2* +keyword3*') as relevance FROM `documents`USE INDEX(search) WHERE MATCH (`column`) AGAINST('+keyword1* +keyword2* +keyword3*' IN BOOLEAN MODE) ORDER BY relevance;
I tried with multiple columns, with no luck. Even though multiple columns are allowed in indexes, you still need an index for each column to use with Match/Against Statement.
Depending in your criterias you can use either options.
I know this is a bit late but what I did to our application is this. Hope this will help someone tho. But it works for me:
SELECT * FROM `landmarks` WHERE `landmark_name` OR `landmark_description` OR `landmark_address` LIKE '%keyword'
OR `landmark_name` OR `landmark_description` OR `landmark_address` LIKE 'keyword%'
OR `landmark_name` OR `landmark_description` OR `landmark_address` LIKE '%keyword%'