2012-03-09 3 views
0

모든 특정 사용자 이벤트를 검색 할 데이터베이스에 대한 SQL 쿼리를 작성하려고합니다. 반복적으로 표시되면 시작일로부터 52 주 동안 매주 게재되기를 바랍니다. 이 작업을 수행하는 더 좋은 방법이 있습니까? 현재 사용중인 코드가 꽤 복잡해 보입니다. 여기 단일 SQL 쿼리 오류

event (
    event_id INT NOT NULL AUTO_INCREMENT, (PK) 
    title VARCHAR(80) NOT NULL, 
    description VARCHAR(200), 
    event_start DATETIME, 
    event_end DATETIME, 
    group_id INT NOT NULL, 
    recurring BOOLEAN 
); 

    Users{ 
    UserID (PK) 
    Username 
    } 

    Groups{ 
    GroupID (PK) 
    GroupName 
    } 

    Membership{ 
    UserID (FK) 
    GroupID (FK) 
    } 

내가 지금 가지고있는 쿼리, 그것은 현재 작동하지 않습니다, 누군가가 나를 도와주세요 수있다 : 다음과 같이

내 테이블이 구성되어?

var result = db.Query(
      @"SELECT e.event_id, e.title, e.description, e.event_start, e.event_end, e.group_id, e.recurring 
      FROM event e 
      JOIN Membership m ON m.GroupID = e.group_id 
      WHERE e.recurring 
      AND m.UserID = ? 
      AND e.event_start >= ? 
      AND e.event_end <= ? 
      UNION ALL 
      SELECT e.event_id, e.title, e.description, DATEADD(week, w.weeks, e.event_start), 
        DATEADD(week, w.weeks, e.event_end), e.group_id, e.recurring 
      FROM event e 
      JOIN Membership m ON m.GroupID = e.group_id, 
      (SELECT row_number() OVER (ORDER BY Object_ID) AS weeks 
        FROM SYS.OBJECTS) AS w 
      WHERE NOT e.recurring 
      AND m.user_id = ? 
      AND e.event_start >= ? 
      AND e.event_end <= ?", username, start, end, username, start, end 
     ); 

사람은 반복이 아닌 모든 이벤트를 선택하도록 내 코드를 적응 도와 드릴까요과 52 주 동안 같은 시간에 반복 일정을 선택?

+0

부수적으로 1 년에 52 주를 기억하지 마십시오. –

+0

52.177457 주! 그래도 쉽게 내릴 수 있습니다. :) –

+1

나는 현재의 해가 52 주를 갖지 않을 때마다 눈먼 공황 상태에서 또 다른 추악한 해킹을 얻는 시스템을 보았습니다. –

답변

1

는 다음과 같이 수 :

SELECT e.event_id, e.title, e.description, e.start_time, e.end_time 
    , e.group_id, e.recurring 
FROM Events e 
JOIN Membership m ON m.groupid = e.group_id 
WHERE e.recurring = 0 
AND m.user_id = ? 
AND e.start_time >= ? 
AND e.end_time <= ? 

UNION ALL 
SELECT e.event_ID, e.title, e.description 
     ,DATEADD(week, w.weeks, e.start_time) -- AS event_start 
     ,DATEADD(week, w.weeks, e.end_time) -- AS event_end 
     ,e.group_id, e.recurring 
FROM Events e 
JOIN Membership m ON m.groupid = e.group_id 
     ,(SELECT row_number() OVER (ORDER BY Object_ID) AS weeks 
     FROM SYS.OBJECTS) AS w 
WHERE e.recurring = 1 
AND m.user_id = ? 
AND e.start_time >= ? 
AND e.end_time <= ? 
  • 사용 UNION ALL 대신 UNION을.

  • event_startevent_end 대신 start_timeend_time (??)으로 변경했습니다. user_id 테이블 Membership에, 그래서 당신은 WHERE 절에 사용하려는 경우이 점에서 JOIN 필요 :

  • 는 나도 처음에는 것을 놓쳤다. 외래 키 열은 group_id/groupid 인 것 같습니다. (맞춤법을 통일했습니다!)

  • 검색어의 첫 번째 부분에 SELECT *이있었습니다. 그러한 쿼리에서 열 이름을 쓰는 것이 낫습니다. 또는 나중에 기본 테이블을 변경하면 놀라운 결과가 발생할 수 있습니다.

  • 초안에 보조 기능 generate_series()을 사용하여 here에서 1-52의 숫자를 생성했지만 원본 솔루션이 더 좋으므로이 변경 사항을 되 돌리십시오.

+0

이 코드를 통합하려면 어디에서 generate_series 함수를 추가해야합니까? 응답에 대한 많은 감사의 말을 전합니다. 보조 기능을 보여 주면 머리 위로 약간 돌아갔습니다! :) –

+0

@SimonKiely : 죄송합니다. 보조 기능이 실제로 필요하지 않습니다. 귀하의 origninal 솔루션은 간단합니다. 나는 그 변화를 되돌 렸습니다. –

+0

Brandstetter, 안녕하세요.이 코드를 내 시스템에 통합하고 오류가 발생했습니다. "쿼리를 구문 분석하는 동안 오류가 발생했습니다. 토큰 줄 번호 = 4, 토큰 줄 오프셋 = 13, 토큰 오류 = AND] " –

1

시도해보십시오. SQL에서 event_start 및 event_stop을 사용했지만 이벤트 테이블에 정의되지 않았습니다. 당신이 섞은 유일한 것은 start_time < = @CurrentTime AND end_time> = @CurrentTime이었습니다. 나는 당신의 코드가 clunky하다고 생각하지 않는다. UNION ALL은 UNION보다 성능이 뛰어납니다 (UNION은 DISTINCT와 같이 작동 : 첫 번째 ORDER BY는 중복을 제거합니다).

DROP TABLE #Events 
CREATE TABLE #Events (
    event_id INT NOT NULL, 
    title VARCHAR(80) NOT NULL, 
    description VARCHAR(200), 
    start_time DATETIME, 
    end_time DATETIME, 
    group_id INT NOT NULL, 
    recurring bit 
); 

INSERT INTO #Events(event_id, title, description, start_time, end_time, group_id, recurring) VALUES 
(1, 'meeting1', 'meeting1', '20000101', '20000102', 1, 0), 
(2, 'meeting2', 'meeting2', '20120309', '20120310', 1, 0), 
(3, 'meeting3', 'meeting3', '20120311', '20120312', 1, 0), 
(10, 'meeting10', 'meeting10', '20000101', '20000102', 1, 1), 
(20, 'meeting20', 'meeting20', '20120309', '20120310', 1, 1), 
(30, 'meeting30', 'meeting30', '20120311', '20120312', 1, 1) 

DECLARE @CurrentTime DATETIME 
SET @CurrentTime = GETDATE() 

SELECT event_id, 
    title, 
    description, 
    start_time, 
    end_time, 
    group_id, 
    recurring 
FROM #Events 
WHERE recurring = 0 AND 
-- user_id = ? AND 
    start_time <= @CurrentTime AND 
    end_time >= @CurrentTime 

UNION ALL 

SELECT event_ID, 
    title, 
    description, 
    DATEADD(WEEK, Interval, start_time) [event_start], 
    DATEADD(WEEK, Interval, end_time) [event_end], 
    group_id, 
    recurring 
FROM #Events, 
    (SELECT ROW_NUMBER() OVER(ORDER BY Object_ID) [Interval] 
    FROM SYS.OBJECTS) as T 
WHERE recurring = 1 AND 
    Interval <= 52 AND 
-- user_id = ? AND 
    start_time <= @CurrentTime AND 
    end_time >= @CurrentTime 
; 
+0

안녕하세요, 답변 해 주셔서 감사합니다. 그것은 매우 도움이됩니다. 내가 지금 당면하는 문제는 user_id 열이 멤버십 테이블에 포함되어 있다는 것입니다. group_id에 user_id가 들어있는 사용자와 관련된 이벤트 만 검색하고 싶습니다. 따라서 멤버십 테이블에 group_id와 여러 user_id가 포함되어 특정 그룹의 구성원 인 모든 사용자를 표시합니다. group_id가 이벤트에 사용되면이 사용자 중 하나의 이벤트 만 검색하려고합니다. –

+0

> group_id가 이벤트에서 사용되면이 사용자 중 하나의 이벤트 만 검색합니다. Wim