LINQ subquery IN - linq-to-sql

I'm a newbie with the IQueryable, lambda expressions, and LINQ in general. I would like to put a subquery in a where clause like this :
Sample code :
SELECT * FROM CLIENT c WHERE c.ETAT IN (
SELECT DDV_COLUMN_VAL FROM DATA_DICT_VAL
WHERE TBI_TABLE_NAME = 'CLIENT' AND DD_COLUMN_NAME = 'STATUS'
AND DDV_COLUMN_VAL_LANG_DSC_1 LIKE ('ac%'))
How do I translate this in LINQ ?

var innerquery = from x in context.DataDictVal
where x.TbiTableName == myTableNameVariable
&& x.DdColumnName == "Status"
&& x.DdbColumnValLangDsc1.StartsWith("ac")
select x.DdvColumnVal;
var query = from c in context.Client
where innerquery.Contains(c.Etat)
select c;

from c in db.Client
where (from d in db.DataDictVal
where d.TblTableName == "Client"
&& d.DDColumnName == "Status"
&& dd.DdvColumnValLandDsc1.StartsWith("ac"))
.Contains(c.Etat)
select c;

If you are new to Linq, you absolutely need two essential tools. The first is a tool that converts most T-SQL statements to Linq called Linqer (http://www.sqltolinq.com/). This should take care of the query in your question. The other tool is LinqPad (http://www.linqpad.net/). This will help you learn Linq as you practice with queries.
I often use Linqer to convert a T-SQL query for me, and then use LinqPad to fine tune it.

Same example with Linq method syntax:
var innerquery = dbcontext.DataDictVal
.where(x=> x.TbiTableName == myTableNameVariable
&& x.DdColumnName == "Status"
&& x.DdbColumnValLangDsc1.StartsWith("ac"))
.select(x=>x.DdvColumnVal)
var query = dbcontext.Client
.where( c=>innerquery.Contains(c.Etat))
Note:
Am providing this answer, because when i searched for the answer, i couldn’t find much answer which explains same concept in the method syntax.
So In future, It may be useful for the people, those who intestinally searched method syntax like me today.
Thanks
karthik

Related

Codeigniter sql binding

How do I use Codeigniter SQL Binding if there are two target dates?
Is how I did it below correct?
public function getInvestmentForBorrowing($id, $Interest, $Currency, $Loantime, $target_date, $Risk_category)
{
$query = '
select CASE WHEN (a.amount_financed - a.amount_invested - a.amount_withdrawn) < a.amount_per_borrower
THEN round((a.amount_financed - a.amount_invested - a.amount_withdrawn), 2)
ELSE round((a.amount_per_borrower) , 2)
END AS investable_amount, a.*,
c.IBAN as Return_IBAN, c.BIC as Return_BIC,
i.average_rate
from investment a
inner join userinfo c
on a.Owner = c.Owner and
c.UPDATE_DT is null
inner join exchange_rates i
on a.Currency = i.currency_id and
? between i.effective_dt and i.expiration_dt
where a.ORIG_ID = ? and
a.Interest <= ? and
a.Currency = ? and
a.status = 2 and
a.Loantime >= ? and
a.Available >= ? and
a.Risk <= ? and
a.UPDATE_DT is null
having investable_amount > 0';
$query = $this->db->query($query, array($target_date, $id ,$Interest, $Currency, $Loantime ,$target_date ,$Risk_category));
$result = $query->result();
return $result;
}
Write now the question marks just represent the array so I added two $target_date to the array but not sure if thats the right way to do it.
It appears to be ok according to the codeigniter documentation but i say that without regard to your original SQL being correct or not.
Just make sure that the number of ? match the number of values you are providing and they are in the right order.
One way to sanity check it, apart from just running it, is to place the following command right after you perform the query:
echo $this->db->last_query();
And providing it known data, you can cheat and just hard code some dummy values for testing, take the generated SQL and throw that into something like phpmyadmin and run it the generated SQL against the Database and see if it works with the expected results.
Just a side note regarding your variable naming style. I see you are mixing cases i.e. things like $target_date (all lower case) and $Risk_category (First letter uppercase). Just be aware that on a linux based system case does matter and mixing like that can cause errors. It's a good idea to decide on one and stick with it.

Is there a nesting levels limit with expressions used in SSIS packages?

Working in SQL Server 2008. My first stab at an SSIS script and I need to emulate some if/then conditional logic written in VB.net. I couldn't find any previous questions dealing with nested conditions in expressions and believe I'm following what I've been able to uncover via google on nested conditions in a derived column.
I'm receiving an error while attempting to use nested conditions in the derived column transformation editor. The error I'm receiving indicates that SSIS could not parse my expression. The actual exception: "Exception from HRESULT: 0xC0204006 (Microsoft.SqlServer.DTSPipelineWrap)"
Questions for which the answers might immediately answer my question (and create a new problem):
is there a nesting levels limit?
can nesting be performed in the condition1 portion of [expression] ? [condition1] : [condition2]
I'll give two snippets, the first is what I'm actually inserting, the second is a more reader-friendly version. Hopefully someone can point out my error.
Not sure that it has bearing, but please note that [BusArea] is a column derived in a previous step.
actual expression:
[BusArea] == "CCC" || [BusArea] == "NBU" || [BusArea] == "CA" ? (ISNULL([CASE_MORG]) or TRIM([CASE_MORG]) == "" ? ( ISNULL([TRX_MORG]) or TRIM([TRX_MORG]) == "" ? NULL(DT_WSTR,50) : [TRX_MORG]) : [CASE_MORG]) : (ISNULL([CASE_AGT]) or TRIM([CASE_AGT]) == "" ? ( ISNULL([TRX_AGT]) or TRIM([TRX_AGT]) == "" ? NULL(DT_WSTR,50) : [TRX_AGT]) : [CASE_AGT])
formatted for easier reading:
[BusArea] == "CCC" || [BusArea] == "NBU" || [BusArea] == "CA" ?
(ISNULL([CASE_MORG]) or TRIM([CASE_MORG]) == "" ?
( ISNULL([TRX_MORG]) or TRIM([TRX_MORG]) == "" ?
NULL(DT_WSTR,50)
: [TRX_MORG]
)
: [CASE_MORG]
)
: (ISNULL([CASE_AGT]) or TRIM([CASE_AGT]) == "" ?
( ISNULL([TRX_AGT]) or TRIM([TRX_AGT]) == "" ?
NULL(DT_WSTR,50)
: [TRX_AGT]
)
: [CASE_AGT]
)
I don't think there is any limit with nesting conditions. Even if there is one, I don't think we will reach the limit in the packages that we create handle our business processes.
You almost got everything correct. The issue with your conditional statement is that you have used or instead of ||
I copied your exact statement and pasted in Derived Transformation within a Data Flow task and got an error because the package couldn't parse the expression. I replaced all the or's with correct Logical OR (||) operator and the expression evaluated correctly.

Could not format node 'Value' for execution as SQL

I've stumbled upon a very strange LINQ to SQL behaviour / bug, that I just can't understand.
Let's take the following tables as an example: Customers -> Orders -> Details.
Each table is a subtable of the previous table, with a regular Primary-Foreign key relationship (1 to many).
If I execute the follow query:
var q = from c in context.Customers
select (c.Orders.FirstOrDefault() ?? new Order()).Details.Count();
Then I get an exception: Could not format node 'Value' for execution as SQL.
But the following queries do not throw an exception:
var q = from c in context.Customers
select (c.Orders.FirstOrDefault() ?? new Order()).OrderDateTime;
var q = from c in context.Customers
select (new Order()).Details.Count();
If I change my primary query as follows, I don't get an exception:
var q = from r in context.Customers.ToList()
select (c.Orders.FirstOrDefault() ?? new Order()).Details.Count();
Now I could understand that the last query works, because of the following logic:
Since there is no mapping of "new Order()" to SQL (I'm guessing here), I need to work on a local list instead.
But what I can't understand is why do the other two queries work?!?
I could potentially accept working with the "local" version of context.Customers.ToList(), but how to speed up the query?
For instance in the last query example, I'm pretty sure that each select will cause a new SQL query to be executed to retrieve the Orders. Now I could avoid lazy loading by using DataLoadOptions, but then I would be retrieving thousands of Order rows for no reason what so ever (I only need the first row)...
If I could execute the entire query in one SQL statement as I would like (my first query example), then the SQL engine itself would be smart enough to only retrieve one Order row for each Customer...
Is there perhaps a way to rewrite my original query in such a way that it will work as intended and be executed in one swoop by the SQL server?
EDIT:
(longer answer for Arturo)
The queries I provided are purely for example purposes. I know they are pointless in their own right, I just wanted to show a simplistic example.
The reason your example works is because you have avoided using "new Order()" all together. If I slightly modify your query to still use it, then I still get an exception:
var results = from e in (from c in db.Customers
select new { c.CustomerID, FirstOrder = c.Orders.FirstOrDefault() })
select new { e.CustomerID, Count = (e.FirstOrder != null ? e.FirstOrder : new Order()).Details().Count() }
Although this time the exception is slightly different - Could not format node 'ClientQuery' for execution as SQL.
If I use the ?? syntax instead of (x ? y : z) in that query, I get the same exception as I originaly got.
In my real-life query I don't need Count(), I need to select a couple of properties from the last table (which in my previous examples would be Details). Essentially I need to merge values of all the rows in each table. Inorder to give a more hefty example I'll first have to restate my tabels:
Models -> ModelCategoryVariations <- CategoryVariations -> CategoryVariationItems -> ModelModuleCategoryVariationItemAmounts -> ModelModuleCategoryVariationItemAmountValueChanges
The -> sign represents a 1 -> many relationship. Do notice that there is one sign that is the other way round...
My real query would go something like this:
var q = from m in context.Models
from mcv in m.ModelCategoryVariations
... // select some more tables
select new
{
ModelId = m.Id,
ModelName = m.Name,
CategoryVariationName = mcv.CategoryVariation.Name,
..., // values from other tables
Categories = (from cvi in mcv.CategoryVariation.CategoryVariationItems
let mmcvia = cvi.ModelModuleCategoryVariationItemAmounts.SingleOrDefault(mmcvia2 => mmcvia2.ModelModuleId == m.ModelModuleId) ?? new ModelModuleCategoryVariationItemAmount()
select new
{
cvi.Id,
Amount = (mmcvia.ModelModuleCategoryVariationItemAmountValueChanges.FirstOrDefault() ?? new ModelModuleCategoryVariationItemAmountValueChange()).Amount
... // select some more properties
}
}
This query blows up at the line let mmcvia =.
If I recall correctly, by using let mmcvia = new ModelModuleCategoryVariationItemAmount(), the query would blow up at the next ?? operand, which is at Amount =.
If I start the query with from m in context.Models.ToList() then everything works...
Why are you looking into only the individual count without selecting anything related to the customer.
You can do the following.
var results = from e in
(from c in db.Customers
select new { c.CustomerID, FirstOrder = c.Orders.FirstOrDefault() })
select new { e.CustomerID, DetailCount = e.FirstOrder != null ? e.FirstOrder.Details.Count() : 0 };
EDIT:
OK, I think you are over complicating your query.
The problem is that you are using the new WhateverObject() in your query, T-SQL doesnt know anyting about that; T-SQL knows about records in your hard drive, your are throwing something that doesn't exist. Only C# knows about that. DON'T USE new IN YOUR QUERIES OTHER THAN IN THE OUTER MOST SELECT STATEMENT because that is what C# will receive, and C# knows about creating new instances of objects.
Of course is going to work if you use ToList() method, but performance is affected because now you have your application host and sql server working together to give you the results and it might take many calls to your database instead of one.
Try this instead:
Categories = (from cvi in mcv.CategoryVariation.CategoryVariationItems
let mmcvia =
cvi.ModelModuleCategoryVariationItemAmounts.SingleOrDefault(
mmcvia2 => mmcvia2.ModelModuleId == m.ModelModuleId)
select new
{
cvi.Id,
Amount = mmcvia != null ?
(mmcvia.ModelModuleCategoryVariationItemAmountValueChanges.Select(
x => x.Amount).FirstOrDefault() : 0
... // select some more properties
}
Using the Select() method allows you to get the first Amount or its default value. I used "0" as an example only, I dont know what is your default value for Amount.

LINQ Query returns nothing

Why is this query returns 0 lines?
There is a record matching the arguments.
SomeDataContext db = new SomeDataContext(ConnString);
return db.Deafkaw.Where(p =>
(p.SomeDate1 >= aDate &&
p.SomeDate1 <= DateTime.Now) &&
(p.Year == aYear && p.IsSomething == false)
).ToList();
Am i missing something?
On the Table Deafkaw
SomeDate1 = 20/4/2010 11:32:17
Year = 2010
IsSomething = False
...besides other columns im not interested in conditions.
I need SomeDate1 between the dates i give IsSomething = False and Year = 2010.
You aren't assigning the result to anything so it is being discarded. Try this:
var results = db.Deafkaw.Where(p =>
(p.ImerominiaKataxorisis >= aDate &&
p.ImerominiaKataxorisis <= DateTime.Now) &&
(p.Year == etos && p.IsYpodeigma == false)
).ToList();
Update: you changed the question so now I'm not sure that this is the correct answer. Can you post the code where you call this method?
It is difficult to answer your question without any additional information. Checking the following points may help you to find the problem:
If you remove Where clause and write Deafkaw.ToList(), what do you get?
What is the value of aDate and etos?
Can you double check the condition? Do you require that all subconditions hold at the same time? Are there any such data if you print entire DeaFkaw data structure?
Can you try removing some sub-conditions to see if that gives you some results?
Try
Deafkaw.Where(p => (p.ImerominiaKataxorisis >= aDate && p.ImerominiaKataxorisis <= DateTime.Now &&
p.Year == etos && p.IsYpodeigma == false)).ToList();
Use SQL profiler. Look at the sql query that is generated. Run the sql query manually and see if you get back any records.

Order By missing in linqtosql select random row

I have the following linq query :
IQueryable<Message> messagesQuery = (from message in _context.Db.Messages
where message.MessageListId == item.MessageListId
&&
!_context.Db.ScheduleXMessages.Any(x => x.MessageId == message.MessageId && x.ScheduleId == item.ScheduleId)
select message);
if (randomSendMessage)
return (from mq in messagesQuery orderby Guid.NewGuid() select mq).FirstOrDefault();
return (from mq in messagesQuery orderby mq.OrderIndex select mq).FirstOrDefault();
Now, if randomSendMessage is true, the order by doesn't get added to the select. if it's false, then the Order By OrderIndex is added to the select.
Any ideas on what might be going on ?
Thanks.
Edit Nope, it doesn't work if I select the column upfront. It just sends the guid as a parameter and instead of doing an orderby newid() , it does it by using one single guid
If you want to get random results with LINQ to SQL you can use Marc Gravell's solution here. I recently explained how to setup a partial class to use it in this post. Otherwise you may have to setup a stored procedure or UDF.
EDIT: I took a look at the blog post you mentioned. The author actually pointed to Marc's solution as an alternative :)
Not exactly sure what is going on, but my guess would be it doesn't support that type of ordering... possibly because it's not defined within the select list. Try the alternative:
IQueryable<Message> messagesQuery = (from message in _context.Db.Messages
where message.MessageListId == item.MessageListId
&&
!_context.Db.ScheduleXMessages.Any(x => x.MessageId == message.MessageId && x.ScheduleId == item.ScheduleId)
select new { Message = message, ID = Guid.NewGuid() });
if (randomSendMessage)
return (from mq in messagesQuery orderby mq.ID select mq.Message).FirstOrDefault();
return (from mq in messagesQuery orderby mq.Message.OrderIndex select mq.Message).FirstOrDefault();
to see if that resolved it by storing the ID within the record.
I guess it should have bee bloody obvious that L2S wouldn't know what to do with Guid.NewGuid() :).
I found an answer here : http://weblogs.asp.net/fmarguerie/archive/2008/01/10/randomizing-linq-to-sql-queries.aspx
It works.