How to Convert this sql query to Linq.
select sum(OutstandingAmt)from IvfReceiptDetails where IvfReceiptId IN(select IvfReceiptId from IvfReceipts where PatientId = 'SI-49650')
I think it is easier to translate SQL using query comprehension syntax instead of lambda syntax.
General rules:
Translate inner queries into separate query variables
Translate SQL phrases in LINQ phrase order
Use table aliases as range variables, or if none, create range variables from table names
Translate IN to Contains
Translate SQL functions such as DISTINCT or SUM into function calls on the entire query.
Here is the code:
var IvfReceiptIds = from IvfReceipt in IvfReceipts
where IvfReceipt.PatientId = "SI-49650"
select IvfReceipt.IvfReceiptId;
var OutstandingAmtSum = (from IvfReceiptDetail in IvfReceiptDetails
where IvfReciptIds.Contains(IvfReceiptDetail.IvfReceiptId)
select IvfReceiptDetail.OutstandingAmt).Sum();
Try this, First get all IvfReceiptId in array based on your inner query used in where condition then check contains. Change name of your _context if it's different.
var arrIvfReceiptId = _context.IvfReceiptDetails.Where(p=>p.PatientId == "SI-49650").ToArray();
var sum = (from ird in _context.IvfReceiptDetails.Where(p=> arrIvfReceiptId.Contains(p.IvfReceiptId))
select OutstandingAmt).Sum();
I'd like to get value by the following SQL using Eloquent ORM.
- SQL
SELECT COUNT(*) FROM
(SELECT * FROM abc GROUP BY col1) AS a;
Then I considered the following.
- Code
$sql = Abc::from('abc AS a')->groupBy('col1')->toSql();
$num = Abc::from(\DB::raw($sql))->count();
print $num;
I'm looking for a better solution.
Please tell me simplest solution.
In addition to #delmadord's answer and your comments:
Currently there is no method to create subquery in FROM clause, so you need to manually use raw statement, then, if necessary, you will merge all the bindings:
$sub = Abc::where(..)->groupBy(..); // Eloquent Builder instance
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder
->count();
Mind that you need to merge bindings in correct order. If you have other bound clauses, you must put them after mergeBindings:
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
// ->where(..) wrong
->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder
// ->where(..) correct
->count();
Laravel v5.6.12 (2018-03-14) added fromSub() and fromRaw() methods to query builder (#23476).
The accepted answer is correct but can be simplified into:
DB::query()->fromSub(function ($query) {
$query->from('abc')->groupBy('col1');
}, 'a')->count();
The above snippet produces the following SQL:
select count(*) as aggregate from (select * from `abc` group by `col1`) as `a`
The solution of #JarekTkaczyk it is exactly what I was looking for. The only thing I miss is how to do it when you are using
DB::table() queries. In this case, this is how I do it:
$other = DB::table( DB::raw("({$sub->toSql()}) as sub") )->select(
'something',
DB::raw('sum( qty ) as qty'),
'foo',
'bar'
);
$other->mergeBindings( $sub );
$other->groupBy('something');
$other->groupBy('foo');
$other->groupBy('bar');
print $other->toSql();
$other->get();
Special atention how to make the mergeBindings without using the getQuery() method
From laravel 5.5 there is a dedicated method for subqueries and you can use it like this:
Abc::selectSub(function($q) {
$q->select('*')->groupBy('col1');
}, 'a')->count('a.*');
or
Abc::selectSub(Abc::select('*')->groupBy('col1'), 'a')->count('a.*');
There are many readable ways to do these kinds of queries at the moment (Laravel 8).
// option 1: DB::table(Closure, alias) for subquery
$count = DB::table(function ($sub) {
$sub->from('abc')
->groupBy('col1');
}, 'a')
->count();
// option 2: DB::table(Builder, alias) for subquery
$sub = DB::table('abc')->groupBy('col1');
$count = DB::table($sub, 'a')->count();
// option 3: DB::query()->from(Closure, alias)
$count = DB::query()
->from(function ($sub) {
$sub->from('abc')
->groupBy('col1')
}, 'a')
->count();
// option 4: DB::query()->from(Builder, alias)
$sub = DB::table('abc')->groupBy('col1');
$count = DB::query()->from($sub, 'a')->count();
For such small subqueries, you could even try fitting them in a single line with PHP 7.4's short closures but this approach can be harder to mantain.
$count = DB::table(fn($sub) => $sub->from('abc')->groupBy('col1'), 'a')->count();
Note that I'm using count() instead of explicitly writing the count(*) statement and using get() or first() for the results (which you can easily do by replacing count() with selectRaw(count(*))->first()).
The reason for this is simple: It returns the number instead of an object with an awkwardly named property (count(*) unless you used an alias in the query)
Which looks better?
// using count() in the builder
echo $count;
// using selectRaw('count(*)')->first() in the builder
echo $count->{'count(*)'};
Correct way described in this answer: https://stackoverflow.com/a/52772444/2519714
Most popular answer at current moment is not totally correct.
This way https://stackoverflow.com/a/24838367/2519714 is not correct in some cases like: sub select has where bindings, then joining table to sub select, then other wheres added to all query. For example query:
select * from (select * from t1 where col1 = ?) join t2 on col1 = col2 and col3 = ? where t2.col4 = ?
To make this query you will write code like:
$subQuery = DB::query()->from('t1')->where('t1.col1', 'val1');
$query = DB::query()->from(DB::raw('('. $subQuery->toSql() . ') AS subquery'))
->mergeBindings($subQuery->getBindings());
$query->join('t2', function(JoinClause $join) {
$join->on('subquery.col1', 't2.col2');
$join->where('t2.col3', 'val3');
})->where('t2.col4', 'val4');
During executing this query, his method $query->getBindings() will return bindings in incorrect order like ['val3', 'val1', 'val4'] in this case instead correct ['val1', 'val3', 'val4'] for raw sql described above.
One more time correct way to do this:
$subQuery = DB::query()->from('t1')->where('t1.col1', 'val1');
$query = DB::query()->fromSub($subQuery, 'subquery');
$query->join('t2', function(JoinClause $join) {
$join->on('subquery.col1', 't2.col2');
$join->where('t2.col3', 'val3');
})->where('t2.col4', 'val4');
Also bindings will be automatically and correctly merged to new query.
I like doing something like this:
Message::select('*')
->from(DB::raw("( SELECT * FROM `messages`
WHERE `to_id` = ".Auth::id()." AND `isseen` = 0
GROUP BY `from_id` asc) as `sub`"))
->count();
It's not very elegant, but it's simple.
This works fine
$q1 = DB::table('tableA')->groupBy('col');
$data = DB::table(DB::raw("({$q1->toSql()}) as sub"))->mergeBindings($q1)->get();
I could not made your code to do the desired query, the AS is an alias only for the table abc, not for the derived table.
Laravel Query Builder does not implicitly support derived table aliases, DB::raw is most likely needed for this.
The most straight solution I could came up with is almost identical to yours, however produces the query as you asked for:
$sql = Abc::groupBy('col1')->toSql();
$count = DB::table(DB::raw("($sql) AS a"))->count();
The produced query is
select count(*) as aggregate from (select * from `abc` group by `col1`) AS a;
->selectRaw('your subquery as somefield')
Deriving off mpskovvang's answer, here is what it would look like using eloquent model. (I tried updating mpskovvang answer to include this, but there's too many edit requests for it.)
$qry = Abc::where('col2', 'value')->groupBy('col1')->selectRaw('1');
$num = Abc::from($qry, 'q1')->count();
print $num;
Produces...
SELECT COUNT(*) as aggregate FROM (SELECT 1 FROM Abc WHERE col2='value' GROUP BY col1) as q1
I'm trying to do a query with a select in another.
I would like to do something like:
select?q=*:* AND id_user=5&fl=id_other
select?q=test AND -id(the result of the other select)&fl=id
So:
select?q=test AND -id(select?q=* AND id_user=5&fl=id_other)&fl=id
Is it possible? Or I have to do two separates selects?
$ids = select?q=*:* AND id_user=5&fl=id_other
$result = select?q=test AND -id(implode(' AND ', $ids))&fl=id
Thanks!
There is a nested query support in Solr. You can _query_ parameter to embed query into another. Check this tutorial for more information.
I am trying to work out how to covert the script below from SQL in to LINQ. Any help would be welcome.
SELECT *
FROM
[tableName]
WHERE
[MyDate] IN
(SELECT
MAX([MyDate])
FROM
[tableName]
GROUP BY
[MyID])
I can't find an equivalent for the "IN" clause section. There are existing questions on this forum but none that cover selecting a DateTime.
Thanks in advance.
You can use the ".Contains(..)" function:
e.g.
var itemQuery = from cartItems in db.SalesOrderDetails
where cartItems.SalesOrderID == 75144
select cartItems.ProductID;
var myProducts = from p in db.Products
where itemQuery.Contains(p.ProductID)
select p;
Although it looks like 2 round trips, as the LINQ only constructs the query when the IEnumerable is tripped, you should get reasonable performance.
I think Any() is what you are looking for:
var result = tableName.Where(x =>
(from t in tableName
group t by t.MyID into g
where g.Max(y => y.MyDate) == x.MyDate
select 1).Any())
Customer.text is a field in an T-SQL DB (that I do not control and thus may not alter) of type "text".
I'd like to do something like this:
List<string> compare = new List<string>();
compare.Add("one");
compare.Add("two");
var q = from t in customer
where t.text.Contains( compare.First())
select t;
this will work.
But now I'd like to do something like: (!NOT WORKING!)
var q = from t in customer
where compare.Contains( t.text )
select t;
How can I achieve this? Is it even possible?
EDIT: The problem is obviously not exactly clear: A text column in SQL cannot be queried using "=" but only with LIKE. Thus the compare.Contains( t.text ) will result in an error, as it is converted into a query using "=".
What I did not tell - I thought it is irrelevant - is, that I use LINQ-to-ORM (LLBLGen in this case).
What I tried instead:
var q = from t in customer
where compare.Any( x => t.text.Contains(x) )
select t;
Now this did not work also. Currently I'm not at work, but the exception was something with a ConstantExpression not being convertable into a SetExpression.
I hope this gave some clarification.
EDIT2:
Joseph pointed this out to me: PredicateBuilder. It creates an Expression on a given ObjectType.
Now my problem is, that my type is an anonymous type out of multiple joins.
Is there an easy or elegant way to handle this?
Now I might be missing something, but your code looks like it should work. Did you include the namespaces at the top of the file?
using System.Linq;
using System.Linq.Expressions;
You could also rewrite it without the Linq2Sql syntax, like:
var q = customer.Where(c => compare.Contains(c.text));
You could build your query using LinqKit's free predicate builder class. Here is a blog post which describes its use and has a link to the download site.
http://thecodeslinger.wordpress.com/2008/10/28/linqkit-predicatebuildert-goodness/
Below is a code sample from the post
//First get a list of keywords that match the description entered.
string[] parts = txtInclude.Text.Split(new[] {‘ ‘});
string[] noparts = null;
if(txtButNot.Text.Trim().Length > 0)
noparts = txtExclude.Text.Trim().Split(new[] {‘ ‘});
var pred = PredicateBuilder.True<Pet>();
//here is where you would loop through your compare object
parts.ForEach(p => pred = pred.And(pl => pl.description.Contains(p)));
if(noparts != null)
noparts.ForEach(p => pred = pred.And(pl => !pl.description.Contains(p)));
var pets = from s in db.Pets.Where(pred)
select s;
You have to convert the text field to string
var query = from t in dataContext.table
where compare.Contains(t.textField.ToString())
select t;