【问题标题】:changing variable used in where clause each time where clause returns true每次 where 子句返回 true 时更改 where 子句中使用的变量
【发布时间】:2012-09-21 20:26:34
【问题描述】:

我有一个包含大约 300 万条记录的数据库,每条记录都有 id (int, primary key)、uniqueNumber(int) 和 updateTime(string)。

uniqueNumber 可以属于多个记录。 updateTime 表示一天中记录更新的时间,例如 14:33:42

编辑:记录按更新时间排序。

我想让用户定义一个 uniqueNumber 和一个间隔。然后我想查询数据库以获取属于该 uniqueNumber 的所有记录,其中它们的 updateTime 等于一个变量,每次 where 条件为真时,它的值都会按间隔增加。

例如,我想要这样的东西:(本例中没有使用数据库)

    string currentTime = "12:25:00";
    int interval = 2;

    public void LinqExample()
    {
        string[] arr = new string[4] { "12:23:00", "12:26:00", "12:27:00", "12:28:00"};

        var query = from c in arr
                    where c.Replace(":", "").CompareTo(currentTime.Replace(":", "")) > 0 && Inc()
                    select c;

        // query's output is: "12:26:00", "12:28:00"
    }

    private bool Inc()
    {
        currentTime = DateTime.Parse(currentTime).AddMinutes(interval).ToLongTimeString();
        return true;
    }

我的代码是正确的方法吗?

谢谢!

【问题讨论】:

  • 您将无法使用它直接查询数据库,因为它依赖于本地状态。这种类型的处理需要您从数据库中提取所有记录。我建议重新审视您的要求和架构。
  • 好的。但是,当在数据库上使用 linq 时,每次 where 子句为真时,是否可以更改变量的值而不从数据库中提取所有记录?
  • @remi:为了能够做到这一点,您的数据库的 LINQ 提供程序应该能够将 Inc() 转换为 SQL。恐怕不太可能。
  • @remi:您使用的是什么 DBMS?你有能力在数据库中创建对象吗?我认为最好在你的数据库中创建函数来返回你需要的所有记录。
  • @remi Aw,如果有一个阈值,我可以想出一个 LINQ 解决方案,它至少有很小的工作机会,具体取决于 LINQ to Entities 的工作原理。但现在我什么都想不出来。我唯一的另一个想法是使用 LINQ 在数据库中尽可能多地过滤,然后在程序中过滤其余部分。无论如何,感谢您回答所有问题。希望我的 cmets 至少可以帮助其他人解决问题。

标签: c# linq


【解决方案1】:

您想要的代码(如果存在)似乎需要通过 EF 在您的表上生成带有 CURSOR 的 SQL 查询。但是,正如我所怀疑的那样,EF 从不生成带有游标的代码,因此您无法使用 LINQ 解决您的问题。恕我直言,这样做的唯一方法是编写这样的表值函数

CREATE FUNCTION GetTimesByUniqueNumberWithIntervalAndCondition
(
    @interval int, @uniqueNumber int,@currentTime time
)
RETURNS 
@Times TABLE 
(
    t char(10)
)
AS
BEGIN
    DECLARE timeCursor CURSOR LOCAL FAST_FORWARD READ_ONLY FOR
    SELECT updateTime FROM Table2 WHERE uniqueNumber = @uniqueNumber
    ORDER BY updateTime 

    DECLARE @t char(10);

    OPEN timeCursor
    FETCH NEXT FROM timeCursor INTO @t;

    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF 
            1 = 1 -- place your condition here
        BEGIN
            INSERT @Times(t) VALUES(@t)
            SET @currentTime = DATEADD(MINUTE,@interval,CAST(@t AS time))
        END

        FETCH NEXT FROM timeCursor INTO @t;
    END

    CLOSE timeCursor
    DEALLOCATE timeCursor

    RETURN 
END
GO

并在每次需要选择时查询此函数。

【讨论】:

  • 但请注意,在 SQL Server 中非常不希望使用游标
  • 您能否解释一下为什么不希望在 SQL Server 中使用游标?
  • 我找到了this link
【解决方案2】:

你想要的是一个带有偏移量的modulo operation。当前时间和记录时间之间的分钟差是一个整数。如果该整数可以被区间值整除,那么您就有了匹配项:

(假设实体框架,使用 linq-to-sql 使用 SqlMethods)

var now = DateTime.Now;
var curr = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0);

var query = context.Table
.Where(t => t.uniqueNumber == uniqueNumber
.Where(t => t.updateTime > curr) 
.Where (t => EntityFunctions.DiffMinutes(curr, t.updateTime) % interval == 0)
.Select (t => new { t.updateTime, .... } )

【讨论】:

  • 我喜欢这个主意,但这并不是 remi 所要求的。 Remi 想要的不是落在任何间隔上的项目,而是落在某个间隔上的项目。
  • @RiskyMartin 我想你就在那里。另外,想一想,这是关于时间之间的差异,而不是日期。但主要的转折是模数,也许这足以让 remi 解决它。另一个可能的问题可能是值本身。如果它们存储为字符串,那么(我认为)不可能以任何转化为 SQL 的方式解决这个问题。雷米?
  • 无论如何,按照@RiskyMartin,应该使用从午夜开始的分钟数的模值。
  • @Gert Arnold 我也喜欢你的想法,但我同意 Risky_Martin 的观点。其次,是的,updateTime 存储为字符串。
  • As string :( :( 你能对此做些什么吗?字符串会阻碍对字段进行任何快速排序和谓词作为时间的任何努力,因为必须首先转换值,这排除了字段上的任何索引。
猜你喜欢
  • 2013-07-08
  • 1970-01-01
  • 2016-05-18
  • 1970-01-01
  • 1970-01-01
  • 2011-05-11
  • 1970-01-01
  • 1970-01-01
  • 2014-04-11
相关资源
最近更新 更多