Is there a way to do conditional logic in a SQL query? - php

So I have a fairly long complex query but the gist is that the query's basic functionality looks like this SELECT verification_id FROM verification_table
The verification_id returns an integer from 0-3. Is there a way to do something in the SQL query where if the verification_id is 0, it returns a string like "new" and different ones for all 4 verification_id's.
I can do this in the backend via PHP but i was wondering if there was a way to do it via MySQL

You want a case statement. It can be used for boolean conditionals as well as for selecting between multiple outcomes...
SELECT [Condition]
CASE WHEN TRUE THEN 'True'
ELSE 'False'
END
FROM [Table]
Note that the return type of each branch must be the same - The column can only be of one type

SELECT CASE
WHEN verification_id = 0 THEN 'new'
WHEN verification_id = 1 THEN 'something else'
ELSE 'error?'
END AS myvalue
FROM verification_table
something like this should work.
Altough you may consider using the mysql ENUM field type which basically translates text strings into numbers and vice versa. It is an efficient field type of storing such values.

Related

MySQL select only using first word of variable

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

MySQL query String contains opposite

MySQL query String contains
Hello, I am trying to make an mysql query that looks for a column value that contains a string from a master string I set. So if my master string is '1234567', I would like it to return any results with column values that have '1','2', etc... The above link was as close as to what I can find but I need it comparing in the opposite direction.
eg.:
WHERE '%{$needle}%' LIKE `column`
You are a little vague about where the various values are being stored (your text uses terms like "master string" but the sample code uses different names).
You can do what you want using regexp. Here is an example:
select 'abcd6efg' regexp concat('.*[', '1234567', '].*')
To be honest, regex is different from like in one important respect. regex returns true if any part of the left string matches, whereas for like the entire string has to match. So, the following also works:
select 'abcd6efg' regexp concat('[', '1234567', ']')
I like to put the explicit wildcards in to avoid mistakes when switching between the two.
You can look up the documentation for regular expressions here.
How about
WHERE ? LIKE CONCAT('%', `column`, '%')
where ? is a placeholder having a bound parameter with your master value (1234567) because you are using the PDO or MySQLi extension, right?
You're most certainly not using the deprecated MySQL extension, surely.

PDO and MySQL type switching

I have a field 'year' in table 1 which is defined as a VARCHAR(255) and I need to update 'num_years' in table 2 with the value of 'year'. 'num_years' is defined as an INT.
When I try to update 'num_years' with 'year' if 'year' is defined as 3 it works fine, but if I define 'year' as 'foo' it will update 'num_years' with 0.
When I used to use mysql_query functions it would generate an error about invalid column 'foo' or similar, but with PDO it doesn't throw an exception when I was expecting it to.
In this manner we want to ensure that 'num_years' is not updated with 0 if 'years' is numeric. Does PDO have anything built in that throws exception if this is the case?
I'm using PDO transactions and prepared statements.
Validate if its a string or not before you put it into your sql statement that way if your year from table1 consists of something like "1 year" you can explode or otherwise strip off the characters and the space and return just the 1 for insert into your int column in table 2.
Also doing it this way you can special handle events like text only in input field and set it as either a 0 or a -1 or something in your int field which you can later trap and validate on display to say "not specified" or something equivilent.
Hope that makes sense
Instead of inserting a string variable to PDO you can insert something like $delta = $year + 0. If it is "foo" you get $delta = 0 and adding this to num_years will not change them.
The other way is of course typecasting, so use (int)$year.
This should be done in PHP, not PDO.

What character can i use in mysql query to represent all results?

Im trying to create a php script that queries a database based on filter input from users
So essentially i want
select * from table where parent_id = '$filter_value'
However i want to apply a default value to $filter_value which will take effect if the user doesnt specify any filters, and will pull up all possible results.
I tried using * but it didnt work...
Two ways:
Compare the value to NULL
SELECT *
FROM table
WHERE ($filter_value IS NULL OR parent_id = '$filter_value')
Dynamically create the SQL based on whether $filter_value contains a value. If it does not, your query should simply be:
SELECT *
FROM table
Check if the filter variable is null, or just wrap your query in an if statement:
SELECT * FROM baz WHERE foo = :bar OR :bar IS NULL
It's not exactly what you asked, but it is very close and I think a better way. You can do something like this:
if ( empty( $filter_value ) === false ) {
select * from table where parent_id = '$filter_value'
} else {
select * from table
}
That is just an example, not good php syntax.
But the idea is that if you want to have different behaviours depending on something, then you should program it that way, for instance, with an if, that way, you know what happens in each case and control the situation, not depending on what mysql does with the empty value passed.
Ok, i tried just inserting a blank space as the default var value, as in
$filter_value = ''
Solved the problem :$

"SELECT * FROM users WHERE id IN ( )" == FAIL

I have a function that I use called sqlf(), it emulates prepared statements. For instance I can do things like:
$sql = sqlf("SELECT * FROM Users WHERE name= :1 AND email= :2",'Big "John"','bj#example.com') ;
For various reasons, I cannot use prepared statements, but I would like to emulate them. The problem that I run into is with queries like
$sql = sqlf("SELECT * FROM Users WHERE id IN (:1)",array(1,2,3) );
My code works, but it fails with empty arrays, e.g. the following throws a mysql error:
SELECT * FROM Users WHERE id IN ();
Does anyone have any suggestions? How should I translate and empty array into sql that can be injected into an IN clause? Substituting NULL will not work.
Null is the only value that you can guarantee is not in the set. How come it is not an option? Anything else can be seen as part of the potential set, they are all values.
I would say that passing an empty array as argument for an IN() clause is an error. You have control over the syntax of the query when calling this function, so you should also be responsible for the inputs. I suggest checking for emptiness of the argument before calling the function.
Is there a possibility that you could detect empty arrays withing sqlf and change the SQL to not have the IN clause?
Alteratively, you could postprocess the SQL before passing it to the "real" SQL executor so that "IN ()" sections are removed although you'd have to do all sorts of trickery to see what other elements had to be removed so that:
SELECT * FROM Users WHERE id IN ();
SELECT * FROM Users WHERE a = 7 AND id IN ();
SELECT * FROM Users WHERE id IN () OR a = 9;
would become:
SELECT * FROM Users;
SELECT * FROM Users WHERE a = 7;
SELECT * FROM Users WHERE a = 9;
That could get tricky depending on the complexity of your SQL - you'd basically need a full SQL language interpreter.
If your prepare-like function simply replaces :1 with the equivalent argument, you might try having your query contain something like (':1'), so that if :1 is empty, it resolves to (''), which will not cause a parse error (however it may cause undesirable behavior, if that field can have blank values -- although if it's an int, this isn't a problem). It's not a very clean solution, however, and you're better off detecting whether the array is empty and simply using an alternate version of the query that lacks the "IN (:1)" component. (If that's the only logic in the WHERE clause, then presumably you don't want to select everything, so you would simply not execute the query.)
I would use zero, assuming your "id" column is a pseudokey that is assigned numbers automatically.
As far as I know, automatic key generators in most brands of database begin at 1. This is a convention, not a requirement (auto-numbered fields are not defined in standard SQL). But this convention is common enough that you can probably rely on it.
Since zero probably never appears in your "id" column, you can use this value in the IN() predicate when your input array is empty, and it'll never match.
The only way I can think to do it would be to make your sqlf() function scan to see if a particular substitution comes soon after an "IN (" and then if the passed variable is an empty array, put in something which you know for certain won't be in that column: "m,znmzcb~~1", for example. It's a hack, for sure but it would work.
If you wanted to take it even further, could you change your function so that there are different types of substitutions? It looks like your function scans for a colon followed by a number. Why not add another type, like an # followed by a number, which will be smart to empty arrays (this saves you from having to scan and guess if the variable is supposed to be an array).

Categories