我有一个这样的时间表(Voyages)表:
ID Arrival Departure OrderIndex
1 01/01/1753 02/10/2009 0
1 02/11/2009 02/15/2009 1
1 02/16/2009 02/19/2009 2
1 02/21/2009 01/01/1753 3
2 01/01/1753 03/01/2009 0
2 03/04/2009 03/07/2009 1
2 03/09/2009 01/01/1753 2
按照设计我将'01/01/1753'
保存为默认值,如果用户没有填写捕获屏幕上的字段以及从未提供的第一个到达和最后一次出发。
我正在使用Nhibernate和Criteria,如果我想知道表中每次航行的第一次出发和最后到达,我想知道查询这些数据的最佳方式。
我的第一个想法是一个groupby(ID),然后在到达和离开时做一些Min和Max,但是`'01 / 01 / 1753'VALUE正在弄乱aronud。
...
.SetProjection(Projections.ProjectionList()
.Add(Projections.GroupProperty("ID"), "ID")
.Add(Projections.Min("DepartureDate"), "DepartureDate")
.Add(Projections.Max("ArrivalDate"), "ArrivalDate")
)
...
那么有没有办法在Min函数比较中跳过这个值(不丢失整行数据),或者有更好的方法可以做到这一点,也许利用总是指示元素正确顺序的OrderIndex ,也许订购ASC取第一个然后订购DESC并再次获得第一个,但我不太确定如何使用标准语法。
答案 0 :(得分:2)
当然,最好的(也是最好的)方法是使用NULL
值而不是最小datetime
值。如果您已经这样做了(或者更改了您的应用程序),那么您编写的代码将按照书面形式运行。现在的方式,我保证那些伪造的价值最终会回来困扰某人(如果这是一个真正的应用程序)。也许不是你,但下一个人。当然,你也应该规范化这个表......
但无论如何。稍后会详细介绍这些内容。你问了一个具体问题。
以下是应该工作的代码(不是缺少测试 - 继续阅读)。
DateTime bogusDate = new DateTime(1753, 1, 1);
ICriteria criteria =
session.CreateCriteria(typeof(Voyage))
.SetProjection
(
Projections.ProjectionList()
.Add
(
Projections.Min
(
Projections.Conditional
(
Restrictions.Eq("Departure", bogusDate),
Projections.Constant(DateTime.MaxValue, NHibernateUtil.DateTime),
Projections.Property("Departure")
)
)
)
.Add(Projections.Max("Arrival"))
.Add(Projections.GroupProperty("Id"))
);
(我发送DateTime.MaxValue
的唯一原因是因为NHibernate将条件的真/假结果强制为相同类型,我无法弄清楚如何将NULL
引入true
部分。)
该代码将此查询发送到数据库引擎(我使用的是SQL Express 2005支持的SQL Server 2005方言):
SELECT min((case when this_.Departure = ? then ? else this_.Departure end)) as y0_,
max(this_.Arrival) as y1_,
this_.Id as y2_
FROM Voyages this_
GROUP BY this_.Id;
@p0 = 1/1/1753 12:00:00 AM,
@p1 = 12/31/9999 11:59:59 PM
哪个看起来不错。现在,我说这个应该工作,因为当你插入参数并直接在引擎上运行查询时,它会给出所需的结果。然而,在我的机器上,使用NHibernate,一切都爆发了:
System.Data.SqlClient.SqlException: Incorrect syntax near '?'.
这告诉我SQL Server在CASE
语句中没有相似的位置参数。 Braindead如果是真的。这可能不是2008+的问题,虽然我没有测试过 - 我特别提到SQL Server,因为我假设你使用的是自1731年1月1日以来它是允许的最小日期datetime
。
那么,这会留下什么问题呢?有选择。
NULL
值添加到数据中。OrderIndex
列。我用SQL写了这个 - 我不知道怎么用ICriteria
来写这个(如果你想要惩罚那个,请帮个忙,把时间花在#1选项上)。请注意,这不到原始查询的一半,这几乎是最佳的AFAIK:SELECT
s.Id,
v1.Departure,
v2.Arrival
FROM
(
SELECT DISTINCT
Id,
MAX(OrderIndex) AS MaxIndex,
MIN(OrderIndex) AS MinIndex
FROM Voyages
GROUP BY Id
) s
INNER JOIN Voyages v1 ON v1.Id = s.Id AND v1.OrderIndex = MinIndex
INNER JOIN Voyages v2 ON v2.Id = s.Id AND v2.OrderIndex = MaxIndex