创建SQL查询以按用户检索最新记录

创建SQL查询以按用户检索最新记录,sql,Sql,我试图让此查询仅返回特定用户的最新交易记录,目前我正在使用此查询,但它与我不需要的额外信息混淆 SELECT TOP 30 USER_NAME, CONVERT(nvarchar(20), ACTIVITY_DATE_TIME, 20) AS DATE_TIME, WORK_TYPE, Location, ITEM, Quantity FROM TRANSACTION_HISTORY WHERE USER_NAME in ('a_user',

我试图让此查询仅返回特定用户的最新交易记录,目前我正在使用此查询,但它与我不需要的额外信息混淆

SELECT TOP 30 
    USER_NAME, 
    CONVERT(nvarchar(20), ACTIVITY_DATE_TIME, 20) AS DATE_TIME, 
    WORK_TYPE, Location, ITEM, Quantity 
FROM 
    TRANSACTION_HISTORY 
WHERE 
    USER_NAME in ('a_user','b_user','c_user','d_user','e_user')
ORDER BY 
    activity_date_time DESC

任何帮助都将不胜感激

从具有最新活动日期时间的表事务历史中检索记录的所有字段

将*更改为要检索的字段

显然,如果您只想检索USER_NAME列具有来自“a_USER”、“b_USER”、“c_USER”、“d_USER”、“e_USER”中任意一个值的记录,请添加where子句:


从具有最新活动日期时间的表事务\u历史中检索记录的所有字段

将*更改为要检索的字段

显然,如果您只想检索USER_NAME列具有来自“a_USER”、“b_USER”、“c_USER”、“d_USER”、“e_USER”中任意一个值的记录,请添加where子句:

这有用吗


这有帮助吗?

我相信用户希望在in子句中返回每个用户的最新事务

如果用户是不同的表,我会建议对TRANSACTION_HISTORY表中的最新记录进行联接/交叉应用。但既然他们都在同一张桌子上,工会怎么样


此处的ORDER BY将应用于整个查询,因为无法对每个工会进行排序。

我相信用户希望在in子句中返回每个用户的最新交易

如果用户是不同的表,我会建议对TRANSACTION_HISTORY表中的最新记录进行联接/交叉应用。但既然他们都在同一张桌子上,工会怎么样


此处的顺序将应用于整个查询,因为无法对每个单独的联合进行排序。

假设mssql 2005+,您可以使用行编号按用户进行分区,并按活动日期进行排序。然后只选择用户的第一行

SELECT
    *
FROM (
    SELECT
        USER_NAME, 
        CONVERT(nvarchar(20), ACTIVITY_DATE_TIME, 20) AS DATE_TIME, 
        WORK_TYPE, Location, ITEM, Quantity,
        RN = row_number() over(paritition by USER_NAME order by activity_date_time DESC)
    FROM 
        TRANSACTION_HISTORY 
    WHERE 
        USER_NAME in ('a_user','b_user','c_user','d_user','e_user')
) t
WHERE
    t.RN = 1 --only want the top history per user
如果表非常大,那么最好使用apply,因为看起来您一次只需要为少数用户执行此操作

 SELECT 
        TTH.* 
    FROM 
        USER U 
        CROSS APPLY (
            SELECT TOP 1
                USER_NAME, 
                CONVERT(nvarchar(20), ACTIVITY_DATE_TIME, 20) AS DATE_TIME, 
                WORK_TYPE, Location, ITEM, Quantity
            FROM 
                TRANSACTION_HISTORY TH
            WHERE
                TH.USER_NAME = U.USER_NAME
            ORDER BY
                activity_date_time DESC
        ) TTH
    WHERE 
        U.USER_NAME in ('a_user','b_user','c_user','d_user','e_user')

假设mssql 2005+,您可以使用行编号按用户划分,按活动日期排序。然后只选择用户的第一行

SELECT
    *
FROM (
    SELECT
        USER_NAME, 
        CONVERT(nvarchar(20), ACTIVITY_DATE_TIME, 20) AS DATE_TIME, 
        WORK_TYPE, Location, ITEM, Quantity,
        RN = row_number() over(paritition by USER_NAME order by activity_date_time DESC)
    FROM 
        TRANSACTION_HISTORY 
    WHERE 
        USER_NAME in ('a_user','b_user','c_user','d_user','e_user')
) t
WHERE
    t.RN = 1 --only want the top history per user
如果表非常大,那么最好使用apply,因为看起来您一次只需要为少数用户执行此操作

 SELECT 
        TTH.* 
    FROM 
        USER U 
        CROSS APPLY (
            SELECT TOP 1
                USER_NAME, 
                CONVERT(nvarchar(20), ACTIVITY_DATE_TIME, 20) AS DATE_TIME, 
                WORK_TYPE, Location, ITEM, Quantity
            FROM 
                TRANSACTION_HISTORY TH
            WHERE
                TH.USER_NAME = U.USER_NAME
            ORDER BY
                activity_date_time DESC
        ) TTH
    WHERE 
        U.USER_NAME in ('a_user','b_user','c_user','d_user','e_user')

一种方法是使用CTE公共表表达式,如果您使用的是SQL Server 2005或更高版本,您在这方面不够具体-其他RDBMS也有CTE和窗口功能,如ROW_NUMBER-这些不是SQL Server特有的功能

有了这个CTE,您可以按照一些标准(即用户名)对数据进行分区,并让SQL Server为每个分区的所有行编号从1开始,按照其他一些标准(如日期)排序

因此,请尝试以下方法:

;WITH MostRecentPerUser AS
(
   SELECT 
       USER_NAME, 
       CONVERT(nvarchar(20), ACTIVITY_DATE_TIME, 20) AS DATE_TIME, 
       WORK_TYPE, Location, ITEM, Quantity,
       ROW_NUMBER() OVER(PARTITION BY USER_NAME ORDER BY CAST(ACTIVITY_DATE_TIME AS DATETIME) ) AS 'RowNum'
   FROM 
       dbo.Transaction_History
   WHERE
       USER_NAME in ('a_user', 'b_user', 'c_user', 'd_user', 'e_user')
)
SELECT 
   USER_NAME, 
   DATE_TIME, 
   WORK_TYPE, Location, ITEM, Quantity
FROM 
   MostRecentPerUser 
WHERE
   RowNum = 1
这里,我只为每个分区选择第一个条目,即每个用户名(按日期和时间排序)

这接近你想要的吗

三个旁注:

首先,如果您有一个日期,为什么不将其存储为DATETIME或date?这应该是-认真的!不要将日期存储为NVARCHA20-永远不要

我会尽量避免使用所有大写标识符——这会使您的代码很难阅读和理解。到现在为止,我们已经超过了所有大写的终端,不是吗

另外:我建议尝试使用比DATE_TIME更有意义和表达力的名称-首先,您有可能与SQL Server关键字DATETIME或DATE发生冲突,第二,你应该努力让你的列名和别名真正表达它们所代表的内容——SalesDate或ActivityDate比DATE\u TIME好得多


一种方法是使用CTE公共表表达式,如果您使用的是SQL Server 2005或更高版本,您在这方面不够具体-其他RDBMS也有CTE和窗口功能,如ROW_NUMBER-这些不是SQL Server特有的功能

有了这个CTE,您可以按照一些标准(即用户名)对数据进行分区,并让SQL Server为每个分区的所有行编号从1开始,按照其他一些标准(如日期)排序

因此,请尝试以下方法:

;WITH MostRecentPerUser AS
(
   SELECT 
       USER_NAME, 
       CONVERT(nvarchar(20), ACTIVITY_DATE_TIME, 20) AS DATE_TIME, 
       WORK_TYPE, Location, ITEM, Quantity,
       ROW_NUMBER() OVER(PARTITION BY USER_NAME ORDER BY CAST(ACTIVITY_DATE_TIME AS DATETIME) ) AS 'RowNum'
   FROM 
       dbo.Transaction_History
   WHERE
       USER_NAME in ('a_user', 'b_user', 'c_user', 'd_user', 'e_user')
)
SELECT 
   USER_NAME, 
   DATE_TIME, 
   WORK_TYPE, Location, ITEM, Quantity
FROM 
   MostRecentPerUser 
WHERE
   RowNum = 1
这里,我只为每个分区选择第一个条目,即每个用户名(按日期和时间排序)

这接近你想要的吗

三个旁注:

首先,如果您有一个日期,为什么不将其存储为DATETIME或date?这应该是-认真的!不要将日期存储为NVARCHA20-永远不要

我会尽量避免使用所有大写标识符——这会使您的代码很难阅读和理解。到现在为止,我们已经超过了所有大写的终端,不是吗

另外:我建议尝试使用更有意义的expr essive名称比DATE_TIME更重要-首先,您有可能与SQL Server关键字如DATETIME或DATE发生冲突,其次-您应该努力使列名和别名真正表达它们所代表的内容-SalesDate或ActivityDate比DATE_TIME好得多


假设activity_DATE_TIME是实际的Datetime字段而不是varchar字段,这将为每个用户获取最新的activity

SELECT 
    USER_NAME, 
    max(ACTIVITY_DATE_TIME) as  ACTIVITY_DATE_TIME
FROM 
    TRANSACTION_HISTORY 
WHERE 
    USER_NAME in ('a_user','b_user','c_user','d_user','e_user')
GROUP BY user_name
如果您没有实际存储时间,那么您需要使用rownumber来获得一个用户,该用户的instnce具有多个相同的datetime

如果还需要表中的其他列,请将上述查询用作派生表:

SELECT <list the columns you need from theTRANSACTION_HISTORY table >
FROM TRANSACTION_HISTORY th
JOIN (
SELECT 
    USER_NAME, 
    max(ACTIVITY_DATE_TIME) as  ACTIVITY_DATE_TIME
FROM 
    TRANSACTION_HISTORY 
WHERE 
    USER_NAME in ('a_user','b_user','c_user','d_user','e_user')
GROUP BY user_name
) a  On th.USER_NAME = a.USER_NAME  and th. ACTIVITY_DATE_TIME = a. ACTIVITY_DATE_TIME

假设activity_DATE_TIME是实际的Datetime字段而不是varchar字段,这将为每个用户获取最新的activity

SELECT 
    USER_NAME, 
    max(ACTIVITY_DATE_TIME) as  ACTIVITY_DATE_TIME
FROM 
    TRANSACTION_HISTORY 
WHERE 
    USER_NAME in ('a_user','b_user','c_user','d_user','e_user')
GROUP BY user_name
如果您没有实际存储时间,那么您需要使用rownumber来获得一个用户,该用户的instnce具有多个相同的datetime

如果还需要表中的其他列,请将上述查询用作派生表:

SELECT <list the columns you need from theTRANSACTION_HISTORY table >
FROM TRANSACTION_HISTORY th
JOIN (
SELECT 
    USER_NAME, 
    max(ACTIVITY_DATE_TIME) as  ACTIVITY_DATE_TIME
FROM 
    TRANSACTION_HISTORY 
WHERE 
    USER_NAME in ('a_user','b_user','c_user','d_user','e_user')
GROUP BY user_name
) a  On th.USER_NAME = a.USER_NAME  and th. ACTIVITY_DATE_TIME = a. ACTIVITY_DATE_TIME

如果您只需要一条记录,您可以将top 30更改为top 1,但是您不需要的额外信息是什么?您使用的是哪些rdbms?Transaction_history表的结构是什么?特别是什么是主键?刚才注意到您转换为nvarchar,然后将列命名为DATE\u TIME?这是故意的吗?如果您只需要一条记录,您可以将前30名更改为前1名,但您不需要的额外信息是什么?您使用的是哪些rdbms?事务历史表的结构是什么?特别是什么是主键?刚才注意到您转换为nvarchar,然后将列命名为DATE\u TIME?这是故意的吗?具体的用户怎么办?我认为这些额外的信息是混乱信息的一部分。@ribot你是什么意思?它只是减少了可用行的集合。那么具体的用户呢?它被额外的信息弄糊涂了,我想这是混乱信息的一部分。@ribot你是什么意思?它只是减少了可用行的集合。我仍然使用交叉应用,但只是通过select user_name='a_user'union select'b_user'union select…Nice-没有想到。我仍然使用交叉应用,但只是通过select user_name='a_user'union select'b_user'union select…Nice-没有想到那个