I've built a MySQL query that returns 452 entries when I try it via phpMyAdmin, here's the query :
SELECT csp.id FROM child_subscription_prices csp
JOIN child_moments cm ON csp.child_moment_id = cm.id
JOIN moments m ON cm.moment_id = m.id
JOIN poles p ON m.pole_id = p.id
JOIN persons pr ON pr.id = csp.payer_id
WHERE cm.day BETWEEN '2013-1-15' AND '2013-1-17' AND p.type_id IN (1,2,3) AND csp.center_id = 1
ORDER BY pr.lastname ASC
But when I call it using Ebean (Play!Framework 2.1.1), like this :
SimpleDateFormat format = new SimpleDateFormat("y-M-d");
StringBuilder querySql = new StringBuilder();
querySql.append("SELECT csp.id FROM child_subscription_prices csp ");
querySql.append("JOIN child_moments cm ON csp.child_moment_id = cm.id ");
querySql.append("JOIN moments m ON cm.moment_id = m.id ");
querySql.append("JOIN poles p ON m.pole_id = p.id ");
querySql.append("JOIN persons pr ON pr.id = csp.payer_id ");
querySql.append("WHERE cm.day BETWEEN :start AND :end AND p.type_id IN (:poles) AND csp.center_id = :center ");
querySql.append("ORDER BY pr.lastname ASC;");
SqlQuery query = Ebean.createSqlQuery(querySql.toString());
query.setParameter("start", format.format(start));
query.setParameter("end", format.format(end));
query.setParameter("poles", StringUtils.join(poleIds.toArray(), ","));
query.setParameter("center", Session.getCenter().getId());
List<SqlRow> rows = query.findList();
rows.size(); // Return 409 !!
Of course, I tested the parameter in Java and compared them, they are identical ! (I even updated my first query to match the dates (2013-01-15 => 2013-1-15, to be like the one made in Java!
I don't have any clue why I have 50 entries less using Java, is there a particular Ebean configuration that doesn't follow some related database for any reason, or something like this that would explain the differences ?
Update
I also tried to count the number of results from the SQL query made in Java:
querySql.append("SELECT COUNT(csp.id) as total FROM child_subscription_prices csp ");
// ...
query.findUnique().getLong("total"); // Also 409 !
So it clearly seems to be a difference between the configuration in PhpMyAdmin and EBean, but I can't see which one!
For information, the problem was coming from this line :
query.setParameter("poles", StringUtils.join(poleIds.toArray(), ","));
Instead, I just had to replace it to this :
// poleids is a List<Long>
query.setParameter("poles", poleIds);
And everything worked fine :)
Related
I need to join main (4-5) tables and get the latest from the inner join table to get the project current status.
investor have many investments
investments have many investment_details
investment_details has many status through project status
Select
siv.company_name
, siv.full_name
, si.permit_number
, si.project_name
, sid.investment_detailed_id
, sis.project_status_id
, sps.project_status_name
From sma_investors siv
Join sma_investments si
On siv.investor_id = si.investment_id
Join sma_investment_details sid
On si.investment_id = sid.investment_id
Inner Join sma_investment_status sis
On sis.investment_status_id = (
Select investment_status_id
From sma_investment_status s
Where s.investment_detailed_id = sid.investment_detailed_id
Order BY investment_status_id DESC LIMIT 1)
Join sma_project_status sps
On sis.project_status_id = sps.project_status_id
This works fine but I can't convert it the CI3.
There is no advantage to using Query Builder (QB) unless you need parts of the query to be written differently due to some condition. QB is also useful if you want user inputs to be automatically escaped. Otherwise, you simply run a whole lot of extra code that leads to the exact same SQL statement string you already have.
In your case, the sub-select will make the conversion even more difficult to accomplish and add a lot of extra code to be executed.
My advice is to keep it simple and use db->query(), e.g.
$sql = "Select siv.company_name, siv.full_name, si.permit_number, si.project_name
, sid.investment_detailed_id, sis.project_status_id, sps.project_status_name
From sma_investors siv
Join sma_investments si On siv.investor_id = si.investment_id
Join sma_investment_details sid On si.investment_id = sid.investment_id
Inner Join sma_investment_status sis On sis.investment_status_id = (
Select investment_status_id From sma_investment_status s
Where s.investment_detailed_id = sid.investment_detailed_id
Order BY investment_status_id DESC LIMIT 1)
Join sma_project_status sps On sis.project_status_id = sps.project_status_id";
$query = $this->db->query($sql);
if(! $query) // might be false if query fails
{
return null;
}
return $query->row(); // one row of data
I finally come up with my own solution and stick to the QB codding standard and it works as i expected
$q = $this->db->select('*')
->from('investors')
->join('investments', `enter code here`'investors.investor_id=investments.investment_id')
->join('investment_details as sid', 'investments.investment_id=sid.investment_id')
->join('investment_status', 'investment_status.investment_status_id=(select '.$this->db->dbprefix('investment_status').'.investment_status_id from '.$this->db->dbprefix('investment_status').' where '.$this->db->dbprefix('investment_status').'.investment_detailed_id=sid.investment_detailed_id order by '.$this->db->dbprefix('investment_status').'.investment_status_id Desc limit 1)', 'inner')
->join('project_status', 'investment_status.project_status_id=project_status.project_status_id')
->where('sid.company_type_id', 1)
->order_by('investments.investment_id', 'desc')
->limit(5)
->get();
In a rather small powershell script, I retrieve data from a sql database using invoke-sqlmd. The output is written into a variable. Later in the script, I want to use only one attribute of this result set in a foreach loop. How can I call on that specific attribute?
If the question was not well asked, please feel free to ask for further information.
This is the sqlcmd:
$SQLcmd = "Select * From (SELECT t.[Initiator] ,t.[EndTime] ,t.StartTime ,CONVERT(NVARCHAR(50), t.StartTime, 111) as Datum ,t.[Result] as Result ,GDI.[Name] ,P.DisplayString ,Pi.DisplayString as DisplayStringDeutsch FROM [M42STORE].$SQL_Table t join [dbo].[GDIEImportClassBase] GDI on GDI.ID = t.ImportSequence left join [dbo].[GDIEImportPickupResult] P on P.Value = t.Result left join [dbo].[GDIEImportPickupResult-CI] Pi on Pi.Owner = P.ID and Pi.LCID = 7 ) Q WHERE Result = '3'"
I'm using LINQPad in my effort to convert SQL to LINQ and learn LINQ in the process. I'm running into some problems, though, and was hoping someone could look at my resulting LINQ code to see if I'm on the right track?
Here's my SQL code:
Select Count(Convert(varchar(250),
Comment.CommentId)) as Num,
DiscussionBoard.ItemName,
Status.Status,
Status.Sequence
From Comment inner join status on Comment.StatusID = Status.StatusID
inner join DiscussionBoard on Comment.DiscussionBoardID
= DiscussionBoard.DiscussionBoardID
WHERE discussionboard.DiscussionBoardID
= '3ab7c139-317c-4450-9823-45a40ea6d0ff'
Group By status.Status,
Status.Sequence,
DiscussionBoard.ItemName
ORDER BY Status ASC
Here is the LINQ code that I've come up with so far. Bear with me, I'm just now learning LINQ and I haven't quite got my head around it. Any pointers would be greatly appreciated:
from Comment in Comments
where DiscussionBoard.DiscussionBoardID == '3ab7c139-317c-4450-9823-45a40ea6d0ff'
join Status in Statuses on Comment.StatusID equals Statuses.StatusID
join DiscussionBoard in DiscussionBoards on Comment.DiscussionBoardID equals DiscucussionBoard.DiscussionBoardID
group CountGroup by new {
Status.Status,
Status.Sequence,
DiscussionBoard.DiscussionBoardID
}
select new
{
Count = CountGroup.Count(),
DiscussionBoard.ItemName,
Status.Status,
Status.Sequence
}
group x by y
This fragment ends a query.
I think you meant:
group x by y into z
This fragment continues the query with z in scope. and removes all prior range variables from scope. z is an IGrouping<y, x>, which is to say, the key type is y's type and the group element type is x's type.
Here's my stab at your query:
from comment in Comments
where comment.DiscussionBoard.DiscussionBoardID == '3ab7c139-317c-4450-9823-45a40ea6d0ff'
let status = comment.Status
let board = comment.DiscussionBoard
group comment by new {
status.Status,
status.Sequence,
board.ItemName
} into g
select new
{
Count = g.Count(),
ItemName = g.Key.ItemName,
Status = g.Key.Status,
Sequence = g.Key.Sequence
}
Another way to open this query would be:
from board in DiscussionBoards
where board.DiscussionBoardID == '3ab7c139-317c-4450-9823-45a40ea6d0ff'
from comment in board.Comments
When this gets called two times, the second invocation doesn't re-run the query on the database, the query caching works.
var query = from p in session.Query<Product>()
where p.YearIntroduced >= 0
select p;
query = query.Cacheable();
var t = query.ToList();
However, when I put some join on the query, the query cache is not working anymore, hence when this is invoked two times, the query is invoked on database two times too:
var query = from p in session.Query<Product>()
join l in session.Query<ProductLanguage>()
on p.ProductId equals l.ProductId
where p.YearIntroduced >= 0
select new { p, l };
query = query.Cacheable();
var t = query.ToList();
Might be a dumb question, is query caching can work on one table only, hence when adding a join, the query is not cacheable anymore?
What's the solution to make a query cacheable even it has a join?
Another oddity, the query caching with join will work if I remove the where clause. When this gets called two times, the second invocation doesn't re-run the query on database, the query caching works
var query = from p in session.Query<Product>()
join l in session.Query<ProductLanguage>()
on p.ProductId equals l.ProductId
select new { p, l };
query = query.Cacheable();
var t = query.ToList();
But what's the use of a query when you can't put a where clause on it?
Is this an NHibernate bug, or am I just using query caching the wrong way?
Found the solution, put the Where clause on the final part of the query:
var query = from p in session.Query<Product>()
join l in session.Query<ProductLanguage>()
on p.ProductId equals l.ProductId
select new { p, l };
query = query.Where(x => x.p.ProductId && x.l.LanguageCode == "en").Cacheable();
var t = query.ToList();
I've got a sql statement, but I can't get it working in linq. Can someone show me how I can write the following sql statement as linq?
SELECT * FROM mobileApplication
LEFT JOIN videoMobile ON mobileApplication.id = videoMobile.mobileApplicationId
AND videoMobile.videoId = 257
It's a left join with a where statement on the right table. It works in sql server 2005, but I'd like to write it in linq.
I didn't verify the syntax, but try this...
var mobileApplications = from ma in mobileApplication
join vm in videoMobile on ma.id equals vm.mobileApplicationId into j1
from j2 in j1.DefaultIfEmpty()
where vm.videoId == 257
select ma;
There is a product that will do this for you. I have found it very useful. The product name is Linqer. It is not free, but not expensive, and offers a 30 day trial. I have found very few queries it is not able to convert. It has worked well for me.
http://www.sqltolinq.com/
Its something like:
from ma in mobiledApplication.DefaultIfEmpty()
join vm in videoMobile on new { mobileApplicationId = ma.id, videoId = 257 } equals new { mobileApplicationId = vm.mobileApplicationId, videoId = vm.videoId } into videoMobileApplication
from vma in videoMobileApplication
select vma
The keys being the default if empty and using anonymous objects on the join criteria to incorporate 257 into the join.
I am pretty sure that using a where clause for the 257 will achieve the same result though...
Try some like this:
var query =
from m in mobileApplication
join v in videoMobile
on m.id = v.mobileApplicationId and v.id = 257
select m;
See here:
http://msdn.microsoft.com/en-us/library/bb397676%28v=VS.100%29.aspx
http://msdn.microsoft.com/en-us/magazine/cc163400.aspx