2016-05-30 3 views
1

Я работаю с таблицей данных, в которой некоторые строки в ней копируются как резервная копия. Я пытаюсь отфильтровать данные, которые были скопированы, но у меня проблемы, потому что мне нужно фильтровать пару колонок. Каждая строка имеет имя и дату, флаг для, если это копия или несколько других вещей (имеет более чем два значения, но это те, которые мне интересны) и другую информацию. Я пытаюсь получить все строки, которые не появляются в качестве резервных, так, например:Фильтр C# SQL для пары значений?

ABC 1/1/2001 dataSet ...  |  ABC 1/1/2001 backupSet ... 
DEF 2/2/2002 dataSet ...  |  DEF 2/2/2002 backupSet ... 
GHI 3/3/2003 dataSet ...  |  ABC 4/4/2004 backupSet ... 
ABC 4/4/2004 dataSet ...  |  
DEF 5/5/2005 dataSet ...  |  
ABC 6/6/2006 dataSet ...  |  

приведет ли:

GHI 3/3/2003 dataSet ... 
DEF 5/5/2005 dataSet ... 
ABC 6/6/2006 dataSet ... 

можно фильтровать по одной колонке, но я не знаете, как сделать оба одновременно.

var result = from a in db.table 
where a.type == "dataSet" 
let backupData = (from b in db.table where b.type == "backupSet" select b.name) 
where !backupData.Contains(a.type) 
select new DataObject 
{ 
    ... 
}; 

Насколько я добрался.

Я также пытаюсь сохранить его только одним запросом, так как набор результатов потенциально может быть довольно большим, поэтому я не хотел просто создавать пару коллекций в памяти, а затем попробовать и отфильтровать их. Это возможно? Все еще немного неопытная в SQL, любая помощь приветствуется.

ответ

1

Вы можете использовать либо Any!):

var result = 
    from a in db.table 
    where a.type == "dataSet" 
     && !db.table.Any(b => b.type == "backupSet" 
      && b.name == a.name && b.date == a.date) 
    select new DataObject 
    { 
     ... 
    }; 

или (если смотреть немного более сложным, но в целом более эффективной) antijoin (реализован в виде left outer join с null правой стороны):

var result = 
    from a in db.table.Where(x => x.type == "dataSet") 
    join b in db.table.Where(x => x.type == "backupSet") 
     on new { a.name, a.date } equals new { b.name, b.date } into bGroup 
    from b in bGroup.DefaultIfEmpty() 
    where b == null 
    select new DataObject 
    { 
     ... 
    }; 
+0

Это работало, спасибо. – user1267983

0

В зависимости от того, что вы пытаетесь сделать (и что вы можете сделать), вы можете использовать group by, предполагая, что name является ключом для связи Backupset и DataSet вместе:

var result = db.Table 
    .GroupBy(x => new { x.name, x.type }) // Composite key 
    .Select(g => new { 
     Name = g.Key.name, // ABC, DEF, etc 
     Type = g.Key.type, // "backupSet", "dataSet" 
     LastRecord = g.OrderByDescending(x => x.date).FirstOrDefault() // Last record for either backupSet or dataSet 
    }) 
    .ToList() // Materialize... query can be very complex 
    .GroupBy(x => x.Name) 
    .Select(g => new { 
     Name = g.Key, 
     LastBackupSet = g.First(x => x.Type == "backupSet").LastRecord, 
     LastDataSet = g.First(x => x.Type == "dataSet").LastRecord 
    }) 
    .ToList(); 

Будьте осторожны, в последнем выражении g.First может бросить последовательность не содержит элементов и .LastRecord может бросить ссылка на объект не указывает на экземпляр объекта

Смежные вопросы