2014-09-11 2 views
2

결과적으로 행 수와 숫자를 반환해야하는 쿼리에는 문제가 있습니다. 요점은 최근 24 시간 동안의 데이터를 1 시간으로 나눈 값이 필요하다는 것입니다. UNION ALL을 24 번 사용하여이 쿼리를 수행했지만 SQL 쿼리 하나가 800 줄 이상 (놀랍게도 3 초만 소요됨)이 있습니다. 어떻게 든 시간을두고 그룹으로 묶을 수는 있지만 그 일을 올바르게 수행하는 방법은 모릅니다. 동등한 쿼리가 단지 약 20-30 줄의 SQL에있을 수 있다고 강력히 믿습니다. 나는 모든 단서를 고맙게 생각합니다. 여기에 제가 언급 한 것들에 대한 간단한 쿼리가 있습니다.시간별 카운트 그룹화 (from-to)

긴 쿼리 (사용 UNION ALL) : 간단한 쿼리 (이 같은 생각에 의해 반환

Time | CountT1 | CountT2 | CountT3 

21:05 | 3215467 | 3456364 | 3234234 

20:05 | 2253221 | 3123123 | 3238291 

19:05 | 1231467 | 1232342 | 1123123 

18:05 | 3112412 | 6712353 | 1233124 

17:05 | 1242141 | 1241142 | 4112426 

16:05 | 3123467 | 3456364 | 3234234 

15:05 | 3215467 | 3412334 | 3231234 

14:05 | 3324467 | 3456123 | 2312334 

13:05 | 3215467 | 3456364 | 1112310 

12:05 | 3215467 | 3456364 | 1231234 

11:05 | 3123127 | 3456364 | 3234234 

10:05 | 3215467 | 3456364 | 3234234 

09:05 | 3215467 | 3456364 | 3234234 

08:05 | 3215467 | 3456364 | 3234234 

07:05 | 3215467 | 3456364 | 3234234 

06:05 | 3215467 | 3456364 | 3234234 

05:05 | 3215467 | 2212214 | 3234234 

04:05 | 3215467 | 3126542 | 3234234 

03:05 | 3215467 | 3123364 | 3234234 

02:05 | 3215467 | 3456364 | 3234234 

01:05 | 3215467 | 3456364 | 3234234 

00:05 | 3215467 | 3456364 | 3123123 

23:05 | 3215467 | 3456364 | 3212313 

22:05 | 3223424 | 1232163 | 1235321 

내가 같은 결과가 필요합니다 : 그 질문은 나에게 그런 일을 제공

DECLARE @CurrentTime datetime = GETDATE(); 

--Data from 1 hour 
SELECT 
----Time 
(SELECT CONVERT(VARCHAR(5), (DATEADD(HOUR, -1, @CurrentTime)), 114)) AS [Time], 

----Count on 1st table 
(SELECT COUNT(T1.[TableFirstId]) 
FROM [dbo].[Table1] AS T1 
WHERE T1.[IncomingDate] BETWEEN (DATEADD(HOUR, -1, @CurrentTime)) AND @CurrentTime) AS [CountT1], 
----Count on 2nd table 
(SELECT COUNT(T2.[TableSecondId]) 
FROM [dbo].[Table2] AS T2 
WHERE T2.[IncomingDate] BETWEEN (DATEADD(HOUR, -1, @CurrentTime)) AND @CurrentTime) AS [CountT2], 
----Count on 3rd table 
(SELECT COUNT(T3.[TableThirdId]) 
FROM [dbo].[Table3] AS T3 
WHERE T3.[IncomingDate] BETWEEN (DATEADD(HOUR, -1, @CurrentTime)) AND @CurrentTime) AS [CountT3] 

UNION ALL 

--Data from 2 hours 
SELECT 
----Time 
(SELECT CONVERT(VARCHAR(5), (DATEADD(HOUR, -2, @CurrentTime)), 114)) AS [Time], 

----Count on 1st table 
(SELECT COUNT(T1.[TableFirstId]) 
FROM [dbo].[Table1] AS T1 
WHERE T1.[IncomingDate] BETWEEN (DATEADD(HOUR, -2, @CurrentTime)) AND (DATEADD(HOUR, -1, @CurrentTime))) AS [CountT1], 
----Count on 2nd table 
(SELECT COUNT(T2.[TableSecondId]) 
FROM [dbo].[Table2] AS T2 
WHERE T2.[IncomingDate] BETWEEN (DATEADD(HOUR, -2, @CurrentTime)) AND (DATEADD(HOUR, -1, @CurrentTime))) AS [CountT2], 
----Count on 3rd table 
(SELECT COUNT(T3.[TableThirdId]) 
FROM [dbo].[Table3] AS T3 
WHERE T3.[IncomingDate] BETWEEN (DATEADD(HOUR, -2, @CurrentTime)) AND (DATEADD(HOUR, -1, @CurrentTime))) AS [CountT3] 

UNION ALL 

--Data from 3 hours 
SELECT 
----Time 
(SELECT CONVERT(VARCHAR(5), (DATEADD(HOUR, -3, @CurrentTime)), 114)) AS [Time], 

----Count on 1st table 
(SELECT COUNT(T1.[TableFirstId]) 
FROM [dbo].[Table1] AS T1 
WHERE T1.[IncomingDate] BETWEEN (DATEADD(HOUR, -3, @CurrentTime)) AND (DATEADD(HOUR, -2, @CurrentTime))) AS [CountT1], 
----Count on 2nd table 
(SELECT COUNT(T2.[TableSecondId]) 
FROM [dbo].[Table2] AS T2 
WHERE T2.[IncomingDate] BETWEEN (DATEADD(HOUR, -3, @CurrentTime)) AND (DATEADD(HOUR, -2, @CurrentTime))) AS [CountT2], 
----Count on 3rd table 
(SELECT COUNT(T3.[TableThirdId]) 
FROM [dbo].[Table3] AS T3 
WHERE T3.[IncomingDate] BETWEEN (DATEADD(HOUR, -3, @CurrentTime)) AND (DATEADD(HOUR, -2, @CurrentTime))) AS [CountT3] 

UNION ALL 

--(etc...) 

) :

DECLARE @CurrentTime datetime = GETDATE(); 

--Data from 24 hours 
SELECT 

----Count on 1st table 
(SELECT COUNT(T1.[TableFirstId]) 
FROM [dbo].[Table1] AS T1 
WHERE T1.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT1], 
----Count on 2nd table 
(SELECT COUNT(T2.[TableSecondId]) 
FROM [dbo].[Table2] AS T2 
WHERE T2.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT2], 
----Count on 3rd table 
(SELECT COUNT(T3.[TableThirdId]) 
FROM [dbo].[Table3] AS T3 
WHERE T3.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT3] 

FROM [dbo].[Table1] AS T1 
GROUP BY DATEPART(HOUR, T1.[IncomingDate]) 

그러나 예상대로 작동하지 않습니다. 저를 이해하도록 도와 줄 사람이 있습니까? 내 문제를 해결 하시겠습니까?

+1

테스트 할 테이블이 없습니다. 어떻게 다르게 작동하는지 말할 수 있습니까? 1 행을 반환합니까? – Kuzgun

+0

마지막 쿼리는 동일한 중복 된 행 24 개를 반환합니다 (24 시간의 계산 된 숫자 만). – JakubM

답변

1

이 솔루션은 IncomingDate를 필요한 시간당 증가분으로 잘라 내고 그 값에 대해 하위 쿼리를 결합하는 방식으로 이루어집니다. 귀하의 요구 사항을 약간 수정하고 있으며 시간 단위로 모든 시간 단위가 정확하게 시작되도록 요구합니다. 이는이 방식이 쿼리를 크게 단순화하기 때문입니다. 내가 그렇게 할 수있는 다른 방법이 있습니다

CONVERT(VARCHAR(13), IncomingDate, 120) 

사용하여 잘라 내기 (here을 강조)하지만 우리는 그 값에 거 그룹이라면이 하나 더 좋은 생각처럼 보인다.

SELECT COUNT(*) AS T1Count, 
CONVERT(VARCHAR(13), IncomingDate, 120) AS IncomingDate 
FROM Table1 
GROUP BY CONVERT(VARCHAR(13), IncomingDate, 120) 

을 그리고 지금 우리가해야 할 일은 3 개 테이블 반복하고, 다음 FULL OUTER은 T1.IncomingDate에 가입 ​​: 하나 개의 테이블에 대한 시간당 행 개수를 얻으려면, 우리는 쿼리를 다음과 같이 있습니다. 결과는 다음과 같습니다 :이 쿼리는 모든 데이터에 대한 것입니다

  • 것을

    SELECT T1.IncomingDate, t1.T1Count, t2.T2Count, t3.T3Count FROM 
        (SELECT COUNT(*) AS T1Count, 
        CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate 
        from Table1 
        group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T1 
    FULL OUTER JOIN (SELECT COUNT(*) AS T2Count, 
           CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate 
           from Table2 
           group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T2 
        ON T1.IncomingDate = T2.IncomingDate 
    FULL OUTER JOIN (SELECT COUNT(*) AS T3Count, 
           CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate 
           from Table3 
           group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T3 
        ON T1.IncomingDate = T3.IncomingDate 
    order by T1.IncomingDate 
    

    주, 당신의 서버가 처리 할 수 ​​있기를 바랍니다. WHERE 절을 사용하여 쉽게 다듬을 수 있습니다.

  • 테스트 데이터가 많지 않은데도 내 로컬 컴퓨터에서 3 방향 완전 외부 조인을 테스트 할 수 없었습니다.이 테스트 데이터는 나 자신을 만들기에는 너무 게을 렀습니다. 그렇지 않은 경우보다 나은 3 방향 외부 조인을 위해 this answer을 사용할 수 있습니다.
+0

네, 맞습니다. 이것은 간단한 SELECT 쿼리를 시간 단위로 그룹화하는 방법입니다. 내부 서브 쿼리를 그룹화 할 필요가 있습니다. 서브 쿼리에서는 하위 쿼리가 하나의 열만 반환해야하고 GROUP BY는 다른 서브 루틴을 필요로하기 때문에 하위 쿼리에서는 금지되어 있습니다. 그래서 내가 옳은 경우 하위 쿼리에서는 불가능합니다. – JakubM

+0

@JakubM 귀하의 요구 사항을 더 잘 이해하고 있다고 생각합니다. 나는 그 해답을 완전히 정비했다. 작동하는지 알려주세요. –

+0

귀하의 헌신에 감사드립니다. 솔직히 말해서 나는 내 문제에 대한 해결책을 찾았지만 아마 최선의 방법은 아닙니다. 임시 테이블을 기반으로하는 쿼리를 만들었습니다 (그 안에 GROUP BY를 사용할 수있었습니다). 제 설계자는 쿼리를 약간 개선해야한다고 말했기 때문에 제안을 분석해야합니다. 지금 나는 테스트 DB (너무 많은 레코드가 없습니다)에서 일하고 있지만, 나는 그 쿼리가 프로드 DB에서 어떻게 돌아갈 지 모른다. 나는 확실히 당신의 질문을 점검 할 것이지만 나는 약간의 시간이 필요하다. 한 번 더 고마워. 거기에 다른 사람들을 위해 작성한 쿼리를 붙여 넣을 것입니다. – JakubM

1

이 쿼리는 SQL이 적은 쿼리와 동일한 결과를 제공합니다.

DECLARE @HourTbl TABLE (HourBegin DATETIME, HourEnd DATETIME) 
DECLARE @i INT=0 
DECLARE @dtBegin datetime 
DECLARE @dtEnd datetime = GETDATE() 

WHILE @i < 24 
BEGIN 
    SET @i = (@i + 1) 
    SET @dtBegin = @dtEnd 
    SET @dtEnd = DATEADD(HOUR, [email protected], @dtBegin) 
    INSERT INTO @HourTbl 
    SELECT @dtBegin, @dtEnd 
END 

;with hourVal ( hourBegin , hourEnd) 
as 
(

select hourBegin, hourend 
from @HourTbl 
) 
select CONVERT(VARCHAR(5), hourVal.hourBegin, 114), 
(
select COUNT(T1.[TableFirstId]) 
from Table1 
where T1.[IncomingDate] BETWEEN hourVal.hourBegin, hourVal.hourEnd 
), 
(
select COUNT(T1.[TableFirstId]) 
from Table2 
where T1.[IncomingDate] BETWEEN hourVal.hourBegin, hourVal.hourEnd 
) 
관련 문제