Trick to use variable in match against mysql - mysql

Please first read my question,and then you will find out it is not a duplicate of other question.
I'm using sphinx search for 98% of search,but need to use match against for just one query.
As we know from mysql documentation that AGAINST only takes string.The search string must be a literal string, not a variable or a column name.
But I have found this link http://bugs.mysql.com/bug.php?id=66573 ,which says it is possible.But I'm not sure how to use that in my case.
Here is my code
$sqli="SELECT busi_title,category FROM `user`.`user_det`";
$queryi=mysqli_query($connecti,$sqli);
if(mysqli_num_rows($queryi)>0){
while($rowi=mysqli_fetch_assoc($queryi)){
$busi_title=$rowi['busi_title'];
$category=$rowi['category'];
}
}else{
echo "OH NO";
}
$sqlj="SELECT * FROM `user`.`user_det` WHERE MATCH(student) AGAINST('$busi_title','$category')";
$queryj=mysqli_query($connecti,$sqlj);
if(mysqli_num_rows($queryj)>0){
..............................
..............................
}else{
foreach ( $res["matches"] as $doc => $docinfo ) {
................................
...............................
}
}
MATCH() AGAINST() is giving error,as it supposed to be.How to use that trick of that link in this case.I don't know the use of #word:= of that link.
Thanks in advance.

That link doesn't show a trick to get around a limitation of MySQL. It's a bug report demonstrating an incorrect statement in the MySQL documentation. The statement in the documentation has now been corrected.
The reason you're getting an error is because you're sending two parameters to AGAINST and it only accepts one. You can use a MySQL variable in AGAINST which is what the bug report is about, but this has nothing to do with the PHP variable that you're using.
EDIT
Upon reading your response, I rather suspect that you have your syntax backwards.
SELECT * FROM `user`.`user_dets` WHERE MATCH(busi_title, category) AGAINST('student')
But note this from the documentation:
The MATCH() column list must match exactly the column list in some FULLTEXT index definition for the table, unless this MATCH() is IN BOOLEAN MODE. Boolean-mode searches can be done on nonindexed columns, although they are likely to be slow.
If you don't have a Fulltext index, you'll actually want this:
SELECT * FROM `user`.`user_dets` WHERE `busi_title` LIKE '%student%' OR `category` LIKE '%student%'

When they say "The search string must be a literal string, not a variable or a column name" does not mean you cannot use variable to create your Query String.
So it is OK to make your query very simple.
Your WHERE could be this:
WHERE `student` = $busi_title OR `student` = $category

Related

Why won't truncateTable work in Joomla 3.7?

I have the following code attempting to truncate a table. The Joomla documentation makes me believe this will work, but it does not. What am I missing?
$db = JFactory::getDbo();
truncate_query = $db->getQuery(true);
//$truncate_query = 'TRUNCATE ' . $db->quoteName('#__mytable');
$truncate_query->truncateTable($db->quoteName('#__mytable'));
$db->setQuery($truncate_query);
echo $truncate_query;
exit();
If I use the line that is commented out to manually generate the SQL, it does work. The reason I am still looking to use the truncateTable function is that I am trying to include the truncation in a transaction. When I use the manual statement, the table is still truncated even if another part of the transaction fails, which is annoying since the other statements rely on data that is truncated, so if the table is emptied when it shouldn't be there is no data left to run the transaction again. Very annoying!
Here's how you call/execute your truncation query:
JFactory::getDbo()->truncateTable('#__mytable');
And now some more details...
Here is the method's code block in the Joomla source code:
public function truncateTable($table)
{
$this->setQuery('TRUNCATE TABLE ' . $this->quoteName($table));
$this->execute();
}
As you can see the truncateTable() method expects a tablename as a string for its sole parameter; you are offering a backtick-wrapped string -- but the method already offers the backtick-wrapping service. (Even if you strip your backticks off, your approach will not be successful.)
The setQuery() and execute() calls are already inside the method, so you don't need to create a new query object nor execute anything manually.
There is no return in the method, so the default null is returned -- ergo, your $truncate_query becomes null. When you try to execute(null), you get nothing -- not even an error message.
If you want to know how many rows were removed, you will need to run a SELECT query before hand to count the rows.
If you want to be sure that there are no remaining rows of data, you'll need to call a SELECT and check for zero rows of data.
Here is my answer (with different wording) on your JSX question.

Asterisk phrase variables within variables?

I have a odd situation where I would like to phrase a variable inside an SQL string. Basically ODBC will return a query with a string, in that string there will be an Asterisk variable and I need that phrased and passed back to SQL. For example (pointless code but showing the example)-
exten => s,n,Set(QUERY=${ODBC_GET_QUERY(${EXTEN})})
The SQL query in func_odbc.conf is SELECT query FROM tablea WHERE number = ${ARG1}
Now QUERY will look like to = ${DIALED}, ${DIALED} being a asterisk variable (I will make it 17005551212 for example) I need that phrased so I end up with -
exten => s,n,Set(ALLOWED=${ODBC_GET_ALLOWED(${QUERY})})
The SQL query in func_odbc.conf would be SELECT allowed FROM tableb WHERE ${ARG1} so the SQL query would resolve to SELECT allowed WHERE to = 17005551212.
Before I dive into this and re-invent the wheel, is it possible or even allowed? I have actually not tried it yet. I know in a Set() statement it will phrase a variable inline, but is there a way to phrase variable that is in a variable when its returned via ODBC? Thanks!
Please read carefully source code.
Func odbc use prepair call. So it will not work for your example just becuase prepair do not allow do that.
In general you can substitute variables. Example 1 WILL work ok.
Workaround - use mysql EXEC.

MySQL REPLACE in UPDATE does not work properly

The following query:
select replace(`Abilities`, 'export_import', 'auto') from fl_account_types;
gives me 'auto,listings' correct replacement from Abilities column. However, when I execute:
update fl_account_types set `Abilities` = replace(`Abilities`, 'export_import', 'autos');
MySQL just omits 'export_import' string and replaces Abilities with 'listings' string.
What could be the reason?
The problem was that Abilities was of type SET and I was trying to replace with a value which was not listed in a definition of it. But I still do not understand why select replace works well and why MySQL do not throw an error.

Filter Dataset using SQL Query

I am using Zeos and mysql in my delphi project.
what I would like to do is filter dataset using a textbox.
to do that, I am using following query in textbox 'OnChange' Event:
ZGrips.Active := false;
ZGrips.SQL.Clear;
ZGrips.SQL.Add('SELECT Part_Name, Description, OrderGerman, OrderEnglish FROM Part');
ZGrips.SQL.Add('WHERE Part_Name LIKE ' + '"%' + trim(txt_search.Text) + '%"');
ZGrips.Active := true;
after I run and type first character in textbox, I get empty dataset in my DBGrid,
so DBGrid is showing nothing, then If I type second character I get some result in DBGrid. and even more strange behavior: if I will use AS Clause in my SQL Query like:
Part_Name AS blablabla,
Description AS blablabla,
OrderGerman AS OG,
OrderEnglish AS OE
in that case DBGrid is showing only 2 columns: Part_Name and Description, I dont understand why it is ignoring 3rd and 4th columns.
thanks for any help in advance.
Always use parameters
Firstly you need to use parameters, otherwise your query will break or worse when the user enters the wrong characters in the search box.
See: How does the SQL injection from the "Bobby Tables" XKCD comic work?
Parameters also makes you query faster, because the database engine only have to decode the query once.
If you change a parameter the engine will know that the query itself has not changed and will not re-decode it.
Don't use clear and add
Just supply the SQL as text in one go, it's faster.
This is esp. true in a loop, outside the loop you will not notice the difference.
Your code should read something like:
procedure TForm1.SetupSearch; //run this only once.
var
SQL: string;
begin
ZGrips.Active:= false;
SQL:= 'SELECT Part_Name, Description, OrderGerman, OrderEnglish FROM Part' +
'WHERE Part_Name LIKE :searchtext'); //note no % here.
ZGrips.SQL.Text:= SQL; //don't use clear and don't use SQL.Add.
end;
//See: http://docwiki.embarcadero.com/Libraries/XE2/en/Vcl.StdCtrls.TEdit.OnChange
procedure TForm1.Edit1Change(Sender: TObject);
begin
if Edit1.Modified then begin
Timer1.Active:= true;
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Active:= false;
if Edit1.Text <> ZGrips.Params[0].AsString then begin
ZGrips.Params[0].AsString:= Edit1.Text + '%'
ZGrips.Active:= true;
end;
end;
Use a timer
As per #MartinA's suggestion, use a timer and start the query only ever so often.
The wierd behaviour you're getting maybe because you're stopping and reactivating a new query before the old one has had time to finish.
The Params[index: integer] property is a bit faster than the ParamsByName property.
Although this does not really matter outside a loop.
Allow the database to use an index!
Using only a trailing wildcard % is faster than using a leading wildcard because the database can only use an index is there is a trailing wildcard.
If you want to use a leading wildcard, then consider storing the data in reverse order and use a trailing wildcard instead.
Full-text indexes are much better than like
Of course if you use both a leading and a trailing wild card then you have to use a full-text index.
In MySQL you'll than use the MATCH AGAINST syntax,
see: Differences between INDEX, PRIMARY, UNIQUE, FULLTEXT in MySQL?
and: Which SQL query is better, MATCH AGAINST or LIKE?
The lastest versions of MySQL support full-text indexes in InnoDB.
Remember to never use MyISAM, it's unreliable.

Why is my query wrong?

before i use alias for table i get the error:
: Integrity constraint violation: 1052 Column 'id' in field list is ambiguous
Then i used aliases and i get this error:
unknown index a
I am trying to get a list of category name ( dependant to a translation) and the associated category id which is unique. Since i need to put them in a select, i see that i should use the lists.
$categorie= DB::table('cat as a')
->join('campo_cat as c','c.id_cat','=','a.id')
->join('campo as d','d.id','=','c.id_campo')
->join('cat_nome as nome','nome.id_cat','=','a.id')
->join('lingua','nome.id_lingua','=','lingua.id')
->where('lingua.lingua','=','it-IT')
->groupby('nome.nome')
->lists('nome.nome','a.id');
The best way to debug your query is to look at the raw query Laravel generates and trying to run this raw query in your favorite SQL tool (Navicat, MySQL cli tool...), so you can dump it to log using:
DB::listen(function($sql, $bindings, $time) {
Log::info($sql);
Log::info($bindings);
});
Doing that with yours I could see at least one problem:
->where('lingua.lingua','=','it-IT')
Must be changed to
->where('lingua.lingua','=',"'it-IT'")
As #jmail said, you didn't really describe the problem very well, just what you ended up doing to get around (part of) it. However, if I read your question right you're saying that originally you did it without all the aliases you got the 'ambiguous' error.
So let me explain that first: this would happen, because there are many parts of that query that use id rather than a qualified table`.`id.
if you think about it, without aliases you query looks a bit like this: SELECT * FROM `cat` JOIN `campo_cat` ON `id_cat` = `id` JOIN `campo` ON `id` = `id_campo`; and suddenly, MySQL doesn't know to which table all these id columns refer. So to get around that all you need to do is namespace your fields (i.e. use ... JOIN `campo` ON `campo`.`id` = `campo_cat`.`id_campo`...). In your case you've gone one step further and aliased your tables. This certianly makes the query a little simpler, though you don't need to actually do it.
So on to your next issue - this will be a Laravel error. And presumably happening because your key column from lists($valueColumn, $keyColumn) isn't found in the results. This is because you're referring to the cat.id column (okay in your aliased case a.id) in part of the code that's no longer in MySQL - the lists() method is actually run in PHP after Laravel gets the results from the database. As such, there's no such column called a.id. It's likely it'll be called id, but because you don't request it specifically, you may find that the ambiguous issue is back. My suggestion would be to select it specifically and alias the column. Try something like the below:
$categories = DB::table('cat as a')
->join('campo_cat as c','c.id_cat','=','a.id')
->join('campo as d','d.id','=','c.id_campo')
->join('cat_nome as nome','nome.id_cat','=','a.id')
->join('lingua','nome.id_lingua','=','lingua.id')
->where('lingua.lingua','=','it-IT')
->groupby('nome.nome')
->select('nome.nome as nome_nome','a.id as a_id') // here we alias `.id as a_id
->lists('nome_nome','a_id'); // here we refer to the actual columns
It may not work perfectly (I don't use ->select() so don't know whether you pass an array or multiple parameters, also you may need DB::raw() wrapping each one in order to do the aliasing) but hopefully you get my meaning and can get it working.