0

データベースをチェックして、顧客が 1 日に複数回訪問したかどうかを確認するクエリがあります。持っている場合は、訪問回数をカウントし、何回訪問したかを教えてくれます。問題は、「Tickets.lcustomerid」が group by 句にスローされ、5 つのレコード (バーコードのない顧客) が失われることです。以下のクエリを変更して、group by 句から「tickets.lcustomerid」を削除する方法groupby 句。

動作するクエリ:

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
4

2 に答える 2

1

あなたのデータモデルやこのクエリで何を達成しようとしているのか理解していないため、問題を直接解決することはできません。ただし、問題を自分で解決する方法についてアドバイスを提供することはできます。

まず、何を達成しようとしているのか、テーブルがどのように組み合わされているのかを正確に理解していますか?もしそうなら、次のステップに進んでください。そうでなければ、最初にこの知識を取得してください。この理解なしに複雑なクエリを実行することはできません。

次に、達成しようとしていることを少しずつ分割し、残りの部分に移動する前に、それぞれがカバーされていることを確認します。したがって、あなたの場合、あなたは何人かの顧客を逃しているようです。新しいクエリから始めます(これには複数の問題があると確信しています)。したがって、join句とwhere句から始めます。

顧客から始めて、チケットに左結合する必要があるのではないかと思います(これにより、チケットの場合と同じように、左の条件が結合する場所が移動します)。これにより、チケットを持っているかどうかに関係なく、すべての顧客を獲得できます。それが目的ではない場合は、必要な顧客レコードの正確なセットが返されるまで、jonとwhereクラスで作業します(そして、物事を理解しようとしている間はselect *を使用します)。この段階でselect*を使用する理由は、データの何が問題の原因になっているのかを確認するためです。それはあなたに修正する方法を教えてくれるかもしれません。

通常、私は結合から始めて、正しい最初のレコードのセットを取得していることがわかるまで、一度に1つずつクラスを追加します。複数の結合がある場合は、一度に1つずつ実行して、突然開始したレコードのレコード数が予想よりも多いか少ないかを確認します。

次に、より複雑な部分に進みます。それぞれを一度に1つずつ追加し、結果を確認します。突然10レコードから5または15に移行した場合は、おそらく問題が発生しています。一度に1ステップずつ作業して問題が発生すると、問題の原因が正確にわかり、検索と修正がはるかに簡単になります。

Group BYは、完全に理解することが重要です。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

このアプローチがこの問題の解決に役立つことを願っています。

于 2013-02-07T15:44:51.217 に答える
1

更新: 私たちの「チャット」に基づくと、顧客 ID が主キーであっても、顧客 ID は一意のフィールドではなくバーコードであるようです。

したがって、サブクエリで GROUP BY 顧客 ID を使用しないようにするには、バーコードで実際に結合するために、そこにある 2 番目の顧客テーブルに結合する必要があります。

これを試して:

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 
于 2013-02-07T15:20:59.853 に答える