我有一个每月付款的用户数据库。我需要检查这些付款是否有连续性。 例如,在下表中:
+---------+------------+
| user_id | date |
+---------+------------+
| 1 | 2015-02-01 |
| 2 | 2015-02-01 |
| 3 | 2015-02-01 |
| 1 | 2015-03-01 |
| 2 | 2015-03-01 |
| 3 | 2015-03-01 |
| 4 | 2015-03-01 |
| 1 | 2015-04-01 |
| 2 | 2015-04-01 |
| 3 | 2015-04-01 |
| 4 | 2015-04-01 |
| 5 | 2015-04-01 |
| 1 | 2015-05-01 |
| 2 | 2015-05-01 |
| 3 | 2015-05-01 |
| 4 | 2015-05-01 |
| 5 | 2015-05-01 |
| 1 | 2015-06-01 |
| 2 | 2015-06-01 |
| 3 | 2015-06-01 |
| 5 | 2015-06-01 |
| 3 | 2015-07-01 |
| 4 | 2015-07-01 |
| 5 | 2015-07-01 |
+---------+------------+
直到五月一切正常,但是在6月份用户4没有付款,尽管他在下个月(7月)付款。 7月份用户1和2没有付费,但这没关系,因为他们可以从服务中退出。 因此,在这种情况下,我需要提供“用户4未在6月支付”的信息。 是否可以使用SQL做到这一点?
如果是必要的信息,我会使用MS Access。
答案 0 :(得分:1)
根据我的经验,您不能只使用付费表来填补空白。如果您的所有用户都没有支付特定月份的费用,则您的查询可能会使整个月离开等式。
这意味着您需要列出从1月到12月的所有日期,并检查每个用户是否已付款。这又需要一张表格,其中包含您要求的日期进行比较。
专用RDBMS提供临时表,SP,函数,允许您创建更高级别/复杂的查询。另一方面,ACE / JET引擎提供的可能性较小,但有一种方法可以完成这项工作。 (VBA)
在任何情况下,您都需要为数据库指定要查找空白的特定日期。您可以说当前年份或年份X和年份之间。
在这里它是如何工作的:
以下是一个例子:
[表]
[查询]
qry_user_payments_all_month_all_user:
SELECT Year([date_field])AS mYear,Month([date_field])AS mMonth,qry_user_payments_user_group.user_id 来自qry_user_payments_user_group,tbl_date 按年份排序([date_field]),月份([date_field]),qry_user_payments_user_group.user_id;
qry_user_payments_paid_or_not_paid
SELECT qry_user_payments_all_month_all_user.mYear, qry_user_payments_all_month_all_user.mMonth, qry_user_payments_all_month_all_user.user_id, IIf(IsNull([tbl_user_payments]。[user_id]),“未付款”,“付费”)AS [支付?] 来自qry_user_payments_all_month_all_user LEFT JOIN tbl_user_payments ON(qry_user_payments_all_month_all_user.user_id = tbl_user_payments.user_id) AND((qry_user_payments_all_month_all_user.mMonth = month(tbl_user_payments。[pay_date])AND(qry_user_payments_all_month_all_user.mYear = year(tbl_user_payments。[pay_date])))) ORDER BY qry_user_payments_all_month_all_user.mYear,qry_user_payments_all_month_all_user.mMonth,qry_user_payments_all_month_all_user.user_id;
[功能]
Public Function FN_CRETAE_DATE_TABLE(iDate_From As Date, Optional iDate_To As Date)
'---------------------------------------------------------------------------------------
' Procedure : FN_CRETAE_DATE_TABLE
' Author : KRISH KM
' Date : 22/09/2015
' Purpose : will generate date period and check whether payments are received. A query will be opened with results
' CopyRights: You are more than welcome to edit and reuse this code. i'll be happy to receive courtesy reference:
' Contact : krishkm@outlook.com
'---------------------------------------------------------------------------------------
'
Dim From_month, To_Month As Integer
Dim From_Year, To_Year As Long
Dim I, J As Integer
Dim SQL_SET As String
Dim strDoc As String
strDoc = "tbl_date"
DoCmd.SetWarnings (False)
SQL_SET = "DELETE * FROM " & strDoc
DoCmd.RunSQL SQL_SET
If (IsMissing(iDate_To)) Or (iDate_To <= iDate_From) Then
'just current year
From_month = VBA.Month(iDate_From)
From_Year = VBA.Year(iDate_From)
For I = From_month To 12
SQL_SET = "INSERT INTO " & strDoc & "(date_field) values ('" & From_Year & "-" & VBA.Format(I, "00") & "-01 00:00:00')"
DoCmd.RunSQL SQL_SET
Next I
Else
From_month = VBA.Month(iDate_From)
To_Month = VBA.Month(iDate_To)
From_Year = VBA.Year(iDate_From)
To_Year = VBA.Year(iDate_To)
For J = From_Year To To_Year
For I = From_month To To_Month
SQL_SET = "INSERT INTO " & strDoc & "(date_field) values ('" & J & "-" & VBA.Format(I, "00") & "-01 00:00:00')"
DoCmd.RunSQL SQL_SET
Next I
Next J
End If
DoCmd.SetWarnings (True)
On Error Resume Next
strDoc = "qry_user_payments_paid_or_not_paid"
DoCmd.Close acQuery, strDoc
DoCmd.OpenQuery strDoc, acViewNormal
End Function
您可以从按钮或表单或调试窗口调用此公共函数:
?FN_CRETAE_DATE_TABLE("2015-01-01","2015-10-01")
这将从jan生成到oct并检查您是否收到了付款。
答案 1 :(得分:0)
这样的事情,寻找下个月没有付款的用户,但是付款后的那个月:
select user_id, month(date) + 1
from tablename t1
where not exists (select 1 from tablename t2
where t2.user_id = t1.user_id
and month(t2.date) = month(t1.date) + 1)
and exists (select 1 from tablename t3
where t3.user_id = t1.user_id
and month(t3.date) > month(t1.date) + 2)
注1:没有指定dbms,因此month()
函数只是伪代码。 ANSI SQL具有extract(month from column_name)
。
注意2:在ANSI SQL date
中是保留字,需要以"date"
分隔。
注3:刚刚意识到这个答案只会在第一个月返回,即使有几个(连续的)缺失......
答案 2 :(得分:0)
我已经为此编写了一个简单的查询,但我意识到这不是最好的解决方案。其他解决方案仍然受到欢迎。
SELECT user_id,
MIN(date) AS min_date,
MAX(date) AS max_date,
COUNT(*) AS no_of_records,
round((MAX(date)-MIN(date))/30.4+1,0) AS months,
(months-no_of_records) AS diff
FROM test
GROUP BY user_id
HAVING (round((MAX(date)-MIN(date))/30.4+1,0)-COUNT(*)) > 0
ORDER BY 6 DESC;
现在我们可以看一下“no_of_records”和“months”栏目。如果它们不相等,则该用户存在差距。