MySQL query with extra manual output based on WHERE - mysql

Maybe it's a dumb question, but imagine having a table with fields like:
wholename, lastname, firstname, dateOfBirth
Now I want to search that table based on user input, but I would like to give a match % to the result. Meaning:
If lastname + firstname + dateOfBirth are all found in the database matchPrct = 100.
If lastname + dataofBirth are found in the databse matchPrct = 80.
And a few other rules (With other words the field matchPrct is an auto generated field which is not really in the db).
SQL for what I would like to achieve is:
SELECT * FROM table
WHERE firstname="%mike%" AND lastname="%tysson%" AND dateOfBirth="01/01/2012"
(create matchPrct=100) OR ....
Hope what I mean is clear.

LIKE is an operator that returns a boolean value, = behaves similarly. Booleans in MySQL are 1 for true and 0 for false. That means that you can say this:
select *,
((firstname like '%mike%') + (lastname like '%tysson%') + (dateOfBirth = '01/01/2012')) / 3.0 as score
from table
where firstname like '%mike%'
or lastname like '%tysson%'
or dateOfBirth = '01/01/2012'
And then read your "how well did it match" values out of score. You can also apply individual weights to each component so that a last name match would count for more than a first name match.
In databases that don't use 1 and 0 as booleans you can cast them or use a CASE to convert booleans to the numbers you want. This doesn't apply to MySQL of course but it is worth keeping in mind.

Related

MySQL/ORACLE performance using LIKE and CONCAT

Which one of these two queries would perform better in MySQL and/or ORACLE?
SELECT *
FROM User
WHERE name LIKE "%searchTerm%"
OR lastname LIKE "%searchTerm%"
OR email LIKE "%searchTerm%";
or
SELECT *
FROM User
WHERE CONCAT(name, " ", lastname, " ", email) LIKE "%searchTerm%";
I have a strong feeling that the second one, but I'd like to be sure.
SELECT *
FROM User
WHERE name LIKE "%searchTerm%"
OR lastname LIKE "%searchTerm%"
OR email LIKE "%searchTerm%";
This query is better then second one. Because if you want to use different filter on all the Fields then you can use them easily.
SELECT *
FROM User
WHERE CONCAT(name, " ", lastname, " ", email) LIKE "%searchTerm%";
In this query you can not use different filter. You have to use common filter on all the fields.
First of all the two queries are not equivalent. In case that a blank (the concatenation delimiter) may be used in the searchTerm, the first query may not match, but the second can, because the match spans two or three columns.
Performance will be very same as both queries make full table scan and the difference is only in the filter condition
First Query
1 - filter("NAME" IS NOT NULL AND "NAME" IS NOT NULL AND "NAME" LIKE
'%searchTerm%' OR "LASTNAME" IS NOT NULL AND "LASTNAME" IS NOT NULL AND
"LASTNAME" LIKE '%searchTerm%' OR "EMAIL" IS NOT NULL AND "EMAIL" IS
NOT NULL AND "EMAIL" LIKE '%searchTerm%')
Second Query
1 - filter("NAME"||' '||"LASTNAME"||' '||"EMAIL" LIKE '%searchTerm%')
So basically neither query is suitable for a customer search on non trival tables.
You typically want to limit the search to column LIKE 'xxxxxx%' which can use an index.
(MySQL Answer)
Either way will involve a full table scan, so neither will be fast. (Fetching rows is more costly than evaluating expressions.) Furthermore, the leading wildcard implies that the string(s) must be fully scanned; no INDEX usable possible.
If your "serachTerm" is always word(s), then use FULLTEXT(name, lastname, email) and MATCH(name, lastname, email) AGAINST ("+searchTerm" IN BOOLEAN MODE); it will be a lot faster.

SQL Select if substring occurs then copy until substring else keep original

I have a database with TV Guide data, and in my description field (VARCHAR) sometimes i have a '|' where behind it is the rating. I used to check this in php, before converting it all to XML, but i would like to do this in SQL.
So if i have this string:
This is the description | rating pg-13
Then i want to keep the
This is the description
but if there is no '|' i want the whole string.
I tried using substring, but can't get it to work.
My query now is:
SELECT *, SUBSTRING(`long_description`, 1, POSITION('|' IN `long_description`)) FROM `programs` WHERE station_id = 1
this works only one way - this gives me the string before the '|' but if there is no '|' it gives an empty column.
Based on the use of backticks, you might be using MySQL. If so, substring_index() does exactly what you want:
select substring_index(long_description, '|', 1)
How about this:
SELECT
*,
IF(long_description LIKE '%|%',
SUBSTRING(`long_description`,
1,
POSITION('|' IN `long_description`)),
long_description)
FROM
`programs`
WHERE
station_id = 1
The IF clause basically just checks if you have a | in the field and applies your routine when this is true. Else it will simply return the complete long_description value.

SQL - Query to find if a string contains part of the value in Column

I am trying to write a Query to find if a string contains part of the value in Column (Not to confuse with the query to find if a column contains part of a string).
Say for example I have a column in a table with values
ABC,XYZ
If I give search string
ABCDEFG
then I want the row with ABC to be displayed.
If my search string is XYZDSDS then the row with value XYZ should be displayed
The answer would be "use LIKE".
See the documentation: https://dev.mysql.com/doc/refman/5.0/en/string-comparison-functions.html
You can do WHERE 'string' LIKE CONCAT(column , '%')
Thus the query becomes:
select * from t1 where 'ABCDEFG' LIKE CONCAT(column1,'%');
If you need to match anywhere in the string:
select * from t1 where 'ABCDEFG' LIKE CONCAT('%',column1,'%');
Here you can see it working in a fiddle:
http://sqlfiddle.com/#!9/d1596/4
Select * from table where #param like '%' + col + '%'
First, you appear to be storing lists of things in a column. This is the wrong approach to storing values in the database. You should have a junction table, with one row per entity and value -- that is, a separate row for ABC and XYZ in your example. SQL has a great data structure for storing lists. It is called a "table", not a "string".
If you are stuck with such a format and using MySQL, there is a function that can help:
where find_in_set('ABC', col)
MySQL treats a comma delimited string as a "set" and offers this function. However, this function cannot use indexes, so it is not particularly efficient. Did I mention that you should use a junction table instead?

Sql query returns only one row (LIKE)

SELECT *
FROM customers
WHERE Firstname LIKE 'George'
The problem is that i have more than 1 rows in the table with tha name Geoge and the result of the query shows only one row
You will want to include the wildcard % character to include the rows the have George present in the name:
SELECT *
FROM customers
WHERE Firstname LIKE '%George%';
If George will always appear at the beginning, then you can include the wildcard on the end:
SELECT *
FROM customers
WHERE Firstname LIKE 'George%';
you need to add a wildcard character % to match any value that contains george
SELECT *
FROM customers
WHERE Firstname LIKE '%George%'
MySQL LIKE Operator
the statement
WHERE Firstname LIKE 'George'
is equivalent with
WHERE Firstname = 'George'
that is why you are only getting one record which firstname is george.
UPDATE 1
SQLFiddle Demo
try
LOWER(Firstname) LIKE '%george%'
handles partial values and avoids case sensietivity issues.

Override column value in WHERE clause?

I was wondering if it was possible to override column value in the Where clause of a SQL query (MySQL in my case).
To be more clear, here is an example :
Suppose a basic query is :
SELECT lastname, firstname FROM contacts WHERE lastname = "Doe";
Is it possible to force lastname and firstname to return value from an other table, just by modifying what is after the WHERE part ? Something like
SELECT lastname, firstname FROM contacts WHERE lastname = (SELECT name FROM companies);
I am currently testing a web application, and I found a SQL Injection flaw where I can change Doe to whatever I want, but I'm limited with only one query (mysql_query restriction of PHP) and addslashes (so no " and ').
possible could be
SELECT lastname, firstname FROM contacts WHERE lastname = "{0}" UNION SELECT {1} --
where {0} non existed value and {1} data from other tables
UPDATE from wiki example
$res = mysql_query("SELECT author FROM news WHERE id=" . $_REQUEST['id'] ." AND author LIKE ('a%')");
become
SELECT author FROM news WHERE id=-1 UNION SELECT password FROM admin/* AND author LIKE ('a%')
The syntax that you used in your SELECT ... WHERE clause is a standard SQL feature called a subquery.
In the context of your example there is a restriction on the subquery to return just single value. Otherwise your query is a valid SQL and you can change subquery to return multiple values (with implicit OR) using IN operator like this:
SELECT lastname, firstname FROM contacts
WHERE lastname IN (
SELECT name FROM companies
);
You can dig deeper into this subject to uncover correlated subquery.