Mysql统计连续签到天数?

94 阅读2分钟

在MySQL中,由于视图定义不支持用户定义变量(如 @prev_user_id@prev_date@cnt),因此你无法直接将上述SQL查询定义为视图。但是,你可以通过其他方法实现类似的功能,例如使用窗口函数或者存储过程。

方法一:使用窗口函数

窗口函数(如 LAG() 或 LEAD())可以用来计算连续签到天数,而不依赖于用户定义变量。以下是使用窗口函数的一个示例:

sql

CREATE VIEW consecutive_signins AS
SELECT user_id, COUNT(*) AS consecutive_days
FROM (
    SELECT user_id, sign_in_date,
           LAG(sign_in_date) OVER (PARTITION BY user_id ORDER BY sign_in_date) AS prev_date,
           CASE 
               WHEN LAG(sign_in_date) OVER (PARTITION BY user_id ORDER BY sign_in_date) IS NOT NULL 
                   AND DATEDIFF(sign_in_date, LAG(sign_in_date) OVER (PARTITION BY user_id ORDER BY sign_in_date)) = 1 THEN 1
               ELSE 0
           END AS is_consecutive
    FROM sign_in_records
    WHERE sign_in_date BETWEEN CURDATE() - INTERVAL 10 DAY AND CURDATE()
    ORDER BY user_id, sign_in_date
) t
WHERE is_consecutive = 1
GROUP BY user_id
HAVING COUNT(*) >= 4;

方法二:使用存储过程

你可以将上述查询封装在一个存储过程中,然后在Java中调用这个存储过程。这样可以避免直接在视图中使用变量。

sql

创建存储过程


DELIMITER $$

CREATE PROCEDURE FindConsecutiveSignins()
BEGIN
    DROP TABLE IF EXISTS temp_signins;
    CREATE TEMPORARY TABLE temp_signins (
        user_id INT,
        sign_in_date DATE,
        cnt INT
    );

    INSERT INTO temp_signins (user_id, sign_in_date, cnt)
    SELECT user_id, sign_in_date,
           (@cnt := IF(@prev_user_id = user_id AND DATEDIFF(sign_in_date, @prev_date) = 1, @cnt + 1, 1)) AS cnt
    FROM sign_in_records
    CROSS JOIN (SELECT @prev_user_id := NULL, @prev_date := NULL, @cnt := 0) r
    WHERE sign_in_date BETWEEN CURDATE() - INTERVAL 10 DAY AND CURDATE()
    ORDER BY user_id, sign_in_date;

    SELECT user_id, COUNT(*) AS consecutive_days
    FROM temp_signins
    WHERE cnt >= 4
    GROUP BY user_id;
END $$

DELIMITER ;

在Java中调用存储过程

在Java中,你可以通过JDBC调用上述存储过程:

java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DatabaseHelper {

    private static final String DB_URL = "jdbc:mysql://localhost:3306/your_database";
    private static final String USER = "your_username";
    private static final String PASS = "your_password";

    public void callStoredProc() throws SQLException {
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement("{call FindConsecutiveSignins()}")) {
            try (ResultSet rs = pstmt.executeQuery()) {
                while (rs.next()) {
                    int userId = rs.getInt("user_id");
                    int consecutiveDays = rs.getInt("consecutive_days");
                    System.out.println("User ID: " + userId + ", Consecutive Days: " + consecutiveDays);
                }
            }
        }
    }
}

public class Main {

    public static void main(String[] args) {
        DatabaseHelper databaseHelper = new DatabaseHelper();
        try {
            databaseHelper.callStoredProc();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

总结

  1. 窗口函数:使用窗口函数可以避免使用用户定义变量,直接定义视图。
  2. 存储过程:将复杂的查询封装在存储过程中,然后在Java中调用存储过程。

这两种方法都可以实现连续签到天数的统计,并且可以在Java中方便地调用。希望这能帮助你解决问题!如果有任何进一步的问题,请随时告诉我。