2012-03-12 2 views
0

이번이 처음입니다. 이런 식으로하려고합니다. 그래서 나와 함께하시기 바랍니다. 이것은 MySql에 있습니다.MySql - 열을 행으로 변환하여 보고서를 생성하는 SQL 쿼리 또는 프로 시저

어떤 학생들이 어떤 주제와 날짜를 완료했는지보고하기 위해 보고서를 작성하려고합니다.

이것은 내가

 
select u.email,t.topic_name,tu.date_created as 'date completed' 
from topic_user tu 
join topic t ON tu.topic_id = t.topic_id 
join user u ON tu.user_id = u.user_id 

 
email   | topic_name  | date completed 
[email protected] | ABC    | 03/01/2012 
[email protected] | DEF    | 03/02/2012 
[email protected] | ABC    | 03/08/2012 
[email protected] | GHI    | 03/08/2012 
[email protected] | ABC    | 03/02/2012 
[email protected] | XYZ    | 03/10/2012 

내가 보고서를 생성 할 방법과 같은 결과를 반환하는 실행 현재 쿼리 열 머리글 및 날짜 등의 항목 이름이된다 값으로 완료했습니다.

 
email   | ABC  | DEF  | GHI  | JKL  | XYZ  
[email protected] | 03/08/2012 | 03/02/2012 | 03/08/2012 | null  | null 
[email protected] | 03/02/2012 | null  | null  | null  | 03/10/2012 

주의 사항 :

1) 모든 항목 이름은 주제 테이블에서 올 것 - 그들은 학생들이 완료되지 않은 경우에도 - 그 - 값이 나타납니다 [email protected] 학생의 경우;로서 null

2) 주제 ABC를 두 번 연구했지만 보고서는 최신 날짜를 받아야합니다.

이 작업을 수행하려면 저장 프로 시저를 작성해야합니다. 어쩌면 먼저 주제 테이블에서 모든 주제 이름을 가져온 다음 임시보기를 작성하여 채 웁니다.

제공 할 수있는 도움에 감사드립니다. 감사합니다.

+0

주제 이름이 고정되어 있습니까? 그들은 SQL 안에 하드 코드 될 수 있을까? 이메일 당 주제 이름 당 date_completed가 하나만 있다는 보장이 있습니까? –

+0

예 코스가 작성되면 주제 테이블에 이름이 채워진다는 의미에서 주제 이름이 고정됩니다. 필요한 경우 새로운 주제가 추가됩니다.아니요. 언급 한대로 동일한 학생이 동일한 주제를 여러 번 공부할 수 있지만 보고서에는 마지막 날짜가 표시되어야합니다. [email protected] 학생을 보시면 ABC라는 주제를 두 번이나 끝 냈지만 보고서에는 마지막 날짜가 표시됩니다. 감사합니다 – Gublooo

답변

2

나는이 테스트하지했습니다, 그리고 내 경험 MySQL은 제한적이지만 아래 내용이 당신이 원하는 바입니다. GROUP_CONCAT 함수를 사용하여 동적으로 SELECT 문을 만든 다음 실행합니다 (이것은 MySQL에서 수행 할 수있는 방법이 아닙니다.). 주제에 매우 정기적으로 변경하지 않으면 물론

SET @SQL = (
SELECT CONCAT('SELECT Email,', GROUP_CONCAT(SelectText), ' FROM Topic_User tu INNER JOIN Users u ON u.User_ID = tu.User_ID GROUP BY Email') 
FROM ( SELECT CONCAT(' MAX(CASE WHEN Topic_ID = ', Topic_ID, ' THEN tu.Date_Created END) AS `', Topic_Name, '`') AS SelectText 
      FROM Topic 
     ) AS d); 

PREPARE stmt FROM @SQL; 
EXECUTE stmt 

당신은 그냥 사용할 수 있습니다

SELECT Email, 
     MAX(CASE WHEN Topic_ID = 1 THEN tu.Date_Created END) AS ABC, 
     MAX(CASE WHEN Topic_ID = 2 THEN tu.Date_Created END) AS DEF, 
     MAX(CASE WHEN Topic_ID = 3 THEN tu.Date_Created END) AS GHI, 
     MAX(CASE WHEN Topic_ID = 4 THEN tu.Date_Created END) AS JKL, 
     MAX(CASE WHEN Topic_ID = 5 THEN tu.Date_Created END) AS XYZ 
FROM Topic_User tu 
     INNER JOIN users u 
      ON u.User_ID = tu.User_ID 
GROUP BY Email 

을하고 쿼리에 새로운 항목이 추가 될 때마다 변경 (이것은 위의 방법에 의해 제조 된 쿼리입니다).

+0

좋은 해결책. MySQL 5.0 이상인 경우에는 정상적으로 작동해야합니다. – nnichols

+0

고맙습니다. - 주제가 정기적으로 변하지 않을 때를위한 솔루션이 마음에 들지만, 데이터베이스에는 약 90 가지의 이상한 주제가 있으며 모든 사례를 추가해야합니다. . 동적으로 생성하는 첫 번째 솔루션은 이상적 이었지만 작동하지 못했습니다. 오류가 발생했습니다. "SQL 구문에 오류가있어서 MySQL 서버 버전에 해당하는 설명서를 확인하십시오. 가장 가까운 문법을 사용하여 'Banking, MAX (CASE WHEN topic_id = 3 THEN tu.date_created END)'와 같은 줄을 사용합니다. " – Gublooo

+0

공백이있는'topic_name'을 사용하면됩니다. 이 문제를 해결하기 위해 솔루션을 편집했습니다. 그렇지 않으면 실행하기 전에 @SQL을 선택하십시오. 생성 된 쿼리가 표시되며 오류가 발생한 위치를 식별하는 데 도움이됩니다. – GarethD

1

동적으로 생성 된 크로스 탭 쿼리를 사용하여이 작업을 수행 할 수 있습니다.

SELECT 
    u.email, 
    MAX(IF(t.topic_name = 'ABC', tu.date_created, NULL)) AS 'ABC', 
    MAX(IF(t.topic_name = 'DEF', tu.date_created, NULL)) AS 'DEF', 
    etc 
FROM topic_user tu 
INNER JOIN topic t 
    ON tu.topic_id = t.topic_id 
INNER JOIN user u 
    ON tu.user_id = u.user_id 
GROUP BY u.user_id; 

그래서, 당신은 동적으로 항목 목록에 대한 첫 번째 질의에 따라 필드 목록을 구축 할 것입니다 선택의 서버 측 언어 - 당신이 결국하고 싶은 쿼리는 다음과 같은 것입니다.

당신은이 주제 테이블에 가입 드롭 할 수 있도록 약간 대신 topic_names의 topic_ids를 사용하여이 쿼리의 오버 헤드를 줄일 수 -

SELECT 
    u.email, 
    MAX(IF(tu.topic_id = 1, tu.date_created, NULL)) AS 'ABC', 
    MAX(IF(tu.topic_id = 2, tu.date_created, NULL)) AS 'DEF', 
    etc 
FROM topic_user tu 
INNER JOIN user u 
    ON tu.user_id = u.user_id 
GROUP BY u.user_id; 
+0

고마워요 nichols - 쿼리에 90 이상한 주제 이름을 나열하는 것을 피하는 방법이 있는지 그리고 어쨌든 주제 테이블에서 동적으로 가져 오는 것이 있다면 – Gublooo

+0

@ Gublooo의 준비된 구문이있는 메소드가 확실히 좋습니다. – nnichols