2015-09-21 69 views
2

我有一個支付每月付款的用戶數據庫。我需要檢查這些付款是否有連續性。 例如下表:日期在數據庫中的連續性(找到缺少日期差距)

+---------+------------+ 
| 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 | 
+---------+------------+ 

直到5月一切正常,但6月4用戶沒有支付,雖然他在接下來的一個月(7月)支付。 七月份用戶1和2沒有付款,但這沒關係,因爲他們可能會退出服務。 因此,在這種情況下,我需要獲得「用戶4在六月份不支付」的信息。 使用SQL可以做到這一點嗎?

我使用MS Access,如果它是必要的信息。

+0

哪裏是你的代碼!你到目前爲止嘗試過什麼? – Marusyk

+0

你使用了什麼[標籤:rdbms]? – Mureinik

+0

你怎麼知道使用辭職? – Marusyk

回答

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」這兩列。如果不相同,則該用戶存在差距。

+1

我懷疑'(MAX(date)-MIN(date))/ 30 + 1',因爲它似乎假設所有的月份都有30天。也許['DateDiff('m',MAX(date),MIN(date))'](http://www.techonthenet.com/access/functions/date/datediff.php)? – Schwern

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 ANSI date是一個保留字,需要分隔爲"date"

注3:剛剛意識到這個答案只返回即使幾個(連續)失蹤的第一個月...

+0

我檢查了您的查詢,但它顯示一個空表...我使用MS Access和沒有錯誤,但表是空的。 – maro

1

從我的經驗來看,你不能只用表中的付費來填補空白。如果萬一用戶沒有支付特定的月份,則有可能您的查詢將整個月的時間排除在外。

這意味着您需要列出從1月到12月的所有日期,並檢查每個用戶是否已付費。這又需要一個表與您要求的日期進行比較。

專用RDBMS提供臨時表SP功能,它允許您創建更高級別/複雜的查詢。另一方面,ACE/JET引擎提供的可能性較小,但有一種方法可以完成此任務。 (VBA)

在任何情況下,您都需要給數據庫特定的日期以查找空位。要麼你可以說今年,要麼說年X與年Y之間。

這怎麼可能工作:

  1. 創建一個名爲tbl_date
  2. 臨時表創建一個VBA函數生成您請求的日期範圍
  3. 創建一個查詢(all_dates_all_users),您選擇要求日期&用戶標識的(沒有加入)這會給你所有的日期x所有用戶的組合
  4. 創建另一個查詢,你離開加入all_dates_all_users查詢與你的user_payments查詢。 (這將生成所有用戶的日期並加入到您的user_payments表中)
  5. 執行您的檢查user_payments是否爲空。 (如果其空用戶x沒有支付的該月)

下面是一個例子:

[表]

  1. tbl_date:ID初級(自動號碼),DATE_FIELD(日期/時間)
  2. tbl_user_payments:pay_id(自動編號,主要),user_id(編號),pay_Date(日期/時間)這是您的表格根據您的要求修改它。我不確定您是否有專用的用戶表,因此我使用此付款表來獲取user_id。

[查詢]

  1. qry_user_payments_all_month_all_user:

    SELECT年份([DATE_FIELD])AS mYear,月([DATE_FIELD])AS mMonth,qry_user_payments_user_group.user_id FROM qry_user_payments_user_group,tbl_date ORDER BY Year([date_field]),Month([date_field]),qry_user_payments_user_group.user_id;

  2. 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 [付費?] FROM 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 =月(tbl_user_payments。[pay_date])AND(qry_user_payments_all_month_all_user.mYear =年(T bl_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 : [email protected] 
'--------------------------------------------------------------------------------------- 
' 

    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") 

這將從一月生成至10月,並檢查是否收到是否付款。

[畫面]: user payments table

+0

我想知道運行此查詢時的性能問題@maro –

+0

感謝您的努力並擴展了答案,但這對我來說太複雜了。 – maro

+0

練習和學習..最終你會有一天到達那裏。 :) –