2014-05-12 53 views
-1

我有以下三個表,成員,ageGroup和日誌。我想知道每個年齡組有多少人在特定的時間內訪問系統。 下面是表的詳細信息獲取屬於一個組的用戶數

tblMembers:

Member_Id,出生日期,年齡

tblAgeGroup:

AgeGroup標識,AgeGroup_Des,MINAGE,MAXAGE,meanAge

tblLog:

Member_Id,AccessDate

所以當管理員選擇一個時間範圍,如2014年1月4日於30/04/2014

我需要示出了類似於下面的輸出:

AgeGroup用戶

15-25 -------------- 3

25-35 -------------- 2

的無

我怎麼都無法這樣做。下面是我根據劇本迄今所做

SELECT Member_Id, Age 
    FROM tblLog 
     JOIN tblMembers ON tblMembers.Member_Id = tblLog.Member_Id 
    WHERE AccessDate >= '2014-04-01' 
    AND AccessDate <= '2014-04-30' 
    GROUP BY Member_Id, Age 

,我能列出Members_Id和他們的年齡。我如何通過在tblAgeGroup表中找到的組詳細信息進行分組。

請指教我。謝謝

+2

您使用的是哪種數據庫平臺? MySQL或SQL Server? –

+0

當您運行該查詢時會發生什麼? –

+0

@PatrickHofman我正在使用MSSQL –

回答

1

嘗試

SELECT ag.AgeGroup_Des, count(1) 
    FROM tblLog l 
     INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id 
     INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age and ag.maxAge > m.Age 
    WHERE AccessDate >= '2014-04-01' 
    AND AccessDate <= '2014-04-30' 
    GROUP BY ag.AgeGroup_Des 

然而,使用間隔,因爲我們在這裏做的tblAgeGroup加入時,它來測試我們得到正確的行數是很重要的。

所以我會運行下面的查詢,並驗證他們確實做返回相同的行數:

SELECT COUNT(1) 
    FROM tblLog l 
     INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id 
     --INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age and ag.maxAge > m.Age 
    WHERE AccessDate >= '2014-04-01' 
    AND AccessDate <= '2014-04-30' 

SELECT COUNT(1) 
    FROM tblLog l 
     INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id 
     INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age and ag.maxAge > m.Age 
    WHERE AccessDate >= '2014-04-01' 
    AND AccessDate <= '2014-04-30' 

有跡象表明,我想起兩兩件事,在這裏使用間隔時可能會出錯。

首先;如果間隔沒有唯一定義,則每個成員都會返回幾次。 如考慮含 ... ,MINAGE = 15 ,MAXAGE = 35 ... 和另一個條目tblAgeGroup: ... ,MINAGE = 20 ,MAXAGE = 25 ...

與21年齡將因此在這兩個區間得到恢復,從而在數量製造通貨膨脹的成員。

其次;如果Age未在tblMembers中定義,則該行將被排除,但這可能是有意的,因爲我們正在使用內部聯接。 你可以解決這個問題,有以下幾點:

SELECT ISNULL(ag.AgeGroup_Des, 'No group found') as AgeGroup_Des, 
     COUNT(1) as "AMT users" 
    FROM tblLog l 
     INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id 
     LEFT JOIN tblAgeGroup ag ON ag.minAge <= m.Age and ag.maxAge > m.Age 
    WHERE AccessDate >= '2014-04-01' 
    AND AccessDate <= '2014-04-30' 
    GROUP BY ISNULL(ag.AgeGroup_Des, 'No group found') 
    ORDER BY 1 

編輯: 增加了SQLFiddle測試: http://sqlfiddle.com/#!6/137b8/5

查詢的小提琴是:

體形:

CREATE TABLE tblMembers 
(
    Member_ID int, 
    DOB date, 
    Age int 
); 

CREATE TABLE tblAgeGroup 
(
    [AgeGroup Id] int, 
    AgeGroup_Des varchar(16), 
    minAge int, 
    maxAge int, 
    meanAge float 
); 

CREATE TABLE tblLog 
(
    Member_id int, 
    AccessDate date 
); 



INSERT INTO tblMembers 
     (Member_ID, DOB, Age) 
SELECT 1, '1991-03-22', 23 
UNION ALL 
SELECT 2, '2000-03-22', 14 
UNION ALL 
SELECT 3, '1981-03-22', 33 
UNION ALL 
SELECT 4, null, null; 

INSERT INTO tblAgeGroup 
     ([AgeGroup Id], AgeGroup_Des, minAge, maxAge, meanAge) 
SELECT 1, '15-25', 15, 25, null 
UNION ALL 
SELECT 2, '10-15', 10, 15, null 
UNION ALL 
SELECT 3, '25-55', 25, 55, null; 

INSERT INTO tblLog 
     (Member_id, AccessDate) 
SELECT 1, GETDATE() 
UNION ALL 
SELECT 2, GETDATE() 
UNION ALL 
SELECT 1, '2014-04-02' 
UNION ALL 
SELECT 2, '2014-04-03' 
UNION ALL 
SELECT 2, '2014-04-03' 
UNION ALL 
SELECT 3, '2014-04-03' 
UNION ALL 
SELECT 4, '2014-04-03'; 

查詢:

-- First query: (exludes member 4, since no DOB is registered: 
SELECT ag.AgeGroup_Des, COUNT(1) 
    FROM tblLog l 
     INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id 
     INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age and ag.maxAge > m.Age 
    WHERE AccessDate >= '2014-04-01' 
    AND AccessDate <= '2014-04-30' 
    GROUP BY ag.AgeGroup_Des; 

-- To validate that the counts are the same: 
SELECT COUNT(1) 
    FROM tblLog l 
     INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id 
     --INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age AND ag.maxAge > m.Age 
    WHERE AccessDate >= '2014-04-01' 
    AND AccessDate <= '2014-04-30'; 

-- Second validation: 
-- Notice: this does return one less row, since we are using inner join, 
-- and thus ommitting member 4 
SELECT COUNT(1) 
    FROM tblLog l 
     INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id 
     INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age AND ag.maxAge > m.Age 
WHERE AccessDate >= '2014-04-01' 
    AND AccessDate <= '2014-04-30'; 

-- Last query, which includes members with no DOB registered, 
-- as well as members that does not fall into any group: 
SELECT ISNULL(ag.AgeGroup_Des, 'No group found') as AgeGroup_Des, 
     COUNT(1) as "AMT users" 
    FROM tblLog l 
     INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id 
     LEFT JOIN tblAgeGroup ag ON ag.minAge <= m.Age AND ag.maxAge > m.Age 
    WHERE AccessDate >= '2014-04-01' 
    AND AccessDate <= '2014-04-30' 
    GRUOP BY ISNULL(ag.AgeGroup_Des, 'No group found') 
    ORDER BY 1; 

2014年5月14日:編輯:

我在您的意見看,你還需要爲空組計數。爲了做到這一點,我已經「倒置」了from子句,以便我們從tblAgeGroup中選擇所有,然後左加入其他表。

此外,我認爲你需要一些日誌條目,但在閱讀評論後,我看到你要求不同的用戶。我已經相應地更改了查詢。

select 
    ag.AgeGroup_Des 
, count(l.Member_ID)   as [AMT Log entries] 
, count(distinct l.Member_ID) as [AMT distinct members] 
from tblAgeGroup ag 
left join tblMembers m on ag.minAge <= m.Age and ag.maxAge > m.Age 
left join tblLog l on l.Member_id = m.Member_ID 
group by isnull(ag.AgeGroup_Des, 'No group found') 
order by 1 
; 

返回

AgeGroup_Des AMT Log entries AMT distinct members 
10-15    3    1 
15-25    2    1 
25-55    1    1 
55-65    0    0 

然而,這種方法確實會忽略不具有DOB /年齡登記的每一個成員。 如果我們要包括這些藏漢,我們需要編輯查詢到完全外部聯接:

select 
    isnull(ag.AgeGroup_Des, 'No group found') as AgeGroup_Des 
, count(l.Member_ID)   as [AMT Log entries] 
, count(distinct l.Member_ID) as [AMT distinct members] 
from tblAgeGroup ag 
full outer join tblMembers m on ag.minAge <= m.Age and ag.maxAge > m.Age 
full outer join tblLog l on l.Member_id = m.Member_ID 
group by isnull(ag.AgeGroup_Des, 'No group found') 
order by 1 
; 

返回

AgeGroup_Des AMT Log entries AMT distinct members 
10-15    3    1 
15-25    2    1 
25-55    1    1 
55-65    0    0 
No group found  1    1 

見更新小提琴這裏:http://sqlfiddle.com/#!6/d8733/5

+0

當我運行你發佈的第一個腳本我得到0條記錄。 –

+0

@GunnarKundsen,但是你的第二個腳本指示了2301條記錄,第三個腳本指向了0條記錄。我可以知道這是爲什麼嗎? –

+0

不知道你的數據集,我不能說這是爲什麼,但我已經創建了一些測試數據,查詢按預期執行,看到這個小提琴:http://sqlfiddle.com/#!6/137b8/ 5(我也編輯過這個答案)。你的數據集有何不同? –

0
SELECT usr_type, SUM(_15_25 + _25_35) AS qty 
    FROM 
     (SELECT CASE 
        WHEN age>=15 AND age<25 THEN '15-25' 
        WHEN age>=25 AND age<=35 THEN '25-35' 
        ELSE 'other' 
       END AS usr_type, 
       CASE 
        WHEN age>= 15 AND age < 25 THEN 1 
        ELSE 0 
       END AS _15_25, 
       CASE 
        WHEN age >= 25 AND age <= 35 THEN 1 
        ELSE 0 
       END AS _25_35 
       Age 
      FROM tblLog 
       JOIN tblMembers ON tblMembers.Member_Id = tblLog.Member_Id 
      WHERE AccessDate >= '2014-04-01' 
      AND AccessDate <= '2014-04-30' 
     ) T 
    GROUP BY usr_type 

試試這個邏輯解決方案。

0
SELECT minAge, maxAge, count(*) as "No of Users" 
    FROM tblAgeGroup g 
     INNER JOIN tblMembers m ON Age BETWEEN minAge AND maxAge 
     INNER JOIN tblLog l ON m.Member_ID = l.Member_ID 
    WHERE AccessDate BETWEEN '2014-04-01' and '2014-04-30' 
    GROUP BY minAge, maxAge 
    ORDER BY minAge, maxAge