2013-02-07 19 views
0

我有一個查詢,檢查數據庫以查看客戶是否每天訪問多次。如果他們有它訪問的次數,然後告訴我他們訪問的次數。問題是它將「Tickets.lcustomerid」引入group by子句,導致我錯過了5條記錄(沒有條碼的客戶)。如何更改以下查詢以從group by子句中刪除「tickets.lcustomerid」...如果將其刪除,則會收到一個錯誤,告訴我「Tickets.lCustomerID」不是有效的選擇,因爲它不是聚合的一部分或groupby子句。Group按列拋出查詢

的作品查詢:

SELECT  Customers.sBarcode, CAST(FLOOR(CAST(Tickets.dtCreated AS FLOAT)) AS DATETIME) AS dtCreatedDate, COUNT(Customers.sBarcode) AS [Number of Scans], 
         MAX(Customers.sLastName) AS LastName 
FROM   Tickets INNER JOIN 
         Customers ON Tickets.lCustomerID = Customers.lCustomerID 
WHERE  (Tickets.dtCreated BETWEEN @startdate AND @enddate) AND (Tickets.dblTotal <= 0) 
GROUP BY Customers.sBarcode, CAST(FLOOR(CAST(Tickets.dtCreated AS FLOAT)) AS DATETIME) 
HAVING  (COUNT(*) > 1) 
ORDER BY dtCreatedDate 

輸出爲:

sBarcode dtcreated Date  Number of Scans slastname  
1234  1/4/2013 12:00:00 AM   2   Jimbo   
     1/5/2013 12:00:00 AM   3   Jimbo2  
1578  1/6/2013 12:00:00 AM   3   Jimbo3   

我與子查詢

SELECT customers.sbarcode, 
     Max(customers.slastname)         AS LastName, 
     Cast(Floor(Cast(tickets.dtcreated AS FLOAT)) AS DATETIME) AS 
     dtCreatedDate, 
     Count(customers.sbarcode)         AS 
     [Number of Scans], 
     Stuff ((SELECT ', ' 
         + RIGHT(CONVERT(VARCHAR, dtcreated, 100), 7) AS [text()] 
       FROM tickets AS sub 
       WHERE (lcustomerid = tickets.lcustomerid) 
         AND (dtcreated BETWEEN Cast(Floor(Cast(tickets.dtcreated 
                   AS 
                   FLOAT)) AS 
                DATETIME 
              ) 
               AND 
Cast(Floor(Cast(tickets.dtcreated 
AS FLOAT 
)) AS 
DATETIME 
) 
+ '23:59:59') 
AND (dbltotal <= '0') 
FOR xml path('')), 1, 1, '')      AS [Times Scanned] 
FROM tickets 
     INNER JOIN customers 
       ON tickets.lcustomerid = customers.lcustomerid 
WHERE (tickets.dtcreated BETWEEN @startdate AND @enddate) 
     AND (tickets.dbltotal <= 0) 
GROUP BY customers.sbarcode, 
      Cast(Floor(Cast(tickets.dtcreated AS FLOAT)) AS DATETIME), 
      tickets.lcustomerid 
HAVING (Count(*) > 1) 
ORDER BY dtcreateddate 

電流輸出電流查詢(注意記錄沒有條形碼缺少)是:

sBarcode dtcreated Date  Number of Scans slastname Times Scanned 
1234  1/4/2013 12:00:00 AM   2   Jimbo   12:00PM, 1:00PM 
1578  1/6/2013 12:00:00 AM   3   Jimbo3  03:05PM, 1:34PM 
+1

哦,我的所有'BETWEEN's和'VARCHAR'沒有長度...

+1

我認爲有趣的是,你正在對customers.sbarcode進行分組並獲取該列的數量。我敢肯定它是有效的,因爲你沒有得到一個明確的,但爲了這個計數不止一個,必須有一些其他列創建多個計數;從可讀性的角度來看,使用這一列進行計數會更好。你能解釋哪張表包含未加入其他表中的記錄的記錄?有五張[票據]記錄沒有匹配的[客戶]記錄,反之亦然?解決方案可能是左連接。 –

+0

它們是5張票據記錄,並且DO有匹配的客戶記錄。如果我運行查詢,而不是子查詢,我會得到結果。缺少的結果是5沒有條形碼。我將發佈可用的查詢和輸出。 – Shmewnix

回答

1

更新:基於我們的「聊天」,似乎customerid不是唯一的字段,但條碼是,即使客戶ID是主鍵。

因此,爲了在子查詢中不需要GROUP BY客戶ID,您需要加入其中的第二個客戶表,以便實際加入條形碼。

試試這個:

SELECT customers.sbarcode, 
     Max(customers.slastname)         AS LastName, 
     Cast(Floor(Cast(tickets.dtcreated AS FLOAT)) AS DATETIME) AS 
     dtCreatedDate, 
     Count(customers.sbarcode)         AS 
     [Number of Scans], 
     Stuff ((SELECT ', ' 
         + RIGHT(CONVERT(VARCHAR, dtcreated, 100), 7) AS [text()] 
       FROM tickets AS subticket 
       inner join 
       customers as subcustomers 
       on 
       subcustomers.lcustomerid = subticket.lcustomerid 
       WHERE (subcustomers.sbarcode = customers.sbarcode) 
         AND (subticket.dtcreated BETWEEN Cast(Floor(Cast(tickets.dtcreated 
                   AS 
                   FLOAT)) AS 
                DATETIME 
              ) 
               AND 
Cast(Floor(Cast(tickets.dtcreated 
AS FLOAT 
)) AS 
DATETIME 
) 
+ '23:59:59') 
AND (dbltotal <= '0') 
FOR xml path('')), 1, 1, '')      AS [Times Scanned] 
FROM tickets 
     INNER JOIN customers 
       ON tickets.lcustomerid = customers.lcustomerid 
WHERE (tickets.dtcreated BETWEEN @startdate AND @enddate) 
     AND (tickets.dbltotal <= 0) 
GROUP BY customers.sbarcode, 
      Cast(Floor(Cast(tickets.dtcreated AS FLOAT)) AS DATETIME) 
HAVING (Count(*) > 1) 
ORDER BY dtcreateddate 
+0

我不知道數據或說明會有幫助。查詢運行正常,如果唯一的分組是按日期和條形碼。一旦你通過lcustomerID進行分組,它將丟棄沒有條形碼的票。我需要通過子查詢中的lcustomerID加入,否則我不會得到「掃描時間」 – Shmewnix

+1

由於密鑰爲空,或者客戶中沒有每張票據的記錄,它只會「丟棄」數據,反之亦然...我不知道這些表中的數據是什麼,所以無法幫助您加入。你說這是因爲他們沒有條形碼,但我不知道哪個是條形碼,哪個是主鍵,等等。 –

+0

請看上面的信息,這對你來說足夠具體嗎?或者你需要更多的信息? – Shmewnix

1

我不能直接解決您的問題,因爲我不明白你的數據模型,或者您正在與此查詢完成的任務。不過,我可以給你一些關於如何自己解決問題的建議。

首先,您是否明白自己想要完成什麼以及表格如何配合?如果這麼做繼續下一步,如果沒有,首先得到這個知識,沒有這種理解,你不能做複雜的查詢。

下一步打破你在小步驟中想要完成的任務,並確保在轉移到其餘部分之前完成每項任務。所以在你的情況下,你似乎錯過了一些客戶。從一個新的查詢開始(我很確定這個問題有多個)。因此,從join和where子句開始。

我懷疑你可能需要從客戶開始並離開加入門票(這會將門票的條件移到左側,因爲他們在門票上)。這將讓你所有的客戶,無論他們有沒有門票。如果這不是你想要的,那麼使用jon和where語句(並在你試圖找出結果的時候使用select *),直到你返回你需要的確切的客戶記錄集。在此階段使用select *的原因是要查看數據中可能導致您遇到的問題。這可能會告訴你如何解決。

通常我從一個連接開始,然後每次添加一個where類,直到我知道我獲得了正確的初始記錄集。如果您有多個連接,請一次完成一次,以便知道您突然開始時的記錄是否多於或少於預期。

然後進入更復雜的部分。一次添加一個,並檢查結果。如果您突然從10條記錄轉到5或15條,那麼您可能遇到了問題。當你一步一步工作並遇到問題時,你確切知道是什麼原因導致問題變得更容易找到和修復。

Group BY對徹底理解很重要。您必須擁有組中的所有非聚合字段,否則它將無法工作。把這看作是像重力定律一樣的規律。這不是你可以改變的。但是可以通過使用派生表或CTE來解決它。如果你不知道它們是什麼,請仔細閱讀這些內容,當你進入複雜的東西時,它們是非常有用的技巧,你應該徹底理解它們。我懷疑你將需要在這裏使用派生表方法來將你需要的東西分組,然後將派生表加入到查詢的其餘部分來獲取ontehr字段。我會舉一個簡單的例子:

select 
     t1.table1id 
    , t1.field1 
    , t1.field2 
    , a.field3 
    , a.MostRecentDate 
From table1 t1 
JOIN 
    (select t1.table1id, t2.field3, max (datefield) as MostRecentDate 
    from table1 t1 
    JOin Table2 t2 on t1.table1id = t2.table1id 
    Where t2.field4 = 'test' 
    group by t1.table1id,t2.field3) a 
    ON a.table1id = t1.table1id 

希望這種方法可以幫助你解決這個問題。