cakephp with oracle: no group by? - oracle

Greetings,
I'm trying to use the 'group' parameter for a find using CakePHP.
The dbms is oracle and to my surprise it didn't work (no group by in the query).
Example:
$this->User->find('all', array('group' => 'id'));
The query returned:
select * from users User where 1 = 1;
digging around the source code at the DboOracle::renderStatement() I found this:
return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$order} {$limit}";
I was surprised not seeing a {$group}, so I look around and found out that some of the dbo_ files do actually have {$group} included in the query, for example dbo_source.php
return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order} {$limit}";
Does this mean that cake doesn't support group by statement on oracle? Or is there a workaround that I'm not aware of?

This is a known problem that was recently fixed. Check this link

Related

Pagination with JPA and Oracle database

This week i was looking into a sorting issue in a WebApp. Sorting a table in the browser by a selected column did not work properly. It turned out that in the application, we used JPAs CriteriaQuery to create the query and then create a TypedQuery for the pagination as follows:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SomeEntity> q = cb.createQuery(SomeEntity.class);
Root<SomeEntity> c = q.from(SomeEntity.class);
q.select(c);
...
q.orderBy(cb.asc(c.get("SomeColumn")));
TypedQuery<> query = em.createQuery(q);
query.setFirstResult(pageIx * pageSize);
query.setMaxResults(pageSize);
...
This is pretty much how the documentation suggests to create queries (see here).
In the logs i saw that this generates an SQL query like this:
select * from (
select lots_of_columns from some_view order by selected_column
) where rownum <= 50
Since Oralce 10 the ordering of the enclosed select has no effect according to the documentation and, if i remember correctly, this also makes sense according to relational algebra. We use Oracle 12c.
So my question is, how am i supposed to takle this correctly?
I have found that offset and fetch should be used but i couldn't find how to tell JPA to generate the SQL accordingly. Also i have found a post that suggested to add the id to the order by clause, however this did not solve the problem either.
Thank you in advance for any thoughts and hints on the topic.

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.

hibernate - using 'having' without group by clause in hql

im trying to run an hql query which aggragets (sum) number of transactions made on a specific account, i dont need a group by since my where clause has a specific account filter (where account = :account)
i do, however, want to return the aggregated value only if it is smaller/bigger than some given value.
when im adding 'having' after the where clause without 'group by' im getting an error -
unexpected token: having
in native sql i succeeded adding 'having' without group by
any ideas on how to make it work with hql?
thanks alot
The reason why databases don't let you mix grouped columns with non-grouped and non-aggregated ones is, that for non-grouped/non-aggregated columns it would have to choose one row's value per group, but doesn't know how to pick one.
If you don't care, then you could just leave it away and if it doesn't matter because they're all the same, you could group by them, too.
It is not hql, but if you have native query, then run it like:
Query query = session.createSQLQuery("select, *** ,... blah blah")
//set If you need
query.setParameter("myparam", "val");
List result = query.list();
In my eyes this is nonsense. 'having' is done for conditions on a 'group by' result. If you don't group, then it does not make much sense.
I would say HQL can't do it. Probably the Hibernate programmers didn't think of this case because they considered it as not important.
And anyway, you don't need it.
If it is a simple query, then you can decide in your java code if you want the result or if you don't need it.
If it is in a subselect, then you can solve the problem with a where condition in the main select.
If you think it is really necessary then your invited to give a more concrete example.

how to properly order_by(time) in codeigniter

How do I do the order_by part in codeigniter?
SELECT <field> FROM <table> ORDER BY STR_TO_DATE( <field>, '%H:%i' ) DESC LIMIT 0 , 30
Tried this but it takes "'%H:%i')" as the field name.
$this->db->order_by("STR_TO_DATE(".$field.", '%H:%i')", $order);
The field is a varchar and the query I posted returns the result that I want but I don't know how to do it in codeigniter
I don't think you can do that in CodeIgniter in version 2.1.0. As Madmartigan put it, the comma trigger CI to wrap the wrong part in the backticks and thus giving the mysql error. I think there is no point digging into active record on the order_by function to find a workaround than a real fix for this to work. I check into the upstream and apparently, they have something which is interesting, you might want to keep an eye when is that released.
I didn't spend more time to find workaround in active record order_by but resort to this alternative which seem to work fine. Consider the following?
$sql = "SELECT <field> FROM <table> ORDER BY STR_TO_DATE(?, '%H:%i') desc LIMIT 0, 30";
$this->db->query($sql, array('19:20'));

Cache and SqlCacheDependency (ASP.NET MVC)

We need to return subset of records and for that we use the following command:
using (SqlCommand command = new SqlCommand(
"SELECT ID, Name, Flag, IsDefault FROM (SELECT ROW_NUMBER() OVER (ORDER BY #OrderBy DESC) as Row, ID, Name, Flag, IsDefault FROM dbo.Languages) results WHERE Row BETWEEN ((#Page - 1) * #ItemsPerPage + 1) AND (#Page * #ItemsPerPage)",
connection))
I set a SqlCacheDependency declared like this:
SqlCacheDependency cacheDependency = new SqlCacheDependency(command);
But immediately after I run the command.ExecuteReader() instruction, the hasChanged base property of the SqlCacheDependency object becomes true although I did not change the result of the query in any way! And, because of this, the result of this query is not kept in cache.
HttpRuntime.Cache.Insert( cacheKey, list, cacheDependency, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(AppConfiguration.CacheExpiration.VeryLowActivity));
Is it because the command has 2 SELECT statements? Is it ROW_NUMBER()? If yes, is there any other way to paginate results?
Please help! After too many hours, a little will be greatly appreciated! Thank you
Running into the same issue and finding the same answers online without any help, I was reasearching the xml invalid subsicription response from profiler.
I found an example on msdn support site that had a slightly different order of code. When I tried it I realized the problem - Don't open your connection object until after you've created the command object and the cache dependency object. Here is the order you must follow and all will be good:
Be sure to enable notifications (SqlCahceDependencyAdmin) and run SqlDependency.Start first
Create the connection object
Create the command object and assign command text, type, and connection object (any combination of constructors, setting properties, or using CreateCommand).
Create the sql cache dependency object
Open the connection object
Execute the query
Add item to cache using dependency.
If you follow this order, and follow all other requirements on your select statement, don't have any permissions issues, this will work!
I believe the issue has to do with how the .NET framework manages the connection, specifically what settings are set. I tried overriding this in my sql command test but it never worked. This is only a guess - what I do know is changing the order immediately solved the issue.
I was able to piece it together from the following to msdn posts.
This post was one of the more common causes of the invalid subscription, and shows how the .Net client sets the properties that are in contrast to what notification requires.
https://social.msdn.microsoft.com/Forums/en-US/cf3853f3-0ea1-41b9-987e-9922e5766066/changing-default-set-options-forced-by-net?forum=adodotnetdataproviders
Then this post was from a user who, like me, had reduced his code to the simplest format. My original code pattern was similar to his.
https://social.technet.microsoft.com/Forums/windows/en-US/5a29d49b-8c2c-4fe8-b8de-d632a3f60f68/subscriptions-always-invalid-usual-suspects-checked-no-joy?forum=sqlservicebroker
Then I found this post, also a very simple reduction of the problem, only his was a simple issue - needing 2 part name for tables. In his case the suggestion resolved the issue. After looking at his code I noticed the main difference was waiting to open the connection object until AFTER the command object AND the dependency object were created. My only assumption is under the hood (I have not yet started reflector to check so only an assumption) the Connection object is opened differently, or order of events and command happen differently, because of this association.
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/bc9ca094-a989-4403-82c6-7f608ed462ce/sql-server-not-creating-subscription-for-simple-select-query-when-using-sqlcachedependency?forum=sqlservicebroker
I hope this helps someone else in a similar issue.
Just a guess, but could it be because your SELECT statement doesn't have an ORDER BY clause?
If you don't specify an explicit ordering then it's possible for the query to return the results in any order each time it is run. Maybe this is causing the SqlCacheDependency object to think that the results have changed.
Try adding an ORDER BY clause:
SELECT ID, Name, Flag, IsDefault
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY #OrderBy DESC) AS Row,
ID, Name, Flag, IsDefault
FROM dbo.Languages
) AS results
WHERE Row BETWEEN ((#Page - 1) * #ItemsPerPage + 1) AND (#Page * #ItemsPerPage)
ORDER BY Row
i'm no expert on SqlCacheDependency, in fact, i found this question whilst looking for answers to my own issues with it! However, i believe the reason your SqlCacheDependency is not working is because your SQL contains a nested sub query.
Take a look at the documentation which lists what you can/can not use in your SQL: Creating a Query for Notification
"....The statement must not contain subqueries, outer joins, or self-joins....."
I also found some invaluable troubleshooting info from a guy at Redgate here: Using and Monitoring SQL 2005 Query Notification that helped me solve my own problem: By using Sql Profiler to trace the QN events he suggests, i was able to spot my connection was incorrectly using the 'SET ARITHABORT OFF' option, causing my notifications to fail.

Resources