Propel : How to use conditional clauses or results - propel

I would like Propel to create a query with conditional clauses and get conditional results.
For a MySQL example I would like something like :
SELECT product.id FROM product WHERE IF(product.promo=0, product.price, product.promo_price) > 100
And something like :
SELECT IF(product.promo=0, product.price, product.promo_price) AS price FROM product WHERE id=123
I dug the Propel documentation but keyword IF is just ubiquitous when I use search tool. Therefore here I am :
Which Method can I use to create such a query ?
I made it happen using where method :
ProductQuery::create()->where('IF(product.promo=0, product.price, product.promo_price) > ?', $myprice);
But I suppose it's only gonna work with MySQL.
What is the proper way to make it ?
Regards,
Etienne

Related

Collection Query Builder - orderBy multiple values

In my eloquent model, I have a location row. It holds 5 potential answers such as:
Hotel
Accommodation
Library
rest of the values
I want to perform an orderBy and want them to be listed as this order. Is there a way to achieve it with orderBy? Something like:
People::orderBy('location', ['Hotel, 'Library', 'Accommodation']);
What is the best way to achieve this?
So, you can achieve that by using:
People::orderByRaw("FIELD(location , 'Hotel, 'Library', 'Accommodation') ASC")
Of course, you may choose ASC or DESC.

Laravel Eloquent Conditional inside Query like PLSQL

I'm trying to do conditional statement inside Laravel query, is it possible?
In PLSQL I would do the following to do IF ELSE, can I do it in Laravel Eloquent ?
select *
from x
where x.id = 1
and ( (varName = 'all') OR (x.name = 'red') )
What's happening up there is user is picking from a drop downbox (varName), and is either picking all colors as 'all', or picking individual colors.
I know it would be easy to write two IF Else statements and duplicate the SQL with each condition, but I have a really big SQL, and don't want to duplicate the whole SQL twice just for something simple. Is it possible to do this in Laravel? Or are there other ways to achieve it?
You may use whereRaw for this, for example
...
->where('x.id','=',1)
->whereRaw('(varName = "all" or x.name="red")')
...
Please note that the raw query isn't escaped by default, so make sure to do this if your handling user input.

Case with Oracle SGBD

I am currently working with SpagoBI tool using the DBMS Oracle, I wanted to achieve a filter using a query that contains "Case" in the first place if no values are chosen at the filter, I will get a result of all columns, and when I chose a value from filter I will have another result proportional to this value.
I tried with this query:
select
price as price, qty as qty
from
HR.TEST
Where
year_column LIKE WHEN $P{year} = 'None' then year_column else $P{year} end
NB: I will filter through the year
$P{Year} is the value of the filter at the tool "SpagoBI" and its default value is None.
I tried this query using the MySQL DBMS and it works but with oracle it did not work.
Think of case as a function that returns a SQL type. In a predicate, you would always do
where f(x) <operator> expression
See this similar question in AskTom.

Laravel - Really struggling to understand eloquent

I'm fairly new to Laravel having come over from Codeigniter and for the most part I really like it, but I really can't get my head around Eloquent.
If I want to do a simple query like this:
SELECT * FROM site INNER JOIN tweeter ON tweeter.id = site.tweeter_id
I try doing something like this (with a "belongs to"):
$site = Site::with('tweeter')->find($site_id);
But now I have two queries and an IN() which isn't really needed, like so:
SELECT * FROM `site` WHERE `id` = '12' LIMIT 1
SELECT * FROM `tweeter` WHERE `id` IN ('3')
So I try and force a join like so:
$site = Site::join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->find($site_id);
And now I get an error like so:
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous
SQL: SELECT * FROM `site` INNER JOIN `tweeter` ON `tweeter`.`id` = `site.tweeter_id` WHERE `id` = ? LIMIT 1
Bindings: array (
0 => 12,
)
It's obvious where the error is, the where needs to use something like "site.id = ?". But I can't see anyway to make this happen?
So i'm just stuck going back to fluent and using:
DB::table('site')->join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->where('site.id','=',$site_id)->first()
I guess it's not a massive problem. I would just really like to understand eloquent. I can't help but feel that i'm getting it massively wrong and misunderstanding how it works. Am I missing something? Or does it really have to be used in a very specific way?
I guess my real question is: Is there anyway to make the query I want to make using Eloquent?
I actually find this behaviour advantageous. Consider this (I'll modify your example). So we have many sites and each has many tweeters. Each site has a lot of info in the DB: many columns, some of them text columns with lots of text / data.
You do the query your way:
SELECT * FROM site INNER JOIN tweeter ON tweeter.id = site.tweeter_id
There are two downsides:
You get lots of redundant data. Each row you get for a tweeter of the same site will have the same site data that you only need once so the communication between PHP and your DB takes longer.
How do you do foreach (tweeter_of_this_site)? I'm guessing you display all the sites in some kind of list and then inside each site you display all of it's tweeters. You'll have to program some custom logic to do that.
Using the ORM approach solves both these issues: it only gets the site data once and it allows you to do this:
foreach ($sites as $site) {
foreach($site->tweeters as $tweeter) {}
}
What I'm also saying is: don't fight it! I used to be the one that said: why would I ever use an ORM, I can code my own SQL, thank you. Now I'm using it in Laravel and it's great!
You can always think of Eloquent as an extension of Fluent.
The problem you're running into is caused by the find() command. It uses id without a table name, which becomes ambiguous.
It's a documented issue: https://github.com/laravel/laravel/issues/1050
To create the command you are seeking, you can do this:
$site = Site::join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->where('site.id', '=', $site_id)->first($fields);
Of course, your syntax with join()->find() is correct once that issue fix is adopted.

LINQ and Generated sql

suppose my LINQ query is like
var qry = from c in nwEntitiesContext.CategorySet.AsEnumerable()
let products = this.GetProducts().WithCategoryID(c.CategoryID)
select new Model.Category
{
ID = c.CategoryID,
Name = c.CategoryName,
Products = new Model.LazyList<Core.Model.Product>(products)
};
return qry.AsQueryable();
i just want to know what query it will generate at runtime....how to see what query it is generating from VS2010 IDE when we run the code in debug mode....guide me step by step.
There is not much to see here - it will just select all fields from the Category table since you call AsEnumerable thus fetching all the data from the Category table into memory. After that you are in object space. Well, depending on what this.GetProducts() does - and my guess it makes another EF query fetching the results into memory. If that's the case, I would strongly recommend you to post another question with this code and the code of your GetProducts method so that we can take a look and rewrite this in a more optimal way. (Apart from this, you are projecting onto a mapped entity Model.Category which again won't (and should not) work with Linq-to-Entities.)
Before reading into your query I was going to recommend doing something like this:
string sqlQueryString = ((ObjectQuery)qry).ToTraceString();
But that won't work since you are mixing Linq-to-Entities with Linq-to-objects and you will actually have several queries executed in case GetProducts queries EF. You can separate the part with your EF query and see the SQL like this though:
string sqlString = nwEntitiesContext.CategorySet.ToTraceString();
but as I mentioned earlier - that would just select everything from the Categories table.
In your case (unless you rewrite your code in a drastic way), you actually want to see what queries are run against the DB when you execute the code and enumerate the results of the queries. See this question:
exact sql query executed by Entity Framework
Your choices are SQL Server Profiler and Entity Framework Profiler. You can also try out LinqPad, but in general I still recommend you to describe what your queries are doing in more detail (and most probably rewrite them in a more optimal way before proceeding).
Try Linqpad
This will produce SELECT * FROM Categories. Nothing more. Once you call AsEnumerable you are in Linq-to-objects and there is no way to get back to Linq-to-entities (AsQueryable doesn't do that).
If you want to see what query is generated use SQL Profiler or any method described in this article.

Resources