簡體   English   中英

SQL Server查詢-對具有多個表中特定條件的列中的值進行計數

[英]SQL Server query - count occurrences of values in a column with specific criteria on multiple tables

我試圖從生成的SQL Server,這表明計數或出現的數量在三個不同的表報告Account_id在從賬表Account_entriesUsers從三個表不同的標准表。

表#1: 帳戶

ID          ACCOUNT_TYPE         
-------------------------
354857      Customer            
354858      Agent          
354859      Fee
354860      Customer 
354861      Customer 
354862      Agent   
354863      Cashier

表#2: ACCOUNT_ENTRIES

ID     ACCOUNT_ID   narrative_TYPE    CREATED_AT  
-------------------------------------------------
35     Customer     Fee               2018-01-02  
36     Agent        Fee               2018-11-02
37     Fee          BalanceUpdate     2018-11-03
39     Customer     BalanceUpdate     2018-11-03  

表#3: 用戶

ID    PHONE_NUMBER  REGISTERED_BY (ACCOUNT_ID)   CREATED_AT  
------------------------------------------------------------
35    XXXXXXX       354858                       2018-01-02    
36    XXXXXXX       354877                       2018-11-02
37    XXXXXXX       354858                       2018-11-03
39    XXXXXXX       354858                       2018-11-03       

我已經嘗試過此SQL查詢,但無法獲得所需的輸出:

select 
    ac.id, count(ae.id) as counter1, count(u.registered_by) as counter2 
from 
    db2inst1.accounts ac
left outer join 
    db2inst1.account_entries ae on ac.id = ae.account_id
left outer join 
    db2inst1.users u on ac.id = u.registered_by 
where 
    ae.narrative_type = 'BalanceUpdate' 
    and ae.created_at > '2018-11-30' 
    and ae.created_at < '2019-01-01' 
    and u.created_at > '2018-11-30' 
    and u.created_at < '2019-01-01' 
    and ac.account_type = 'Agent'
group by 
    ac.id

我實際上想看到的是下面

ACCOUNT_ID    COUNTER1  COUNTER2   COUNTER1+COUNTER2
----------------------------------------------------
354857            20         2      22 
354858            24        23      47
354859            26        11      37
354860            27        23      60  

其中計數器1計算account_idaccount_entries的出現次數,計數器2在users表上(注冊者)

請幫助

我認為獲取所需方法的快捷方式是使用count(distinct) 您還需要將過濾條件移到on子句中,因此不必不必要地將行過濾掉:

select ac.id, count(distinct ae.id) as counter1, 
       count(distinct u.registered_by) as counter2 
from db2inst1.accounts ac left outer join
     db2inst1.account_entries ae
     on ac.id = ae.account_id and
        ae.narrative_type = 'BalanceUpdate' and
        ae.created_at > '2018-11-30' and
        ae.created_at < '2019-01-01' left outer join
     db2inst1.users u
     on ac.id = u.registered_by and
        u.created_at > '2018-11-30' and
        u.created_at < '2019-01-01'
where ac.account_type = 'Agent'
group by ac.id;

我在SELECT查詢中看到了幾個潛在的問題(盡管嘗試非常可靠,但是很好的開始!)

  1. 進行LEFT JOIN ,然后在WHERE子句中,對LEFT JOIN的表中的列進行過濾幾乎可以將其轉換為INNER JOIN

假設account_id “ 2”在account_entries表中沒有記錄,請考慮左連接的以下結果:

SELECT * FROM accounts A LEFT JOIN account_entries B ON A.id = B.account_id

|-- accounts table --|  |----------- account_entries table ---------|
id   account_type        id    account_id  narrative_type  created_at
---------------------------------------------------------------------
1    Agent               101   1           Fee             2018-12-01
1    Agent               102   1           BalanceUpdate   2018-12-02
2    Customer            NULL  NULL        NULL            NULL
3    Agent               103   3           Fee             2018-12-01

在這種情況下,如果將查詢添加到WHERE narrative_type = 'BalanceUpdate' ,則將對每個記錄進行評估,並且由於NULL不等於'BalanceUpdate',它將過濾出account_id “ 2”。 這模仿了INNER JOIN的行為

為了解決這個問題,您可以將過濾器移到ON A.id = B.account_id AND B.narrative_type = 'BalanceUpdate'ON子句中,而不是WHERE子句中(例如, ON A.id = B.account_id AND B.narrative_type = 'BalanceUpdate'

在某些情況下,將其保留在WHERE子句中,但是使用ISNULL可以有所幫助,但是我認為在這種特定用例中這沒有任何意義。


  1. 由於account_entries和用戶中的每個帳戶可能有多個記錄,因此,如果將它們都重新加入到accounts表中,則最終會得到某種笛卡爾積。

例如,如果您具有以下account_entries:

id    account_id  narrative_type  created_at
--------------------------------------------
101   1           Fee             2018-12-01
102   1           BalanceUpdate   2018-12-02
103   3           Fee             2018-12-01

這些用戶:

id    phone_number  registered_by  created_at
---------------------------------------------
1001  XXXXX         1              2018-12-01
1002  XXXXX         1              2018-12-01
1003  XXXXX         2              2018-12-01

將它們連接在一起時,除了帳戶ID之外,它們之間沒有任何其他關系,必須將每個帳戶條目與每個與該帳戶ID相匹配的用戶進行匹配。 然后,您將得到以下結果:

account_id  account_entry_id  user_id
--------------------------------------------
1           101               1001
1           101               1002
1           102               1001
1           102               1002
2           NULL              1003
3           103               NULL

為了解決這個問題,您可以使用COUNT(DISTINCT ...) ,然后將其忽略。 這可能很好,但是也許在更大的數據集上可能會導致性能問題。

我希望在加入數據之前先進行匯總。 這可以作為簡單的子查詢完成,也可以使用通用表表達式(“ CTE”)非常干凈地完成

這是我處理查詢的方法:

WITH cte_account_entries AS
    (
        SELECT
            account_id,
            COUNT(*) account_entries
        FROM account_entries 
        WHERE   narrative_type = 'BalanceUpdate'
            AND CAST(created_at AS DATE) BETWEEN '2018-12-01' AND '2018-12-31'
        GROUP BY 
            account_id   
    ),
cte_users AS 
    (
        SELECT
            registered_by,
            COUNT(*) users
        FROM users 
        WHERE   CAST(created_at AS DATE) BETWEEN '2018-12-01' AND '2018-12-31'
        GROUP BY 
            registered_by   
    )
SELECT
    A.id account_id,
    A.account_type,
    ISNULL(B.account_entries, 0) counter1,
    ISNULL(C.users, 0) counter2,
    ISNULL(B.account_entries, 0) + ISNULL(C.users, 0) [counter1+counter2]
FROM accounts A 
LEFT JOIN cte_account_entries B
ON      A.id = B.account_id
LEFT JOIN cte_users C 
ON      A.id = C.registered_by
WHERE   A.account_type = 'Agent'

cte_account_entries是第一個公用表表達式,該表達式按帳戶計算帳戶條目的數量,從而實現問題中指出的過濾器。 注意如果列中同時包含日期和時間,我會進行CAST(... AS DATE)

cte_users相似,但是與users表有關。

最后,所有這些都合並到最終的SELECT語句中,篩選出僅“ Agent”帳戶類型,並且LEFT JOIN到CTE,每個帳戶僅產生一個記錄,因此不會有笛卡爾積。

ISNULL在這里也非常有幫助。 例如,如果沒有一個帳戶的帳戶條目,但是有12個用戶,那么您可能最終嘗試將它們加在一起,例如NULL + 12,這將產生NULL。 ISNULL會將那個NULL轉換為0,所以您得到0 + 12。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM