我面临一个相当有趣的问题。我有一个具有以下结构的表:
CREATE TABLE [dbo].[Event]
(
Id int IDENTITY(1,1) NOT NULL,
ApplicationId nvarchar(32) NOT NULL,
Name nvarchar(128) NOT NULL,
Description nvarchar(256) NULL,
Date nvarchar(16) NOT NULL,
Time nvarchar(16) NOT NULL,
EventType nvarchar(16) NOT NULL,
CONSTRAINT Event_PK PRIMARY KEY CLUSTERED ( Id ) WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON
)
)
所以问题是我必须在网格中显示这些数据。有两个要求。第一个是显示所有事件,而不管是什么应用程序抛出它们。这很简单 - 选择语句可以很容易地完成工作。
第二个要求是能够按Application
对事件进行分组。换句话说,以一种方式显示所有事件,如果ApplicationId
重复多次,则只抓取每个应用程序的最后一个条目。此查询/视图中不再需要此时事件(Id)的主键。
您可能还注意到事件日期和时间是字符串格式。这没关系,因为它们遵循标准的日期时间格式:mm / dd / yyyy和hh:mm:ss。我可以按如下方式提取:
Convert( DateTime, (Date + ' ' + Time)) AS 'TimeStamp'
我的问题是,如果我在其余列上使用AGGREGATE函数,我不知道它们会如何表现:
SELECT
ApplicationId,
MAX(Name),
MAX(Description),
MAX( CONVERT(DateTime, (Date + ' ' + Time))) AS 'TimeStamp',
MAX( EventType )
FROM
Event
GROUP BY
ApplicationId
我犹豫不决的原因是因为MAX
之类的函数会从(子)记录集返回给定列的最大值。没必要拉最后一条记录!
关于如何根据每个应用程序仅选择最后一条记录的任何想法?
答案 0 :(得分:42)
您可以使用ranking function和common table expression。
WITH e AS
(
SELECT *,
ROW_NUMBER() OVER
(
PARTITION BY ApplicationId
ORDER BY CONVERT(datetime, [Date], 101) DESC, [Time] DESC
) AS Recency
FROM [Event]
)
SELECT *
FROM e
WHERE Recency = 1
答案 1 :(得分:7)
从SQL Server 2012开始,您可以简单地
SELECT
[Month]
, [First] = FIRST_VALUE(SUM([Clicks])) OVER (ORDER BY [Month])
, [Last] = FIRST_VALUE(SUM([Clicks])) OVER (ORDER BY [Month] DESC)
FROM
[dbo].[Table]
GROUP BY [Month]
ORDER BY [Month]
答案 2 :(得分:0)
SELECT
E.ApplicationId,
E.Name,
E.Description,
CONVERT(DateTime, (E.Date + ' ' + E.Time)) AS 'TimeStamp',
E.EventType
FROM
Event E
JOIN (SELECT ApplicationId,
MAX(CONVERT(DateTime, (Date + ' ' + Time))) AS max_date
FROM Event
GROUP BY ApplicationId) EM
on EM.ApplicationId = E.ApplicationId
and EM.max_date = CONVERT(DateTime, (E.Date + ' ' + E.Time)))
答案 3 :(得分:0)
因为那里没有where子句,所以记录子集都是记录。但是你认为最大限度地放在了错误的列上。此查询将为您提供所需内容。
Select max(applicationid), name, description, CONVERT(DateTime, (Date + ' ' + Time))
from event
group by name, description, CONVERT(DateTime, (Date + ' ' + Time))
答案 4 :(得分:0)
您可以使用子查询或CTE表来执行此操作:
;WITH CTE_LatestEvents as (
SELECT
ApplicationId,
MAX( CONVERT(DateTime, (Date + ' ' + Time))) AS 'LatestTimeStamp',
FROM
Event
GROUP BY
ApplicationId
)
SELECT
ApplicationId,
Name,
Description,
CONVERT(DateTime, (Date + ' ' + Time))) AS 'TimeStamp',
EventType
FROM
Event e
Join CTE_LatestEvents le
on e.applicationid = le.applicationid
and CONVERT(DateTime, (e.Date + ' ' + e.Time))) = le.LatestTimeStamp
答案 5 :(得分:0)
您可以将子查询与group by一起使用 - group by参数不需要在select中。假设Id是自动递增的,因此最大的是最新的。
SELECT
ApplicationId,
Name,
Description,
CONVERT(DateTime, (Date + ' ' + Time)) AS 'TimeStamp',
EventType
FROM
Event e
WHERE
Id in (select max(Id) from Event GROUP BY ApplicationId)
答案 6 :(得分:0)
我认为这对那些愿意获取最后插入记录的人很有用,它应该分组:
select * from(select * from TableName ORDER BY id DESC)AS x GROUP BY FieldName
它适用于以下内容:
表格结构 ID名称状态 1 Junaid是的 2 Jawad No. 3法赫德是的 4 Junaid No. 5 Kashif是的
查询上方的结果 ID名称状态 4 Junaid No. 2 Jawad No. 3法赫德是的 4 Kashif是的
这只是按名称生成最后一组记录。
答案 7 :(得分:0)
6年后SQL Server的另一个答案:
select t1.[Id], t2.[Value]
from [dbo].[Table] t1
outer apply (
select top 1 [Value]
from [dbo].[Table] t2
where t2.[Month]=t1.[Month]
order by [dbo].[Date] desc
)
虽然我更喜欢Postgresql解决方案,它具有独特的on功能,键入效果更好,效率更高:
select distinct on (id),val
from tbl
order by id,val
答案 8 :(得分:0)
起初我曾经将CTE与row_number一起使用,但是SQL Server认证课程中的一个示例向我展示了一个更好的示例(通过不断获得更好的执行计划来判断):
SELECT
ApplicationId,
Name,
Description,
CONVERT(DateTime, (Date + ' ' + Time)) AS 'TimeStamp',
EventType
FROM
Event AS E
WHERE
NOT EXISTS(SELECT * FROM Event AS Newer WHERE Newer.ApplicationId = E.ApplicationId AND Newer.Id > E.Id)
GROUP BY
ApplicationId
我假设更大的ID意味着更大的Date + Time(否则,我将使用convert转换为datetime,尽管这不能SARGable)。该查询将查找最年轻的记录-不存在较年轻的记录。如果索引设置正确,将使用索引查找。具有排名功能的替代方法通常使用表扫描,因为它可以对所有记录进行排名。
答案 9 :(得分:0)
我遇到了同样的问题。现在,我不想让 CTE 和“OVER”过于复杂。这是一个简单的例子。我用 MAX(DateEntered) 写了一个带有组的子查询。例如,如果它是 int,您可能想要通过 ID 来做,这比日期/时间更准确。在任何情况下,一旦您有了这个子查询,您只需将它与您的主查询内联以充当记录的过滤器。就这么简单。
表 a 是我的用户表。表 b 是子查询,表 c 是我想要“过滤”的表。
SELECT DISTINCT a.FirstName,a.LastName,a.ImagePath, c.MessageText
FROM [AuthUsers] a
INNER JOIN (SELECT MessageFromId,MAX(DateEntered) AS LastEntered FROM ChatRoomConversation GROUP BY MessageFrom) AS b
ON a.Id=b.MessageFromId
INNER JOIN ChatRoomConversation c
ON b.LastEntered=c.DateEntered