PHP SELECT distinct doesn't echo variable? - php

$query = "SELECT distinct('case'), firstname, lastname
FROM cases ";
Why can't "case" be echoed? It is a number..
It will echo when the query is like this:
$query = "SELECT case, firstname, lastname
FROM cases ";

First, case should not be in quotes, it should be in backticks. Second, DISTINCT always applies to the whole row regardless of any parentheses you may have around any of your expressions. In your query your parentheses are misleading and should be removed.
SELECT DISTINCT `case`, firstname, lastname FROM cases
If you want to return a single aggregated row for each case you need to use "GROUP BY `case`", but then you need to consider what should be returned for the other values.

The case is not echoed because you might be trying to echo $row['case'] which wont work because the feild that is returning is not case but distinct(case)
And you need to avoid the single quote and either give no quotes or use a backquote; else mysql will take case as a literal string
so change the query to
SELECT
DISTINCT(case),
firstname,
lastname
FROM
cases
And if you want to access the case as $row['case'] the use as like
SELECT
DISTINCT(case) as case,
firstname,
lastname
FROM
cases

Related

searching datas in the database with prepare statement

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!

Using PHP array to search a column in SQL DB that is separated by commas

I have a column in my DB labeled providers. This column can have multiple values, i.e (1,2,3,4,5) or (14,2,9,87). I have an array that is also filled with similar values i.e (1,9,7,3) and so forth.
I am trying to query my DB and return results from the table where any of the values in the variable array match the values split by commas in the column.
This is what I have.
$variable = "1,9,3,4";
$sql = "SELECT id, provider FROM table_name WHERE FIND_IN_SET(provider, '$variable')";
However, this is not working. If the column in the DB has more then one value, it returns nothing. If the column only has one value, it returns it fine.
I'm not sure, but LOCATE should solve your problem.
Example:
$sql = "SELECT id, provider FROM table_name WHERE LOCATE('$variable', provider) = 1;";
but not works if order of ids is different.
The CSV should be the second parameter of your find_in_set. The first should be the single value you are searching for. So you should split $variable into multiple values. Something like this:
$variable = "1,9,3,4";
$values = str_getcsv($variable);
foreach($values as $value) {
$sql = "SELECT id, provider FROM table_name WHERE FIND_IN_SET($value, provider)";
//execute $sql here
}
should do it.
With your previous approach the find_in_set was looking for 1,9,3,4, not 1, 9, 3, or 4, as you had wanted. The manual also states the behavior using the function that way won't work.
This function does not work properly if the first argument contains a comma (,) character.
You should update the table in the future when you have time so it is normalized.

SQL find part of string

I met following problem:
I've got table 'students' with columns: 'id_student', 'name' and 'surname'.
Then I got a variable that contains full_name (example: 'James Bond')
I need to make a query that selects 'id_student' where 'name' and 'surname' matches whole name.
I tried to do this in several ways, like:
SELECT id_student FROM students WHERE name+' '+surname LIKE full_name
but it doesn't work. Any idea?
Your code should work in a database where + is used for string concatenation. The LIKE is fine, but = seems sufficient:
SELECT id_student
FROM students
WHERE CONCAT(name, ' ', surname) = full_name;
Note that unexpected characters and small differences in spelling would cause the comparisons to fail.
MySQL does not support string concatenation using plus, at least not by default. Instead, we can use the CONCAT function. The LIKE expression you want here is:
full_name LIKE 'James%Bond'
Here we want any record which starts with James and ends with Bond.
SELECT id_student
FROM students
WHERE full_name LIKE CONCAT(name, '%', surname);
Maybe you should try something like:
SELECT id_student
FROM students
WHERE CONCAT_WS(" ", name, surname)
LIKE full_name
CONCAT_WS or CONCAT is the MySQL function to join strings. The former allows you to define a separator, a space in your case.

How to build a MySQL query with conditional filters?

I'm pretty new to both PHP and MySQL and I'm trying to build a small library of singers' quotes. I'd like the user to be able to search for a quote by typing a part of the quote itself, the singer's name or the singer's band, if any.
Now, that part I pretty much nailed:
$query = 'SELECT * FROM quotes WHERE (quote LIKE "%'.$search_string.'%" OR singerName LIKE "%'.$search_string.'%" OR bandName LIKE "%'.$search_string.'%")';
This works, although it alors returns results where the search_string is in the middle of a word: if I type "her", it will return every quote containing "other" or "together". If I drop the second % from the query, it won't return quotes where the search_string isn't the very first word, which I want it to do.
Anyway, what I'd also like to do is give the possibility to filter the results. Let's say I want the user to be able to only show quotes in English, German or Both, via radio buttons. By default, Both is selected, so the $query above is still valid. However, if the user selects English, it should also say something like AND (language = 'EN').
For now, I tried adding to the query this way:
if ($_POST['language']== "EN") {
$sql .= " AND (language = 'EN')";
}
It works, but it can be a real hassle, as I also want the user to search for quotes using only the filters, without entering a search query: they would be able to look for quotes in English by singers in Band, for example. So, I also have this:
if (strlen($search_string) < 1) {
$sql = "SELECT * FROM quotes";
}
But then, the $sql .= " AND (language = 'EN')"; wouldn't be correct anymore, as "AND" should be "WHERE". So I'll have to have another if clause to modify the string, and another one for every filter I decide to apply.
My question is then: how should I build my query, given that there are optional filters, and that the search should also be possible using the filters alone?
Thanks!
Set an always true condition in order to have constant WHERE clause.
$sql = "SELECT * FROM myTable WHERE 1 = 1 "
if (true) {
$sql .= " AND col1 LIKE '%val%' ";
}

Getting certain parts of a string out of a select

I have a database (mydb) with following data in one column:
PK:
8/10/6101+6102 (2971386)
6110/2411 (3037457)
8/10/6504 (2276770)
8/10/6403 (2724296)
-2669938
8/1/1001-1031 (2857109)
-2547251
8/9/5003-5006 (2770096)
I have to compare these data with a variable $id for example: 2724296
SELECT * FROM mydb WHERE PK = '$id';
Of course, this query won't deliver a result. Is there a easy way to compare my $id with the values in the brace and the values with no brace? A replace in the select replaces e.g. only the brace, but not the value left to the brace.
Greets, Yab86
You can use REGEXP for this. Try this query,
$query = "SELECT * FROM mydb WHERE PK REGEXP '({$id})' OR PK REGEXP '-{$id}'";
You can use below:
SELECT * FROM mydb WHERE PK LIKE '%(2724296)';
Below is little complex: using regular expression
SELECT * FROM mydb WHERE PK REGEXP '[(]2724296[)]';
See this https://dev.mysql.com/doc/refman/5.1/en/regexp.html for writing customizable regular expression.
I would try a regular expression (assuming you only want to check the number inside the brackets). Something like this should work:
\([0-9]*\)$
This will return a string that begins with ( followed by 1 or more numbers and ends with ). You should then be able to remove the brackets from the string and compare it with your variable

Categories