I got a table with 13 columns.
id,
jobtitle,keyword1,keyword2,keyword3,
jobtitle2,keyword12,keyword22,keyword23,
jobtitle3,keyword13,keyword23,keyword33.
I am trying to achieve the following.
When jobtitle got a specific value (e.g. Programmer) i want the values of keyword1,keyword2 and keyword3.
When jobtitle2 got a specific value (e.g. Programmer) i want the vaules of keyword12, keyword22 and keyword23.
When jobtitle3 got a specific value (e.g. Programmer) i want the values of keyword13, keyword23 and keyword33.
All three, two or just one jobtitle can have a value.
i got the following mySQL query
SELECT distinct CASE
WHEN jobtitle = "Programmer" THEN keyword1
WHEN jobtitle = "Programmer" THEN keyword2
WHEN jobtitle = "Programmer" THEN keyword3
END as col_1,
CASE
WHEN jobtitle2 = "Programmer" THEN keyword12
WHEN jobtitle2 = "Programmer" THEN keyword22
WHEN jobtitle2 = "Programmer" THEN keyword32
END as col_2,
CASE
WHEN jobtitle3 = "Programmer" THEN keyword13
WHEN jobtitle3 = "Programmer" THEN keyword23
WHEN jobtitle3 = "Programmer" THEN keyword33
END as col_3
FROM tbl_keywords
As far as i know somth. like case when jobtitle="Programmer" then keyword1,keyword2,keyword3 is not allowed because only one return value is accepted.
I am just asking myself if my work arround, see my query above is any close to "best-practice" ? If no how would you solve this.
The query is actually working.
Your query does not make any sense - when you repeat the same condition three times you can also do it in one condition. And it looks a lot like a bad table design in the first place to me. You could be better off with splitting the data into different tables or rows but we would need to see the whole Table to get a better idea of how to help you.
Maybe you can do whatever you actually want to do by using nested mysql IF() functions, but as i said i dont think the query is your main problem.
SELECT distinct IF(jobtitle = "Programmer",keyword1,IF(jobtitle2 = "Programmer",keyword12, ... ))
Related
a quick question :), I wrote this because someone said that my codes are vulnerable to mysql injection and it is a requirement to learn prepared statement in web programming to avoid any user putting malicious data or statement into the database..What I have is a search function that search data from the database, if you type in a string like this "torres" then i search for torres but if you just put "tor" it won't search for datas that contain "tor" in their name..I don't know the correct format while using prepared statement, If you have advice I'm very happy to take it :)
<?php
if (isset($_POST['search'])) {
$box = $_POST['box'];
$box = preg_replace("#[^0-9a-z]#i","",$box);
$grade =$_POST['grade'];
$section = $_POST['section'];
$strand = $_POST['strand'];
$sql = "SELECT * FROM student WHERE fname LIKE ? or lname LIKE ? or mname LIKE ? or grade = ? or track = ? or section = ?";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)){
echo "SQL FAILED";
}
else {
//bind the parameter place holder
mysqli_stmt_bind_param($stmt, "ssssss",$box, $box, $box, $grade, $strand, $section);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
while($row = mysqli_fetch_assoc($result))
{
echo "<tr>";
echo "<td>".$row['lname']."</td>";
echo "<td>".$row['fname']."</td>";
echo "<td>".$row['mname']."</td>";
echo "<td>".$row['grade']."</td>";
echo "<td>".$row['track']."</td>";
echo "<td>".$row['section']."</td>";
echo "</tr>";
}
}
As requested:
#ArtisticPhoenix I clearly prefer the king's way [compound full text index]. This should be your primary answer showing an example/explaination.
First make a full text index that includes all three fields (this is in PHPmyAdmin, it's a bit easier to explain with an image)
Then do a query like this:
#PDO version SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST(:fullname IN BOOLEAN MODE)
#MySqli version SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST(? IN BOOLEAN MODE)
SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST('edward' IN BOOLEAN MODE)
It seems simple but there are some things with full text to be aware of Min char count which is 3 (I think) anything smaller than that is not searched on. This can be changed but it requires repairing the DB and restarting MySql.
Stop words, these are things like and, the etc. These can also be configured in my.cnf.
Punctuation is ignored. This might not seem a big deal on names but think of hyphenated last names.
Usually I reduce the word min to 2 and point the stopwords to an empty file (disabling them).
The match against syntax is quite different, it's pretty powerful but it's not really used outside of full text. An example is: this is the wild card * and you use '"' double quotes for exact phrase match '"match exactly"', and + is logical AND, such as word+ word+ (default is or), - is do not match this etc... If I remember right, I used it a bunch a few years ago but haven't had to use it recently.
For example doing "begins with" on a partial word
SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST('edwar*' IN BOOLEAN MODE)
Same result matches one row. The obvious benefit is searching all 3 fields at the same time, but the full text syntax itself can be quite useful too.
For more information:
https://dev.mysql.com/doc/refman/8.0/en/fulltext-boolean.html
PS. I might add that using OR in a query can really kill performance, I've went as far as to replace simple OR with a UNION because of how bad the performance is on a large table. Logically the DB optimizer has to rescan the entire table for an OR, unlike AND where it can use the result of the previous expression to reduce the next expressions data set (or that is how I understand it). I can say the performance difference is very noticeable using OR vs UNION.
This is true for a compound full text index vs doing OR on each field separately. By default fulltext is faster, but it's even faster this way.
To fix your current query (for the sake of completeness)
You need whats known as an exclusive or, like this:
SELECT * FROM student WHERE ( fname LIKE ? OR lname LIKE ? OR mname LIKE ? ) AND grade = ? AND track = ? AND section = ?
What this does is group the OR's together so that they evalute as one expression to the "next level up" ( outside the parenthesis ). Basically order of operations. In English, you would have to match at least 1 of these columns fname, lname, mname AND you would also have to match all of the rest of the columns as well, to get a result returned for any given row.
If you use all OR (as you are now) and any single field matches, then the query comes back as true with matches. Which is the behaviour you are experiencing now.
If you simply change everything outside of the name fields to AND, Basically remove the parenthesis
Like this:
#this is wrong don't use it.
SELECT * FROM student WHERE fname LIKE ? OR lname LIKE ? OR mname LIKE ? AND grade = ? AND track = ? AND section = ?
Then you have to match this way.
(grade AND track AND section AND mname) OR lname OR fname
So if the last or first name match you get results regardless of any of the other fields. But the mname field you would find has to match with all the rest of the fields to get a result (but you would not likely notice this). Because, it would seem that the query works how you want but only when the mname is a match.
I hope that makes sense. It may be helpful to think of the WHERE clause as an IF condition the same logic rules apply.
Cheers!
I am using php and mySQL. I have a select query that is not working. My code is:
$bookquery = "SELECT * FROM my_books WHERE book_title = '$book' OR book_title_short = '$book' OR book_title_long = '$book' OR book_id = '$book'";
The code searches several title types and returns the desired reference most of the time, except when the name of the book starts with a numeral. Though rare, some of my book titles are in the form "2 Book". In such cases, the query only looks at the "2", assumes it is a "book_id" and returns the second entry in the database, instead of the entry for "2 Book". Something like "3 Book" returns the third entry and so forth. I am confused why the select is acting this way, but more importantly, I do not know how to fix it.
If you have a column in your table with a numeric data type (INT, maybe), then your search strategy is going to work strangely for values of $book that start with numbers. You have discovered this.
The following expression always returns true in SQL. It's not intuitive, but it's true.
99 = '99 Luftballon'
That's because, when you compare an integer to a string, MySQL implicitly does this:
CAST(stringvalue AS INT)
And, a cast of a string beginning with the text of an integer always returns the value of the integer. For example, the value of
CAST('99 Luftballon' AS INT)
is 99. So you'll get book id 99 if you look for that search term.
It's pointless to try to compare an INT column to a text string that doesn't start with an integer, because CAST('blah blah blah' AS INT) always returns zero. To make your search strategy work better, you should consider omitting OR book_id = '$book' from your search query unless you know that the entirety of $book is a number.
As others mention, my PHP allowed both numerical enties and text entries from the browser. My query was then having a hard time with this, interpreting some of my text entries as numbers by truncating the end. Thus, my "2 Book" was being interpreted as the number "2" and then being queried to find the second book in the database. To fix this I just created a simple if statement in PHP so that my queries only looked for text or numbers. Thus, in my case, my solution was:
if(is_numeric($book)){
$bookquery = "SELECT * FROM books WHERE book_id = '$book'";
}else{
$bookquery = "SELECT * FROM books WHERE book_title = '$book' OR book_title_short = '$book' OR book_title_long = '$book'";
}
This is working great and I am on my way coding happily again. Thanks #OllieJones and others for your questions and ideas which helped me see I needed to approach the problem differently.
Not sure if this is the correct answer for you but it seems like you are searching for only exact values in your select. Have you thought of trying a more generic search for your criteria? Such as...
$bookquery = "SELECT * FROM my_books WHERE book_title LIKE '".$book."' OR book_title_short LIKE '".$book."' OR book_title_long LIKE '".$book."' OR book_id LIKE '".$book."'"
If you are doing some kind of searching you might even want to ensure the characters before the search key are found as well like so....
$bookquery = "SELECT * FROM my_books WHERE book_title LIKE '%".$book."' OR book_title_short LIKE '%".$book."' OR book_title_long LIKE '%".$book."' OR book_id LIKE '%".$book."'"
The % is a special char that looks for allows you to search for the chars you want to search for PLUS any characters before this that aren't in the search criteri... for example $book = "any" with a % before hand in the query like so, '%".$book."'"`` would return bothcompanyand also the wordany` by itself.
If you need to you can add a % to the end also like so, `'%".$book."%'"`` and it would do the same for the beginning and end of the search key
I am building a site where candidates can post their resume and employers can post their jobs.
The employers can post a job with multiple qualifications and I saved it in database like this PHP,Javascript,ASP. Now I want admin to be able to select the candidates who are eligible for a post.
I have written the query:
$sql = "
SELECT
cand_f_name,
cand_l_name,
cand_qualification,
cand_phone,
cand_email,
cand_experience_yr,
cand_experience_mn,
cand_message,
cand_id
FROM
tbl_cand_data
WHERE
cand_qualification LIKE '%$emp_q%'
But it is not showing the expected result. I think my condition cand_qualification LIKE '$emp_q' is wrong.
My tbl_cand_data :
If you are doing a LIKE query you should include wildcards, as they will match a string containing, otherwise just do an exact match using =:
// String match
WHERE
cand_qualification LIKE '%emp_q%';
// Exact match
WHERE
cand_qualification = '$emp_q';
// You could try a WHERE IN clause as well
WHERE cand_qualification IN ('$emp_q');
// Values have to be quoted individually
WHERE cand_qualification IN ('BA','BSc','BCom');
// If you have an array you can do this:
$myArray = array('BA', 'BSc', 'BCom');
$emp_q = "'" . implode("','", $myArray) . "'"; //Output 'BA', 'BSc', 'BCom'
I saved it in database like this PHP,Javascript,ASP
That's what you did utterly wrong.
you have to create a related table (that's why our ratabase called relational one!) storing qualifications, and interconnection table, consists of qualifications id linked with candidates ids.
And query them using basic joins.
Note that despite of your current decision, even if you decide to continue with your lame schema, you WILL have to remake it proper way, sooner or later (but sooner will make you less work).
That is the very basics of database architecture and noone can go against it.
SELECT fields FROM tbl_cand_data d, qualification q, qual_cand qc
WHERE q.name = 'ASP' AND q.id=qc.qid AND d.id=qc.did
Like requires percent %
try it
I have two questions regarding my script and searching. I have this script:
$searchTerms = explode(' ', $varSearch);
$searchTermBits = array();
foreach($searchTerms as $term){
$term = trim($term);
if(!empty($term)){
$searchTermBits[] = "column1 LIKE '%".$term."%'";
}
}
$sql = mysql_query("SELECT * FROM table WHERE ".implode(' OR ', $searchTermBits)."");
I have a column1 with a data name "rock cheer climbing here"
If I type in "rock climb" this data shows. Thats perfect, but if I just type "Rocks", it doesn't show. Why is that?
Also, How would I add another "column2" for the keyword to search into?
Thank you!
Searching that string for "rocks" doesn't work, because the string "rocks" doesn't exist in the data. Looking at it, it makes sense to you, because you know that the plural of "rock" is "rocks", but the database doesn't know that.
One option you could try is removing the S from search terms, but you run into other issues with that - for example, the plural of "berry" is "berries", and if you remove the S, you'll be searching for "berrie" which doesn't get you any further.
You can add more search terms by adding more lines like
$searchTermBits[] = "column1 LIKE '%".$term."%'";
and replacing ".$term." with what you want to search for. For example,
$searchTermBits[] = "column1 LIKE '%climb%'";
One other thing to note... as written, your code is susceptible to SQL injection. Take this for example... What if the site visitor types in the search term '; DROP TABLE tablename; You've just had your data wiped out.
What you should do is modify your searchTermBits[] line to look like:
$searchTermBits[] = "column1 LIKE '%" . mysql_real_escape_string($term) . "%'";
That will prevent any nastiness from harming your data.
Assuming the data you gave is accurate, it shouldn't match because you're using "Rocks" and the word in the string is "rock". By default mysql doesn't do case sensitive matching, so it's probably not the case.
Also, to avoid sql injection, you absolutely should be using mysql_real_escape_string to escape your content.
Adding a second column would be pretty easy as well. Just add two entries to your array for every search term, one for column1 and one for column2.
Your column1 data rock cheer climbing here your search criteria %Rocks% it doesn't fit at all as rocks is not in your column1 data
you can add column2 as you do for column1 then put it all together by using an AND operator (column1 LIKE "%rock%" OR column1 LIKE "%climb%") AND (column2 LIKE "%rope%" OR column2 LIKE "%powder%")
TIPS:
If your table/schema are using xx_xx_ci collation (then this is mean case insensitive,mysql doesn't care case sensitive) but if other then you need to make sure that the search term must be case sensitive(mysql do case sensitive).
In some languages (ColdFusion comes to mind), you can run a query on the result set from a previous query. Is it possible to do something like that in php (with MySQL as the database)?
I sort of want to do:
$rs1 = do_query( "SELECT * FROM animals WHERE type = 'fish'" );
$rs2 = do_query( "SELECT * FROM rs1 WHERE name = 'trout'" );
There is no MySQL function like this for PHP, however there is a more advanced substitute for it.
Edit: For those of you who don't know what a query of queries is, it's exactly this and there's a purpose some people do it like this. Using an AND operator is ****NOT**** the same thing! If I want results where username='animuson' for one part of my script and then want all the results out of that query where status='1', it is not logical for me to run another query using an AND operator, it is much more logical to loop through the previous results in PHP. Stop upvoting things without reading the comments on why they weren't upvoted in the first place, that's just lazy. If you don't have a clue what's being talked about, you shouldn't be upvoting or downvoting in the first place.
Well, you may want to do this without touching the db:
while($t = mysql_fetch_array($rs1)){
if($t[name] == 'trout'){
echo 'This is the one we\'re looking for!';
break;
}
}
In PHP, it would be terribly inefficient. You would have to loop through each row and check that its name was trout. However, is there any reason you can't do
SELECT * FROM `animals` WHERE `type` = 'fish' AND `name` = 'trout'
in SQL? It would be much, much faster.
You can also do something like
select morestuff from (select stuff from table where a = b ) where c = d;
Use the AND keyword?
"SELECT * FROM animals WHERE type = 'fish' and name='trout'"
Also, you can use LINQ for php http://phplinq.codeplex.com/