我一直在尝试创建一个sql查询,该查询返回给定日期每个用户的最新记录。
Select dbfirst, dblast, max(dbdate) as MaxDate
from table
where (DATEPART(yy, dbdate) = 2015
AND DATEPART(mm, dbdate) = 10
AND DATEPART(dd, dbdate) = 22)
group by dbfirst, dblast
我得到的结果是针对在指定日期登录的用户,即
╔═════════╦════════╦════════════════════════╗
║ dbfirst ║ dblast ║ MaxDate ║
╠═════════╬════════╬════════════════════════╣
║ user ║ 10 ║ 20151022 13:13:09.000 ║
║ user ║ 11 ║ 20151022 10:18:50.000 ║
╚═════════╩════════╩════════════════════════╝
这只返回最新用户的一条记录。
我还需要能够显示列' dbflow'在结果中是varchar" In"或" Out"但是当我这样做的时候。
Select dbfirst, dblast, dbflow, max(dbdate) as MaxDate from [Inventory].[dbo].[pr_dbs] where (DATEPART(yy, dbdate) = 2015 AND DATEPART(mm, dbdate) = 10 AND DATEPART(dd, dbdate) = 22) group by dbfirst, dblast, dbflow
它返回最新的In和Out,我只需要最新的记录,无论dbflow如何。
╔═════════╦════════╦════════╦═════════════════════════╗
║ dbfirst ║ dblast ║ dbflow ║ MaxDate ║
╠═════════╬════════╬════════╬═════════════════════════╣
║ user ║ 10 ║ In ║ 2015-10-22 13:13:09.000 ║
║ user ║ 11 ║ In ║ 2015-10-22 10:18:50.000 ║
║ user ║ 10 ║ Out ║ 2015-10-22 12:13:09.000 ║
║ user ║ 11 ║ Out ║ 2015-10-22 9:18:50.000 ║
╚═════════╩════════╩════════╩═════════════════════════╝
提前感谢您的帮助或建议。
答案 0 :(得分:3)
根据官方 Microsoft培训套件考试70-461 (SQL Server),您有3个问题的解决方法(如果您知道不能有多个不同的dbflow)每个 distinct(dbfirst,dblast)):
只需将其添加到GROUP BY
子句
第二个选项是将类似MAX
的聚合函数应用于列。
第三个选项是首先对[pr_dbs]表中的行进行分组和聚合,根据分组查询定义表表达式,然后将表表达式与[pr_dbs]原始表连接以获取最后一栏
WITH CTE AS (
SELECT dbfirst, dblast, max(dbdate) as MaxDate
FROM [Inventory].[dbo].[pr_dbs]
WHERE (DATEPART(yy, dbdate) = 2015
AND DATEPART(mm, dbdate) = 10
AND DATEPART(dd, dbdate) = 22)
GROUP BY dbfirst, dblast
)
SELECT CTE.*, D.dbflow
FROM [Inventory].[dbo].[pr_dbs] AS D
INNER JOIN CTE
ON D.dblast = CTE.dblast
AND D.dbfirst = CTE.dbfirst;
SQL Server通常会优化第三种解决方案 第一。第一种解决方案可能更可取,因为它涉及很多 更少的代码。
修改强>
当您解决问题时,它是否满足您的需求:
SELECT table.dbfirst, table.dblast, table.MaxDate, table.dbflow
FROM table
INNER JOIN
(
SELECT dbfirst, dblast, max(dbdate) as MaxDate
FROM table
WHERE (DATEPART(yy, dbdate) = 2015
AND DATEPART(mm, dbdate) = 10
AND DATEPART(dd, dbdate) = 22)
GROUP BY dbfirst, dblast
) AS T
ON table.dbfirst = T.dbfirst
AND table.dblast = T.dblast
AND table.dbdate = T.MaxDate
答案 1 :(得分:1)
您是否想过使用窗口函数?这将是您的查询的示例:
SELECT DISTINCT dbflow
, dbfirst
, dblast
, MAX(dbdate) OVER (PARTITION BY dbfirst, dblast) AS MaxDate
FROM [Inventory].[dbo].[pr_dbs]
WHERE DATEPART(yy, dbdate) = 2015
AND DATEPART(mm, dbdate) = 10
AND DATEPART(dd, dbdate) = 22;
但是,我不确定这是否是正确的逻辑。
答案 2 :(得分:0)
请勿使用日期部分进行比较。函数的使用通常会排除索引的使用。因此,您查询的一种可能性是:
Select dbfirst, dblast, max(dbdate) as MaxDate, AVG(dbflow)
from table
where dbdate >= '2015-10-22' and dbdate < '2015-10-23'
group by dbfirst, dblast;
如果您想要日期的最后一个流程,那么请使用没有聚合的窗口函数:
Select dbfirst, dblast, dbdate as MaxDate, dbflow
from (select t.*,
row_number() over (order by dbdate desc) as seqnum
from table t
where dbdate >= '2015-10-22' and dbdate < '2015-10-23'
) t
where seqnum = 1;
这两个查询都可以利用table(dbdate)
上的索引,而您的版本却无法使用该索引。
答案 3 :(得分:-1)
您为dbfirst
和dblast
显示一个结果行,并希望为其显示dbflow
。但是哪一个?每dbfirst
和dblast
有几条记录,这就是为什么您无法显示dbdate
,而是决定一个日期,即max(dbdate)
。
与日期一样,您必须决定显示哪个dbflow
并相应地使用MAX,MIN,AVG或其他任何内容。