1

我觉得很愚蠢,但我被一个显然非常简单的查询卡住了。我有这样的东西,每一行都是观看电影的用户:

user_id     date    duration
   1      01-01-01    62m
   1      03-01-01    95m
   2      02-01-01    58m
   2      06-01-01    25m
   2      08-01-01    95m
   3      03-01-01    96m

现在,我想要一张桌子,其中有每个用户观看的第一部电影及其duration. 问题是如果我使用MIN(),那么我必须GROUP同时使用user_idduration。但如果我也一样GROUPduration那么我基本上会回到同一张桌子。我该如何解决这个问题?

4

9 回答 9

2

试试这个查询。我没有测试过。

SELECT date, duration FROM tablename n
    WHERE NOT EXISTS(
        SELECT date, user_id FROM tablename g
        WHERE n.user_id = g.user_id AND g.date < n.date
        );
于 2013-09-18T13:50:37.160 回答
2

您可以使用排名功能,如ROW_NUMBER

WITH CTE AS
(
  SELECT rn = ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY date ASC),
         user_id, date, duration
  FROM dbo.TableName
)
SELECT user_id, date, duration FROM CTE WHERE rn = 1

的优点ROW_NUMBER是您可以轻松更改逻辑。例如,如果您想反转逻辑并获取每个用户最后观看电影的行,您只需更改ORDER BY date ASCORDER BY date DESC.

(common-table-expression)的优点CTE是您还可以使用它来删除或更新这些记录。通常用于删除或识别重复项。因此,您可以在执行之前先选择查看将被删除/更新的内容。

于 2013-09-18T13:27:16.357 回答
1

您可以使用ROW_NUMBER()which 是一个排名函数,它根据您要排序的列为每个组生成序列号。在这种情况下,如果出现平局,则每个用户只选择一条记录,但如果要选择所有记录,则需要使用DENSE_RANK()而不是ROW_NUMBER()

SELECT  user_id, date, duration
FROM    
        (
            SELECT  user_id, date, duration,
                    ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY date) rn
              FROM tableName
        ) a
WHERE rn = 1

这也假设列的数据类型dateDATE

于 2013-09-18T13:26:29.790 回答
1

如果您想要每个用户的第一个 watch_date,则该用户不应有此日期之前的日期:

SELECT *
FROM watched_movies wm
WHERE NOT EXISTS (
  SELECT *
  FROM watched_movies nx
  WHERE nx.user_id = wm.user_id
  AND nx.watch_date < wm.watch_date
  );

注意:我将date列替换为watch_date,因为 date 是保留字(类型名称)。

于 2013-09-18T13:34:17.790 回答
1

如果您使用的是 SQL Server 2005 或更高版本,则可以使用窗口函数。

SELECT *
FROM
(
SELECT user_id, date, duration, MIN(date) OVER(PARTITION BY user_id) AS MIN_DATE
FROM MY_TABLE
) AS RESULTS
WHERE date = MIN_DATE

over 子句和partion by 将“分组” user_id 并选择每个 user_id 的最小日期而不消除任何行。然后,您从表中选择日期等于最小日期的日期,并留下每个 user_id 的第一个日期。一旦您了解了窗口函数,这是一个常见的技巧。

于 2013-09-18T13:34:35.967 回答
1

假设每个用户每个日期只能有一条记录,它会是这样的:

select y.*
from table t
inner join (
  select user_id, min(date) mindate
  from table
  group by user_id
) t1
  on  t.user_id = t1.user_id
      and t.date = t1.mindate
于 2013-09-18T13:26:15.980 回答
0

这应该为您提供最早日期观看的第一部电影的持续时间:

SELECT a.user_id, b.date, a.duration
FROM table a 
INNER JOIN (SELECT user_id,min(date) date FROM table GROUP BY user_id) b ON a.user_id = b.user_id AND a.date = b.date
INNER JOIN (SELECT user_id,date,min(session_id) FROM table GROUP BY user_id, date) c ON b.user_id = c.user_id AND b.date = c.date AND a.session_id = c.session_id
于 2013-09-18T13:27:58.327 回答
0

使用子查询获取最小日期,然后将其连接回表以获取所有其他相关列。

SELECT  T2.user_id
        ,T2.date
        ,T2.duration
FROM    YourTable T2
INNER JOIN
        (
        SELECT  T1.user_id
                ,MIN(T1.date) as first_date
        FROM    YourTable T1
        ) SQ
ON      T2.user_id = sq.user_id
AND     T2.date = sq.first_date
于 2013-09-18T13:30:19.947 回答
0

尝试这个:

WITH TABLE1
    AS (SELECT
             '1' AS USER_ID,
             '01-01-01' AS DT,
             62 AS DURATION
        FROM
             DUAL
        UNION ALL
        SELECT
             '1' AS USER_ID,
             '03-01-01' AS DT,
             95 AS DURATION
        FROM
             DUAL
        UNION ALL
        SELECT
             '2' AS USER_ID,
             '02-01-01' AS DT,
             58 AS DURATION
        FROM
             DUAL
        UNION ALL
        SELECT
             '2' AS USER_ID,
             '06-01-01' AS DT,
             25 AS DURATION
        FROM
             DUAL
        UNION ALL
        SELECT
             '2' AS USER_ID,
             '08-01-01' AS DT,
             95 AS DURATION
        FROM
             DUAL
        UNION ALL
        SELECT
             '3' AS USER_ID,
             '03-01-01' AS DT,
             96 AS DURATION
        FROM
             DUAL)
SELECT
      *
FROM
      (SELECT
            USER_ID,
            DT,
            DURATION,
            RANK ( ) OVER (PARTITION BY USER_ID ORDER BY DT ASC) AS ROW_RANK
       FROM
            TABLE1)
WHERE
      ROW_RANK = 1
于 2013-09-18T13:29:45.787 回答