如何在PL / SQL中处理隐式游标的结果集?

时间:2014-07-17 02:23:41

标签: sql oracle plsql

我正在寻找一些帮助,根据以下规则编写数据转换SQL脚本(或者PL / SQL脚本?)。

For each person...
1) If all three tasks are 'done', do nothing
2) If 'wake up' task is 'awaiting', do nothing
3) Else, INSERT a new record for person WHERE item = 'go to work' 
and status = 'awaiting'

tasks table:
id     person     item          status
1      john       wake up       done
2      john       brush teeth   done
3      john       get dressed   done
4      amy        wake up       done
5      amy        brush teeth   done
6      amy        get dressed   done
7      frank      wake up       awaiting
8      sue        wake up       done
9      sue        brush teeth   started   
10     andy       wake up       done
11     andy       brush teeth   started
12     andy       get dressed   started   
...
...
... 

虽然我有一些SQL经验,但我刚开始学习PL / SQL。我相信这里可能需要PL / SQL来遍历每个人,检查人员记录,并应用IF THEN逻辑。

这是我到目前为止所做的:

BEGIN
    FOR task IN (SELECT DISTINCT person
        FROM tasks)
    LOOP
        DBMS_OUTPUT.PUT_LINE('Processing... ' || task.person || ', ' || task.item || ', ' || task.status);
        -- This is where I am having trouble. 
        -- How can I examine all rows for each candidate 
        -- at once when each row is returned only one at a time?
    END LOOP;
END;

2 个答案:

答案 0 :(得分:0)

INSERT INTO tasks
  SELECT MYSEQ.NEXTVAL,Person,item,status
  FROM
  (
     SELECT person,
           'go to work' AS item
           'AWAITING' as status
     FROM tasks
     GROUP BY person
    HAVING COUNT(DECODE(status,'AWAITING',1)) = 0 AND COUNT(*) <> 3
  ) MYVIEW

希望像这样的查询,对你有帮助吗?

仍然,对于PL / SQL解决方案:

BEGIN
    FOR task IN (SELECT DISTINCT person
        FROM tasks)
    LOOP
        DBMS_OUTPUT.PUT_LINE('Processing... ' || task.person || ', ' || task.item || ', ' || task.status);
        INSERT INTO tasks
            SELECT 
             MYSEQ.NEXTVAL,
             task.person,
             'go to work',
             'AWAITING'
            FROM dual
            WHERE NOT EXISTS
            (SELECT 'x' FROM tasks t
             WHERE t.person = task.person AND t.status = 'AWAITING');


         DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQL%ROWCOUNT) || ' rows inserted.');
    END LOOP;
    COMMIT;
END;

答案 1 :(得分:0)

您可以根据需要使用以下SQL查询插入新行。可以使用PL / SQL将相同的逻辑构建到循环中,但基于集合的SQL处理比循环和逐个记录处理要快得多。

以下查询假定您有一个BEFORE INSERT触发器,它从序列中获取下一个值以更新id列。

INSERT INTO tasks (person, item, status)
SELECT
    person, 'go to work', 'awaiting'
FROM persons
WHERE (task = 'wake up' AND status <> 'awaiting')
OR person in
(
    SELECT
        person
    FROM tasks
    WHERE status = 'done'
    GROUP BY person
    HAVING count(*) <> 3
) persons_done;

否则,您可以手动从序列中获取下一个值,如:

INSERT INTO tasks (id, person, item, status)
SELECT
    my_sequence.nextVal, person, 'go to work', 'awaiting' --Replace my_sequence with the name of the sequence in your database
FROM persons
WHERE (task = 'wake up' AND status <> 'awaiting')
OR person in
(
    SELECT
        person
    FROM tasks
    WHERE status = 'done'
    GROUP BY person
    HAVING count(*) <> 3
) persons_done;

<强>参考

Thanks for the question regarding "Cursors or queries?", version 9.2.0 on AskTom Oracle