How To Use MATCH In Symfony2 Database Query - mysql

I'm building a search feature for my Symfony2 project, and I wrote the SQL for it as follows:
SELECT dlc.title, dlc.description, dlc.keywords
FROM ShoutMainBundle:Dlc dlc
WHERE MATCH (dlc.title, dlc.description, dlc.keywords) AGAINST (":keyword" IN BOOLEAN MODE)
AND dlc.type = (":audio")
ORDER BY dlc.date DESC
However, when I run this in the project the following error is given:
[Syntax Error] line 0, col 96: Error: Expected known function, got
'MATCH'
Is there an alternative I could use instead of MATCH? At the moment (just so I can do basic testing) I'm using LIKE, but it doesn't work too well if it's more than one word being used to search with.
EDIT:
This is how the code is used within the code:
$em = $this->getDoctrine()->getEntityManager();
$wckeyword = '%'.$skeyword.'%';
$dlcresult = $em->createQuery('
SELECT dlc.title, dlc.description, dlc.keywords
FROM ShoutMainBundle:Dlc dlc
WHERE MATCH (dlc.title, dlc.description, dlc.keywords) AGAINST (":keyword" IN BOOLEAN MODE)
AND dlc.type = (":audio")
ORDER BY dlc.date DESC'
)->setParameters(array('type' => $stype, 'keyword' => $wckeyword));
$dlcres = $dlcresult->getResult();

Doctrine doesn't support that out-of-the-box, true. But you can:
Create custom functions for DQL yourself
Use native SQL and custom hydration

This is not currently possible with Doctrine2 ORM. As Doctrine supports many different database vendors and most of them don't have a FULLTEXT search feature, it's not supported at all.
You can always use Doctrine2 DBAL for searching. You lose all these nifty orm features, but in my practice they aren't that needed in searching situations anyway.

Related

Conditional order by in Propel ORM with a dot in the condition

I'm trying to build the following query in propel
SELECT *
FROM user
ORDER BY username = 'foo.bar' DESC, username
These options all give me errors:
UserQuery::create()
->addAscendingOrderByColumn("username = 'foo.bar'")
This is caused due to the ".". Without it's working
Errormessage:
"Criteria:(Error: Cannot fetch TableMap for undefined table: username = 'foo)"
Sadly, this is not possible in Propel 1 (nor do I know if it's possible with Propel 2). I had a similar issue:
https://groups.google.com/forum/#!topic/propel-users/sz3wA_bdF8k
And upon further investigation, I discovered that you can only pass column names and fully qualified names (table.column) into the ORDER BY methods. Switch statements do work in ->withColumn clauses though, for anyone who's trying to do something similar.

Can't access SQL column aliases in Rails 4.1

After upgrading my rails app from 3.2 to 4.1.13 one of my queries doesn't seem to be making aliased columns available to ActiveRecord (I think). If I run .to_sql and query using that SQL I can clearly see the aliased columns are being returned but when I try to access them like I used to I get undefined method errors.
I'm not sure how to troubleshoot this.
The query is built from a Ransack search and some Squeel joins.
search_result = search.result.in_current_club_type.
joins{role.outer}.joins{contact.outer}.for_current_or_last_year.with_fellowship.
select(<<-SQL
people.id, people.last_name, people.first_name, people.parent_only, clubs.name AS club_name,
roles.name AS role_name, tlt, master_guide, pla, grade, people.type, people.email,
contacts.primary_phone AS phone
SQL
)
The aliases I'm needing to access are role_name, club_name, and phone. I've placed a binding.pry right after that and attempt search_result.first.role_name and the returned error is
NoMethodError: undefined method `role_name' for #<Member:0x007fa8bcf121d0>
I could turn those into instance methods, but I'd like to be able to continue with the existing way of doing things if possible.
Thank you for your guidance.
Ok, I don't know exactly why but it seems that search was being built from a scope that needed to be rewritten using Squeel syntax. Then things joined properly and I could call the aliased columns.
Old Scope
scope :unapproved, -> { joins(approvals).where('approvals.approved IS NULL OR approvals.approved = ?', false) }
New Scope
scope :unapproved, -> { joins{approvals}.where{(approvals.approved == nil) | (approvals.approved == false)} }

What does it mean the colon in queries yii2 framework?

I'm totally new in yii2 and I want to know what does it mean the colon in the query?
I have made a research about binding parameters, but in the yii2 documentation says:
// returns all inactive customers
$sql = 'SELECT * FROM customer WHERE status=:status';
which side is from the data base? the left side or the right side?
which is a simple text and which one is a column from the DB? Im so confused.
what would be another way to make the query without the colon? is it valid?
why it has 'anyo = **:**valor' in the next example? and some others dont?
$dbLibro = Libro::find()->where('tipo = "Nacimiento"')->andWhere('cerrado = 0')->andWhere('anyo = :valor',[':valor'=>date("Y")])->one();
I hope its clear cause the documentation is a bit confusing for me.
The colons are not directly related with Yii2, it's related with PHP PDO extension that used by Yii2.
Each colon is placeholder used later for binding value. Check for example this question.
If we write this query in ActiveQuery:
SELECT * FROM customer WHERE status = :status
we can get something like this:
$query = Customer::find()->where('status = :status', [':status' => Customer::STATUS_ACTIVE]);
Assuming STATUS_ACTIVE constant equals to 1, after execution it transforms to this:
SELECT * FROM "customer" WHERE status = 1
So the left side (before equals) represents column name, right part - value which will be safely binded after.
But you don't have to write params by yourself, Yii2 QueryBuilder generates it automatically for you.
There are other ways to write query without colons and they are used more often. This query can be written like this:
$query = Customer::find(['status' => Customer::STATUS_ACTIVE]);
$models = $query->all();
Or like this using shortcut:
$models = Customer::findAll(['status' => Customer::STATUS_ACTIVE]);
Or it can be even put inside of a scope:
$models = Customer::find()->active();
In this case Yii generates parameters automatically and it will be equivalent to this:
SELECT * FROM "customer" WHERE "status"=:qp1
Value 1 will be binded to :qp1 parameter, note that in this case column names are also double quoted.
If you try to use more conditions, params will be :qp2, :qp3 and so on (default PARAM_PREFIX is :qp).
As for your second query, it can be rewritten like this:
$model = Libro::find()
->where([
'tipo' => 'Nacimiento',
'cerrado' => 0,
'anyo' => date('Y'),
])->one();
Such queries look way better and readable in this state.
Yii2 allows generate even more complex conditions in queries, check this section of the docs for more details.
P.S. It's better to use english for naming in your code. Think about other international developers supporting your code. date('Y') can be calculated using database functions depending on used RDBMS.

Switched MySQL to Postgres: "column must appear in the GROUP BY clause or be used in an aggregate function"

Switching a rails app from MySQL to Postgres gives the following error:
ERROR: column "contacts.id" must appear in the GROUP BY clause or be used in an aggregate function
Here is the scope in question:
class User < MyModel
def self.top_contacts(timeframe = 1.week.ago, limit = 5)
Contact.unscoped
.where('created_at between ? and ?', timeframe, Time.now)
.group(:user_id)
.order('sum(score) DESC')
.limit(limit)
.includes(:user)
.collect{|x| x.user}
end
end
How to fix this?
Isn't using Rails as the database abstraction layer ensure switching the database should work seamlessly?
The problem is on the level of the SQL, which is invisible from your ORM layer. The problem is exactly with the RoR ORM, because it seems to generate a MySQL-friendly query which uses an extraordinary feature of the MySQL, which postgresql don't have.
The quick solution: give contacts.id to the columns by which you are GROUP-ing as well:
.group("user_id, contacts.id");

how to use string left function in hql

I have a sql query like this
select column from table where path = left('INPUTSTRING', length(path));
and trying to accomplish it in hql like this,
return session.createQuery("from Table where Path = left(:input, length(Path))").
query.setParameter("input", inputPath).
.list();
and getting an error like this
Caused by: org.hibernate.hql.ast.QuerySyntaxException: unexpected token: left near line 1
how to get this done? What is the corresponding string function in hql? Is there a solution for this using criteria query apis?
Yes, left() is not supported by the MySQLDialect. See the list of HQL supported functions on API docs.
Now you have left with 2 options.
Use session.createSQLQuery() method.
Create Your own Dialect class by extending the MySQLDialect and register the function there. This is told at hibernate forum here explained well in a blog post here.
I'm not sure if HQL does this for you , but you can use IQuery/session.CreateSQLQuery() to use a raw SQL query to populate a mapped entity. I've never used it for substrings, but have used it for aggregate functions. Check chapter 13 of the NHibernate docs and see if that does it for you. You can check the query substitution available in Nhibernate - here