Manejar SQL: tome "contar usuarios que han iniciado sesión durante más de 3 días consecutivos" como ejemplo para manejar el mismo tipo de requisitos de SQL


  • Como desarrollador de big data, nunca debe dejar atrás sus capacidades de SQL.

1. Introducción

Cuando trabajamos en ETL o en entrevistas de big data, el SQL a menudo se rompe a mano y el SQL común tiene problemas continuos de inicio de sesión. La pregunta general es "Estadísticas de XX que han iniciado sesión en XX durante N días consecutivos".
El editor está aquí hoy para presentar dos soluciones para que pueda manejar fácilmente estos problemas de SQL.

Muchas funciones de mysql8.x y Hive están básicamente satisfechas. En aras de la eficiencia y la conveniencia, aquí está mysql como ejemplo. Otro SQL es similar. Si tiene alguna pregunta, puede dejar un mensaje en el área de comentarios.

Caso: Basado en el requisito de "contar usuarios que han iniciado sesión por más de 3 días consecutivos".

preparación de datos

Ejecute el siguiente código en mysql para generar la tabla de datos correspondiente

-- ----------------------------
-- Table structure for user_activity
-- ----------------------------
DROP TABLE IF EXISTS `user_activity`;
CREATE TABLE `user_activity`  (
  `user_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `activity_date` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user_activity
-- ----------------------------
INSERT INTO `user_activity` VALUES ('user1', '2023-03-01');
INSERT INTO `user_activity` VALUES ('user2', '2023-03-02');
INSERT INTO `user_activity` VALUES ('user3', '2023-03-03');
INSERT INTO `user_activity` VALUES ('user4', '2023-03-04');
INSERT INTO `user_activity` VALUES ('user1', '2023-03-08');
INSERT INTO `user_activity` VALUES ('user2', '2023-03-08');
INSERT INTO `user_activity` VALUES ('user5', '2023-03-08');
INSERT INTO `user_activity` VALUES ('user6', '2023-03-08');
INSERT INTO `user_activity` VALUES ('user3', '2023-03-09');
INSERT INTO `user_activity` VALUES ('user5', '2023-03-09');
INSERT INTO `user_activity` VALUES ('user6', '2023-03-09');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-09');
INSERT INTO `user_activity` VALUES ('user3', '2023-03-10');
INSERT INTO `user_activity` VALUES ('user5', '2023-03-10');
INSERT INTO `user_activity` VALUES ('user6', '2023-03-10');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-10');
INSERT INTO `user_activity` VALUES ('user5', '2023-03-11');
INSERT INTO `user_activity` VALUES ('user6', '2023-03-11');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-11');
INSERT INTO `user_activity` VALUES ('user6', '2023-03-12');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-12');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-13');
INSERT INTO `user_activity` VALUES ('user8', '2023-03-13');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-14');
INSERT INTO `user_activity` VALUES ('user8', '2023-03-14');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-15');
INSERT INTO `user_activity` VALUES ('user8', '2023-03-15');
INSERT INTO `user_activity` VALUES ('user8', '2023-03-16');
SELECT * FROM `user_activity`

El resultado es el siguiente:

user1	2023-03-01
user2	2023-03-02
user3	2023-03-03
user4	2023-03-04
user1	2023-03-08
user2	2023-03-08
user5	2023-03-08
user6	2023-03-08
user3	2023-03-09
user5	2023-03-09
user6	2023-03-09
user7	2023-03-09
user3	2023-03-10
user5	2023-03-10
user6	2023-03-10
user7	2023-03-10
user5	2023-03-11
user6	2023-03-11
user7	2023-03-11
user6	2023-03-12
user7	2023-03-12
user7	2023-03-13
user8	2023-03-13
user7	2023-03-14
user8	2023-03-14
user7	2023-03-15
user8	2023-03-15
user8	2023-03-16

inserte la descripción de la imagen aquí

Opción 1: pensamiento convencional

  • 1. Primero agrupe los datos user_id, ordénelos según la fecha de actividad del usuario
  • 2. Use la fecha de inicio de sesión y rn para encontrar date_sub, si las fechas de diferencia obtenidas son iguales, significa que estos dos días deben ser consecutivos
    • Por ejemplo, 1 de enero, 2 de enero y 3 de enero de 2023; las clasificaciones son 1, 2 y 3 respectivamente; ahora use la fecha: ¿la clasificación es igual al 31 de diciembre de 2022?
  • 3. De acuerdo con la agrupación sub_fecha de ID de usuario y diferencia de fecha, el número de inicios de sesión se cuenta (1) después de la agrupación

Para agrupar los datos user_id, ordene según la fecha de actividad del usuario

select
			user_id,
			activity_date,
			ROW_NUMBER() over(partition by user_id order by activity_date) as rn
from user_activity

inserte la descripción de la imagen aquí

Use la fecha de inicio de sesión y rn para encontrar date_sub, si las fechas de diferencia obtenidas son iguales, significa que estos dos días deben ser consecutivos

SELECT
		user_id,
		activity_date,
		DATE_SUB(activity_date,INTERVAL rn DAY) as sub_date
	from(
		select
			user_id,
			activity_date,
			ROW_NUMBER() over(partition by user_id order by activity_date) as rn
		from user_activity
	)t1

inserte la descripción de la imagen aquí

Agrupados según user_id y diferencia de fecha sub_date, el número de inicios de sesión se cuenta (1) después de agrupar

SELECT
	user_id,
	min(activity_date) as min_date,
	max(activity_date)  as max_date,
	count(1) as  login_times
from(
	SELECT
		user_id,
		activity_date,
		DATE_SUB(activity_date,INTERVAL rn DAY) as sub_date
	from(
		select
			user_id,
			activity_date,
			ROW_NUMBER() over(partition by user_id order by activity_date) as rn
		from user_activity
	)t1
)t2
group by user_id,sub_date
having login_times>=3;

inserte la descripción de la imagen aquí

  • De los resultados, se puede ver que los usuarios 5, 6, 7 y 8 han iniciado sesión durante 3 días consecutivos o más

Solución 2: utilice funciones de retraso y adelanto

  • 1. Para cada ID de usuario, primero use las funciones de retraso y adelanto para encontrar la fecha del día anterior y el día posterior a la fecha actual
  • 2. Para cada usuario, si la diferencia entre la fecha del día anterior y el día siguiente y la fecha actual = 1, pertenece al inicio de sesión continuo.
    • Por ejemplo, 1 de enero, 2 de enero y 3 de enero de 2023, ahora use la fecha 2: la diferencia entre antes y después es 2-1 = 1, 3-2 = 1. Si el valor es 1 o no Paño de lana.
  • 3. Para la agrupación de usuarios, la función dateiff calcula los días del tiempo máximo de actividad y el tiempo mínimo de actividad, y calcula los usuarios >=3 días

Use las funciones LEAD y LAG para encontrar la fecha antes y después de 1 día

select
		user_id,
		LAG(activity_date,1,activity_date) over(partition by user_id order by activity_date) as lag_login_date,
		activity_date as current_login_date,
		LEAD(activity_date,1,activity_date) over(partition by user_id order by activity_date) as lead_login_date
	from user_activity

inserte la descripción de la imagen aquí

Para cada usuario, si la diferencia entre la fecha del día anterior y el día siguiente y la fecha actual = 1, pertenece al inicio de sesión continuo.

SELECT
	user_id,
	lag_login_date,
	current_login_date,
	lead_login_date
from(
	select
		user_id,
		LAG(activity_date,1,activity_date) over(partition by user_id order by activity_date) as lag_login_date,
		activity_date as current_login_date,
		LEAD(activity_date,1,activity_date) over(partition by user_id order by activity_date) as lead_login_date
	from user_activity
)t1
where datediff(current_login_date,lag_login_date)=1 
and datediff(lead_login_date,current_login_date)=1;

Para la agrupación de usuarios, la función dateiff calcula los días del tiempo máximo de actividad y el tiempo mínimo de actividad, y calcula los usuarios >=3 días

SELECT
	user_id,
	min(activity_date) as min_date,
	max(activity_date)  as max_date,
	count(1) as  login_times
from(
	SELECT
		user_id,
		activity_date,
		DATE_SUB(activity_date,INTERVAL rn DAY) as sub_date
	from(
		select
			user_id,
			activity_date,
			ROW_NUMBER() over(partition by user_id order by activity_date) as rn
		from user_activity
	)t1
)t2
group by user_id,sub_date
having login_times>=3;

inserte la descripción de la imagen aquí

Comparación del esquema 1 y el esquema 2

Solución 1, la idea es muy simple y más fácil de implementar Se puede completar simplemente al comprender la función de clasificación de ventanas y las capacidades básicas de SQL. En el nivel de dificultad
,
la opción 2 tiene una idea simple, pero es más difícil de implementar y requiere cierta comprensión y habilidad en la función de apertura de ventanas. dificultad alta


Supongo que te gusta

Origin blog.csdn.net/m0_49303490/article/details/130469205
Recomendado
Clasificación