我感觉很愚蠢,但是我很难接受一个非常简单的查询。我有类似的东西,每一行都是观看电影的用户:
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_id
和duration
。但是,如果我GROUP
也duration
,那么我基本上会有相同的表格。我该如何解决这个问题呢?
答案 0 :(得分: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 ASC
更改为ORDER BY date DESC
。
CTE
(common-table-expression)的优点是您还可以使用它来删除或更新这些记录。通常用于删除或识别重复项。因此,您可以先选择在执行之前查看将删除/更新的内容。
答案 1 :(得分: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
);
答案 2 :(得分: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
答案 3 :(得分:1)
您可以使用ROW_NUMBER()
这是一种排名功能,可根据您要排序的列为每个组生成序号。在这种情况下,如果存在平局,则只选择每个用户的一条记录,但如果要选择所有这些记录,则需要使用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
这也假设列date
的数据类型为DATE
答案 4 :(得分: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是保留字(类型名称)。
答案 5 :(得分: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将“分组”user_id并选择每个user_id的最小日期而不消除任何行。然后从表中选择日期等于最小日期,并留下每个user_id的第一个日期。一旦你了解了窗口函数,这是一个常见的技巧。
答案 6 :(得分: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
答案 7 :(得分: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
答案 8 :(得分: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