#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’. Попробуйте сами, если сможете, пожалуйста.