2009-03-24 12 views
3

필자는 작성해야 할 반쯤 복잡한 저장 프로 시저가 있습니다. 나는 정확히 DBA가 아니지만 우리 회사의 다른 누구도 내가 가진 것보다 낫지 않습니다. 기본 아이디어는 작업 그룹이 있다는 것입니다. 사용자는 이러한 작업을 완료하고 완료된 각 작업에 대한 플래그를 얻습니다. "완료"로 간주 되려면 사용자는 주어진 작업 그룹 전체를 완료해야합니다. 린치 핀 (lynch pin)은 다른 태스크 그룹을위한 래퍼 태스크 중 일부입니다.복잡한 MySQL 저장 프로 시저

예를 들어, 우리는 다음과 같은 가능한 작업있다 : 그들은 작업 3 완료되면

Task 1 
Task 2 
Task 3 
Task 4 -> (1, 2, 3) 
Task 5 -> (1, 2) 
Task 6 
Task 7 -> (5, 6) 
사용자가 작업 1을 완료하면

2, 그들은 암묵적으로 작업 5. 완료를, 그들은 암묵적으로 완료 한 것 작업 4.

다른 사용자의 마무리 작업이 1, 2, 6, 그들이 암묵적으로 완료 한 경우 1, 2, 5, 6, 7 역에서

, 할당은 작업 7 필요한 경우, 그것은 것 1과 2가 필요한 작업 6과 5가 필요합니다.

저는 5 개의 기본 테이블 userCompletedTask, assignmentRequiredTask, compoundTask, userTaskAssignment 및 task가 있습니다. 나는 사용자와 할당 테이블을 불필요하게 생략했다.

userCompletedTask: 
userID (Foreign Key on user) 
taskID (Foreign Key on task) 

usertTaskAssignment: 
userID (Foreign key on user) 
assignmentID (Foreign key on assignment) 

assignmentRequiredTask: 
assignmentID (Foreign key on assignment) 
taskID (Foreign key on task) 

task: 
taskID (primary key) 
compound (boolean flag. If 1, it is compound) 

compoundTask: 
parentID (foreign key on task) 
childID (foreign key on task) 

사용자에게 작업 4가 완료되어야하는 userTaskAssignment가 할당됩니다. 적절한 compoundTasks가 있는지 확인하기 위해 assignCompletedTasks를 assignRequiredTasks에 대해 확인하는 저장 프로 시저를 작성하려고합니다.

의사 코드는이를 좋아하는 것 : 난 그냥 저장 proceedure에이 번역 충분히 MySQL은/​​SQL의 내부를 모르는

collection tasksCompleted = user->getTasksCompleted 
collection tasksRequired = new collection 

foreach task in assignment->getRequiredTasks 
    if(task.isCompound) 
     tasksRequired->addAll(getCompountTasks(task)) 
    else 
     tasksRequired->add(task) 

if tasksCompleted->containsAll(tasksRequired) 
    return true 
else 
    return false 

. 최후의 수단은 응용 프로그램에 코드를 가져 오는 것이지만 이것은 데이터 수준에 맞을 것입니다. 어떤 도움이라도 대단히 감사하겠습니다.

편집

으로 아래 지적했다 compoundTask 항목 자체는 화합물 작업이 될 수 있습니다. 따라서 완료해야 할 모든 비 복합 작업 목록을 얻으려면 재귀 적 연습이 필요합니다. 나는 이것을 예시로 위의 예를 확장했다.

답변

1

실제로 compoundTask 테이블이 task 테이블을 복제하고 있습니다. 단순히 nullable parent_id 열을 작업 테이블에 추가하면 동일한 테이블에서 동일한 결과를 얻을 수 있습니다. 이 여기 간다

,이 검증되지 않은 어쩌면조차 유효한 MySQL은,하지만 당신이 시작할 수 있어야합니다 taskID의이에서 반환 된 무엇이든

SELECT DISTINCT taskID FROM task AS t LEFT JOIN compoundTask AS ct ON ct.taskID = t.taskID 
INNER JOIN userCompletedTask AS uct ON uct.taskID = t.taskID 
INNER JOIN userCompletedTask AS uctCompound ON uctCompound.taskID = ct.taskID 
WHERE uct.userID = @user AND uctCompound.userID = @user 

지정된 @user 완료된다.

MySQL을 마친 이후로 오랜 시간이 걸렸습니다. 따라서 작동하지 않을 수도 있습니다. 또한 compoundTasktask 테이블을 통합 할 수 있다면 2nd INNER JOIN은 필요하지 않습니다.

+0

Null 허용 상위 행을 사용하려고 만드는 문제는 단일 작업이 여러 복합 업무의 하위 일 수 있습니다. 예제에서 task1과 task2는 모두 복합 태스크 4와 5의 멤버입니다. 나는 같은 테이블에 두 번 가입하는 것을 결코 생각하지 못했습니다. – Drew

+0

사실, 당신은 맞습니다 - taskID가 기본 키이기 때문에이 방법은 작동하지 않습니다. compoundTaskID와 같은 기본 키로 작동하는 또 다른 열을 추가해야합니다. 예제 행 : [compoundTaskID : 1 - taskID : 5 - parentID : 1] - [compoundTaskID : 2 - taskID : 5 - parentID : 2] –

0

저는 mysql에 익숙하지 않지만 저는 T-SQL 저장 프로 시저에 익숙하지 않습니다. 여기에 저장 프로 시저가 있어야한다고 생각합니다.나는

CREATE PROCEDURE proc (@userId BIGINT) 
AS 
BEGIN 

/* 
    Consider this table the same as 
    collection tasksCompleted = user->getTasksCompleted 
*/ 
CREATE TABLE #TasksCompleted 
(
    taskID BIGINT 
); 

INSERT INTO #TaskCompleted 
    (SELECT 
    task.taskId 
    FROM 
    userCompletedTask natural join 
    task 
    WHERE 
    userCompletedTask.userId = @userID AND 
    task.completed = 1); 


/* 
    Same as collection tasksRequired = new collection 
*/ 
CREATE TABLE #RequiredTasks 
(
    taskID BIGINT 
); 

CREATE TABLE #RetrivedRequiredTasks 
(
    taskID BIGINT, 
    compound BIT 
); 

INSERT INTO #RetrivedRequiredTasks 
    (SELECT 
    task.taskId, 
    task.compound 
    FROM 
    usertTaskAssignment NATURAL JOIN 
    assignmentRequiredTask NATURAL JOIN 
    task 
    WHERE 
    userCompletedTask.userId = @userID); 

INSERT INTO #RequiredTasks 
    (SELECT taskID FROM #RetrivedRequiredTasks WHERE compound = 0); 

INSERT INTO #RequiredTasks 
    (SELECT 
    compoundTask.childID 
    FROM 
    #RetrivedRequiredTasks INNER JOIN 
    compoundTask on 
    (
     #RetrivedRequiredTasks.compound = true AND 
     #RetrivedRequiredTasks.taskId = compoundTask.parentID 
    )); 

DECLARE @count INT 

SELECT @count = Count(*) 
FROM #RequiredTasks 
WHERE taskId NOT IN (
    SELECT taskID FROM #TaskCompleted); 

IF @count = 0 THEN 
    SELECT 1 /* All required tasks completed */ 
ELSE 
    SELECT 0 /* vice-versa */ 

END

0

당신은 오직 다음 작업 중 하나 개 수준이 경우 적절하게 더 나은 모델 수도 있으므로 구문 걱정을 제거하시기 바랍니다 ....이 T-SQL과 MySQL의 혼합 생각 작업 테이블과 하위 작업 테이블이 있어야합니다. 비 복합 작업의 경우 배수가 아닌 단일 하위 타스크가 있습니다. parentid = childid 인 모든 복합 작업이 아닌 행에 행을 추가하여 모델에서이 작업을 수행 할 수 있습니다.

그 옆의 모두, 다음 코드는 당신에게 사용자에 대해 필요한 모든 완료되지 않은 작업의 목록을 제공해야합니다

SELECT 
    COALESCE(CT.child_id, T.task_id) 
FROM 
    User_Task_Assignments UTA 
INNER JOIN Assignment_Required_Tasks ART ON 
    ART.assignment_id = UTA.assignment_id 
INNER JOIN Tasks T ON 
    T.task_id = ART.task_id 
LEFT OUTER JOIN Compound_Tasks CT ON 
    CT.parent_task_id = T.task_id AND 
    T.compound = 1 
LEFT OUTER JOIN User_Completed_Tasks UCT ON 
    UCT.user_id = @user_id AND 
    UCT.task_id = COALESCE(CT.child_id, T.task_id) 
WHERE 
    UTA.user_id = @user_id AND 
    UCT.user_id IS NULL 
+0

불행히도, 하위 작업은 그 자체로, 그리고 복합 작업으로 간주 될 수 없습니다. 이제는 적절한 작업을 모두 마칠 때까지 반복적 인 훈련이 필요할 것입니다. 아마도이 점이 더 복잡해 질 것입니다. – Drew

관련 문제