简体   繁体   中英

Linq to get data from a table but not if in another table?

Because of a poor design on our database I have to write a complex query to get my data.

I need to get all valid data from a table_1. In other works I need to get each valid row of my table_1. I don't have a simple valid or invalid column in my table_1. This information is stored in a table_2. Table_2 contains all invalid row with the error message.

Let say the data I need to retrieve are orders. For my example notice that OrderNo is the number of an order. So I can have multiple line, version, of this order in table_1 and I can also have multiple line of error on this order in table_2. So I will also have to use a version number.

I already tried this:

table_1.Where(y => (y.OrderNo == "1234"));
table_2.Where(y => (y.OrderNo == "1234")).Select(y => y.Version).Distinct();

And I think I need to do something like this:

var errorList = table_2.Where(y => (y.OrderNo == "1234")).Select(y => y.Version).Distinct();
table_1.Where(y => (y.OrderNo == "1234" && y.Version.NOT_IN(erriList)));

Could you help me?

I suppose you are searching for Contains function with ! symbol ( logical negation operator ). Like this:

var errorList = table_2.Where(y => y.OrderNo == "1234")
                       .Select(y => y.Version);

var res = table_1.Where(y => y.OrderNo == "1234" 
            //here you get only rows that doesn't represent in errorList 
            && !errorList.Contains(y.Version)); 

to get data from a table but not if in another table

This is called antijoin . While you can use Contains and Any based approaches presented in the other answers, usually you'll get the best performance by using the classic SQL approach - LEFT OUTER JOIN combined with checking the right side for NULL .

Which in LINQ looks like this:

var query =
    from t1 in table_1
    //where t1.OrderNo == "1234"
    join t2 in table_2 on t1.OrderNo equals t2.OrderNo into t2group
    from t2 in t2group.DefaultIfEmpty()
    where t2 == null
    select t1;

Actually when you use OrderNo filter, most probably there will not be a noticeable speed difference between this and other queries. The main benefit of the above would be if you remove that filter, although many nowadays SQL query optimizers are able to derive one and the same execution plan regardless of whether the query uses JOIN / IN / EXISTS constructs.

How about this:

var validRows = table1
                .Where(t1 => !table2
                              .Any(t2 => t1.OrderNo == t2.OrderNo && 
                                         t1.Version == t2.Version));

Note that this is far more efficient in SQL unless you're using something fancy that translates the expression to SQL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM