Предварительный запрос данных с пробелами с помощью linq2sql

#c# #linq-to-sql

#c# #linq-to-sql

Вопрос:

Привет, у меня есть таблица: значения с valueId, отметкой времени, значением и принадлежностью. Каждые 15 минут в эту таблицу добавляется новая строка с новым значением, текущей меткой времени и определенным полем принадлежности. И теперь я хочу найти пробелы, я имею в виду значения, где одно за другим имеет временную метку более 15 минут.

Я пытался сделать это:

 var gaps = from p1 in db.T_Values
                       join p2 in db.T_Values on p1.TimeStamp.AddMinutes(15) equals p2.TimeStamp
                       into grups where !grups.Any() select new {p1};
  

и это работает, но я не знаю, оптимально ли это, как вы думаете? и я не знаю, как я могу добавить, где p1.belongTo == 1. Потому что этот запрос ищет все данные.

Джон сказал

 var gaps = from p1 in db.T_Values
           where p1.BelongTo == 1
           where !db.T_Values.Any(p2 => p1.TimeStamp.AddMinutes(15) == p2.Timestamp)
           select p1;
  

Джон, этот последний запрос переведен в:

 exec sp_executesql N'SELECT [t0].[ValueID], [t0].[TimeStamp], [t0].[Value],
                    [t0].[BelongTo], [t0].[Type]
FROM [dbo].[T_Values] AS [t0]
WHERE (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[T_Values] AS [t1]
WHERE DATEADD(ms, (CONVERT(BigInt,@p0 * 60000)) % 86400000,
DATEADD(day, (CONVERT(BigInt,@p0 * 60000)) / 86400000, [t0].[TimeStamp])) = [t1].[TimeStamp]
))) AND ([t0].[BelongTo] = @p1)',N'@p0 float,@p1 int',@p0=15,@p1=1
  

и это работает, если только все строки не имеют одинакового значения belongTo , когда есть строки с belongTo со многими разными значениями, тогда я заметил, что мне нужно добавить в sql: и [t1].belongTo = 1, который в конечном итоге должен выглядеть следующим образом

 N'SELECT [t0].[ValueID], [t0].[TimeStamp], [t0].[Value], [t0].[BelongTo], [t0].[Type]
FROM [dbo].[T_Values] AS [t0]
   WHERE (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[T_Values] AS [t1]
WHERE DATEADD(ms, (CONVERT(BigInt,@p0 * 60000)) % 86400000, 
DATEADD(day, (CONVERT(BigInt,@p0 * 60000)) / 86400000, [t0].[TimeStamp])) = [t1].[TimeStamp]
and [t1].BelongTo = 1  
  ))) AND ([t0].[BelongTo] = @p1)',N'@p0 float,@p1 int',@p0=15,@p1=1
  

другими словами:

 SELECT  TimeStamp
FROM [dbo].[T_Values] AS [t0]
WHERE NOT( (EXISTS (SELECT NULL AS [EMPTY]
FROM [dbo].[T_Values] AS [t1]
WHERE DATEADD(MINUTE, 15, [t0].[TimeStamp]) = [t1].[TimeStamp])))
AND ([t0].[BelongTo] = 1)
  

следует изменить на

 SELECT  TimeStamp
FROM [dbo].[T_Values] AS [t0]
WHERE NOT( (EXISTS (SELECT NULL AS [EMPTY]
FROM [dbo].[T_Values] AS [t1]
WHERE DATEADD(MINUTE, 15, [t0].[TimeStamp]) = [t1].[TimeStamp] and [t1].BelongTo=1)))
AND ([t0].[BelongTo] = 1)
  

но я все еще думаю, как я могу добавить это в linkq

Комментарии:

1. Я оставлю это на усмотрение Джона Скита, поскольку вы на это надеетесь.

2. без мата, c; mon, я ищу помощи от всех людей, если кто-то еще может сказать что-нибудь о том, насколько оптимальным является этот запрос, было бы здорово

Ответ №1:

Что ж, добавить дополнительное where предложение несложно (и в то же время я удалю бессмысленный анонимный тип):

 var gaps = from p1 in db.T_Values
           where p1.BelongTo == 1
           join p2 in db.T_Values
           on p1.TimeStamp.AddMinutes(15) equals p2.TimeStamp
           into grups
           where !grups.Any()
           select p1;
  

Хотя я не уверен, зачем вы группируете… Я бы подумал, что это будет проще:

 var gaps = from p1 in db.T_Values
           where p1.BelongTo == 1
           where !db.T_Values.Any(p2 => p1.TimeStamp.AddMinutes(15) == p2.Timestamp)
           select p1;
  

Что касается производительности — посмотрите на сгенерированный SQL и на то, как он выглядит в SQL profiler.

РЕДАКТИРОВАТЬ: если вам нужна BelongTo проверка в обеих версиях (имеет смысл) Я бы предложил это:

 var sequence = db.T_Values.Where(p => p.BelongTo == 1);

var gaps = from p1 in sequence
           where !sequence.Any(p2 => p1.TimeStamp.AddMinutes(15) == p2.Timestamp)
           select p1;
  

Комментарии:

1. в запросе, как вы сказали, var gaps = из p1 в db.T_Values, где p1.belongTo == 1, где !db.T_Values. Любой (p2 => p1.Временная метка. Добавьте минуты (15) == p2.Временная метка) выберите p1; мы не можем указать два раза, где, nad p2 недоступен, мне также было интересно, почему

2. @kosnkov: Боюсь, я не понял вашего комментария. p2 доступно только в Any вызове, поскольку это параметр в лямбда-выражении.

3. @Jon извини, Джон, ты совершенно прав, сегодня я выясню, какова производительность между этими двумя запросами, относящимися к процедуре sql, и я сообщу тебе, как это переводится, и какой метод является наиболее быстрым способом сделать это. Большое вам спасибо.

4. я проверил, оба запроса переведены в одну и ту же хранимую процедуру:exec sp_executesql N’SELECT [t0]. [valueId], [t0]. [Временная метка], [t0]. [Значение], [t0]. [Принадлежит], [t0]. [Введите] из [dbo]. [T_Values] КАК [t0], ГДЕ (НЕ (СУЩЕСТВУЕТ( ВЫБЕРИТЕ NULL КАК [ПУСТОЙ] ИЗ [dbo]. [T_Values] КАК [t1], ГДЕ DATEADD(ms, (CONVERT(BigInt,@p0 * 60000)) % 86400000, DATEADD(day, (CONVERT(BigInt,@p0 * 60000)) / 86400000, [t0]. [Временная метка])) = [t1]. [Временная метка] ))) И ([t0]. [belongTo] = @p1)’,N’@p0 float,@p1 int’,@p0= 15,@p1= 19241 и это действительно быстро

5. Еще раз привет, честно говоря, это не работает, потому что join не учитывает belong to при объединении одной таблицы с другой

Ответ №2:

Как насчет

 var gaps = dbT_Values.Take(dbT_Values.Count()-1)
                     .Select((p, index) => new {P1 = p, P2 = dbT_Values.ElementAt(index   1)})
                     .Where(p => p.P1.BelongsTo == 1 amp;amp; p.P1.TimeStamp.AddMinutes(15).Equals(p.P2.TimeStamp)).Select(p => p.P1);
  

Комментарии:

1. извините, но при выполнении вашего запроса я получил эту ошибку: Неподдерживаемая перегрузка, используемая для оператора запроса ‘Select’. я немного изменил его на:var gaps1 = db.T_Values. Возьмите (db.T_Values. Count() — 1) .Select((p, index) => new { P1 = p, P2 = db.T_Values. ЭлементАт(индекс 1) }) . Где(p => p.P1.inputId == 1 amp;amp; p.P1.TimeStamp. Добавьте минуты(15).Равно (p.P2.Временная метка)). Выберите (p => p.P1);

2. Это перегрузка, которую я использую msdn.microsoft.com/en-us/library/bb534869.aspx . у вас есть using System.Linq; , не так ли?

3. да, я использую.system.linq, и этот запрос действительно выдает мне ошибку Неподдерживаемая перегрузка, используемая для оператора запроса ‘Select’. Попробуйте сами, если сможете, пожалуйста.