你能在SQL中编写自定义聚合函数吗?你能查询分组的内容吗?

时间:2010-02-17 01:57:36

标签: sql linq

我正在尝试将Linq查询转换为SQL。我的Linq查询如下所示:

from s in Somethings
where s.CreatedTime >= new DateTime(2010, 01, 01)
where s.CreatedTime <  new DateTime(2010, 02, 01)
group s by s.Data into grouping
select grouping.OrderByDescending(s => s.CreatedTime)
               .ThenByDescending( s => s.UpdatedTime)
               .First();

用语言来说,这应该是从某个月开始的所有事情。然后按特定键对它们进行分组。对于每个键,我想要最近创建的元素。如果同时创建了具有相同键的两个元素,我想通过最近更新的方式来断开关系。

到目前为止,我已经将其用于SQL

SELECT s1.*
FROM Somethings s1
JOIN (
  SELECT s.Date AS Data, MAX(CreatedTime) AS CreatedTime
  FROM Somethings s
  WHERE s.CreatedTime >= '20100101' 
    AND s.CreatedTime <  '20100201' 
  GROUP BY s.Data
) s2 ON s1.Data = s2.Data
    AND s1.CreatedTime = s2.CreatedTime

这有效,但我无法控制关系是如何被打破的。

我真正想要的是一种在Linq中任意排序每个分组的方法。我想定义自己的聚合函数,它接受一组行,并返回一行。这可能在SQL中,还是Linq更具表现力? SQL的聚合函数MAX,MIN,COUNT等似乎不像Linq中的等价函数那样是第一类函数。当然,这可能只是我对SQL的了解不足。

这是一个用于进一步说明我想在SQL中做什么的组成示例:

SELECT (SELECT * 
        FROM grouping 
        ORDER BY CreatedTime DESC, UpdatedTime DESC
        LIMIT 1)
FROM Somethings s
WHERE s.CreatedTime >= '20100101' 
  AND s.CreatedTime <  '20100201' 
GROUP BY s.Data AS grouping

在此示例中,我的非法内部查询提供与聚合函数相同的角色。

2 个答案:

答案 0 :(得分:2)

这不是一个真正的聚合,它只是一个分组最大值。 ROW_NUMBER是编写这些查询的最简单方法:

;WITH CTE AS
(
    SELECT
        Query, CreatedTime, UpdatedTime, <other_columns>,
        ROW_NUMBER() OVER
        (
            PARTITION BY Query
            ORDER BY CreatedTime DESC, UpdatedTime DESC
        ) AS RowNum
    FROM Somethings
    WHERE CreatedTime >= '20100101'
    AND CreatedTime < '20100201'
)
SELECT *
FROM CTE
WHERE RowNum = 1

它不一定是效率最高的,但在大多数情况下它都相当不错。而且好处是你可以修改它来做每组前3名,前3名等,你可以完全控制关系。

(P.S。我希望你实际上并没有将列命名为“查询”)

答案 1 :(得分:0)

在sql中使用Group By展平组中的记录。这允许您在组上执行聚合函数,返回有关组的信息(最小值,最大值,计数等),但不能访问每个组中的各个记录。

也许这不能回答你的问题......

再添加一个级别,再次分组,最大更新时间......这应该可以解决您的问题。

SELECT sFinal.* FROM Somethings sFinal
 JOIN 
   (
     SELECT s1.Query, MAX(UpdatedTime) AS UpdatedTime
     FROM Somethings s1
     JOIN (
          SELECT s.Query AS Query, MAX(CreatedTime) AS CreatedTime
          FROM Somethings s
          WHERE s.CreatedTime >= '20100101' 
          AND s.CreatedTime <  '20100201' 
          GROUP BY s.Query
          ) s2
     ON s1.Query = s2.Query 
     AND s1.CreatedTime = s2.CreatedTime
     GROUP BY s1.Query
   ) s3
ON sFinal.Query = s3.Query AND sFinal.UpdatedTime = s3.UpdatedTime

现在,如果它们具有匹配的CreatedTime和UpdatedTime,则将返回多个记录。但它应该是你想要的。