2013-02-07 2 views
0

고객이 하루에 여러 번 방문했는지 확인하기 위해 데이터베이스를 검사하는 쿼리가 있습니다. 그들이 가지고있는 경우 방문 횟수를 계산 한 다음 그들이 방문한 시간을 알려줍니다. 문제는 "Tickets.lcustomerid"를 group by 절에 던져서 5 개의 레코드 (바코드가없는 Customers)를 놓친다는 것입니다. 그룹 by 절에서 "tickets.lcustomerid"를 제거하기 위해 아래의 쿼리를 어떻게 바꿀 수 있습니까? 제거하면 집계의 일부가 아니기 때문에 "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 
+1

길이가없는 'BETWEEN'과'VARCHAR' ...

+1

나는 customers.sbarcode를 그룹화하고 그 열의 수를 얻는 것이 흥미 롭다고 생각합니다. 당신이 별개의 것을 얻지 못하기 때문에 그것이 작동한다고 확신합니다.하지만이 카운트가 하나 이상이되기 위해서는 여러 카운트를 생성하는 다른 컬럼이 있어야합니다. 이 열을 카운트에 사용하면 가독성 측면에서 더 나을 것입니다. 어떤 테이블에 다른 테이블의 레코드에 참여하지 않는 레코드가 포함되어 있는지 설명 할 수 있습니까? 일치하는 [고객] 레코드가없는 다섯 개의 [티켓] 레코드가 있습니까? 솔루션은 아마도 왼쪽 조인이 될 것입니다. –

+0

그들은 5 티켓 레코드이며 일치하는 고객 레코드가 있습니다. 하위 쿼리없이 쿼리를 실행하면 결과가 나옵니다. 누락 된 결과는 바코드가없는 5입니다. 나는 작동하는 쿼리와 출력을 게시 할 것이다. – Shmewnix

답변

1

업데이트 : 고객 ID가 기본 키이지만 고객 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

키가 null이거나 모든 티켓에 대해 고객의 레코드가 없기 때문에 데이터가 "삭제"됩니다. 반대의 경우도 마찬가지입니다. ...이 테이블에 어떤 데이터가 있는지 모르기 때문에 조인에 도움이되지 않습니다. 당신은 바코드가 없기 때문에 그것이라고하지만 바코드, 기본 키 등이 무엇인지 모르겠습니다. –

+0

위의 정보를 참조하십시오, 당신에게 충분히 구체적입니까? 아니면 더 많은 정보가 필요합니까? – Shmewnix

1

내가 직접 문제를 해결할 수 있습니다. 그러나 문제를 스스로 해결하는 방법에 대한 조언을 드릴 수 있습니다.

먼저 무엇을 달성하려고하는지 정확히 어떻게 이해하고 있습니까? 다음 단계로 넘어갈 수 없다면, 먼저이 지식을 얻으십시오. 이러한 이해 없이는 복잡한 쿼리를 수행 할 수 없습니다.

다음 단계는 작은 단계로 수행하려는 작업을 해체하고 나머지 작업을 수행하기 전에 각 작업을 완료했는지 확인하십시오. 그래서 당신의 경우에 당신은 몇몇 고객을 놓치고있는 것처럼 보입니다. 새로운 쿼리로 시작하십시오. (저는 이것이 하나 이상의 문제를 가지고 있음을 확신합니다). 그래서 join과 where 절로 시작하자.

고객과 함께 시작하고 티켓에 왼쪽 가입을해야 할 수도 있습니다 (티켓에있는 그대로 왼쪽 조인으로 이동하는 경우). 티켓이 있는지 여부에 관계없이 모든 고객에게 제공됩니다. 그것이 원하는 것이 아닌 경우, 필요한 고객 레코드의 정확한 세트를 반환 할 때까지 jon 및 where clasues와 작업하십시오 (그리고 사태를 파악하는 동안 select *를 사용하십시오). 이 단계에서 select *를 사용하는 이유는 데이터에서 여러분이 겪고있는 문제의 원인이 무엇인지를 보는 것입니다. 수정하는 방법을 알려줄 수 있습니다.

보통 나는 처음부터 레코드 집합을 얻고 있다는 것을 알기 전까지 한 번에 하나씩 어디서 clasues를 추가할까요? 여러 개의 조인이있는 경우 갑자기 시작될 때 알 수 있도록 한 번에 하나씩 수행하여 예상보다 많은 레코드를 확보하십시오.

그런 다음 더 복잡한 부분으로 이동하십시오. 한 번에 하나씩 각 항목을 추가하고 결과를 확인하십시오. 갑자기 10 레코드에서 5 또는 15로 이동하면 문제가 발생한 것입니다.한 번에 한 걸음 씩 작업하고 문제가 생길 때 문제의 원인을 정확히 알면 찾기 쉽고 수정하기가 더 쉽습니다.

그룹 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 

이 방법을 사용하면이 문제를 쉽게 해결할 수 있습니다.