SELECT COUNT INTO переменная - PullRequest
0 голосов
/ 01 мая 2020

Я пытаюсь получить количество строк таблицы и сохранить ее в переменной, чтобы я мог использовать эту переменную, однако она будет сохранять ее только в переменной, если я использую WHERE ROWNUM = 1;, но тогда она будет хранить только число 1 а не фактическое количество строк. Весь оператор выбора, который я использую:

SELECT COUNT(*)
INTO vn_no_tickets
FROM tickets
WHERE ROWNUM = 1;

Если я не использую WHERE ROWNUM = 1;, я получаю сообщение об ошибке «Точная выборка возвращает больше, чем запрошенное количество строк», но снова, когда я использую это, я получаю только 1 строку, а не фактическое число или строк. Спасибо

Редактировать: Вот полная процедура

CREATE OR REPLACE PROCEDURE proc_ticket_exp IS
    vn_no_tickets NUMBER(4);
    vn_ticket_id tickets.ticket_id%TYPE;
    vd_exp_date tickets.expiration_date%TYPE;
    vc_customer_firstname tickets.customer_firstname%TYPE;
    vc_customer_surname tickets.customer_surname%TYPE;
    vd_one_week DATE;
    vc_fullname VARCHAR2(40); 
BEGIN
    vd_one_week := sysdate + 7;
    SELECT COUNT(*)
    INTO vn_no_tickets
    FROM tickets
    WHERE ROWNUM = 1;
    DBMS_OUTPUT.PUT_LINE (vn_no_tickets);

    WHILE vn_no_tickets != 0 LOOP
        SELECT expiration_date, ticket_id, customer_firstname, customer_surname
        INTO vd_exp_date, vn_ticket_id, vc_customer_firstname,  vc_customer_surname
        FROM tickets
        WHERE ROWNUM = vn_no_tickets;
        vc_fullname := CONCAT(vc_customer_firstname, CONCAT(' ', vc_customer_surname));
        IF vd_exp_date < vd_one_week THEN
            DBMS_OUTPUT.PUT_LINE (vc_fullname || 's ticket will expire within one week. Ticket Number: ' || vn_ticket_id);
        END IF;
        vn_no_tickets := vn_no_tickets - 1;
    END LOOP;        
END proc_ticket_exp;
/ 
SHOW ERRORS

Ответы [ 2 ]

2 голосов
/ 01 мая 2020

Документация Oracle для ROWNUM является довольно явной:

Условия проверки значений ROWNUM, превышающих положительное целое число, всегда ложны. Например, этот запрос не возвращает строк:

SELECT *
FROM employees
WHERE ROWNUM > 1;

Первой извлеченной строке присваивается ROWNUM, равный 1, и условие становится ложным. Вторая извлекаемая строка теперь является первой строкой, ей также присваивается ROWNUM, равный 1, и условие становится ложным. Впоследствии все строки не удовлетворяют условию, поэтому строки не возвращаются.

(Примечание. Это также относится к сравнению на равенство, превышающему 1).

Итак, это условие:

    WHERE ROWNUM = vn_no_tickets

возвращает строку только тогда, когда vn_no_tickets равен "1".

Самый простой способ исправить это - обойтись без счетчика:

FOR t IN (SELECT expiration_date, ticket_id, customer_firstname, customer_surname
         FROM tickets
         )
LOOP
    vc_fullname := t.customer_firstname || ' ' || t.customer_surname;
    IF t.exp_date < vd_one_week THEN
        DBMS_OUTPUT.PUT_LINE (vc_fullname || 's ticket will expire within one week. Ticket Number: ' || t.ticket_id);
    END IF;
END LOOP;   

Тем не менее, вы должны переместить условие IF в предложение WHERE. Глупо извлекать строку из базы данных, просто чтобы проверить условие - когда это условие можно использовать для фильтрации результирующего набора в первую очередь.

2 голосов
/ 01 мая 2020

Фактический код, который не работает, приведен ниже, поскольку в первом запросе, который вы вводите rownum=1, вы получите count also as 1, следовательно, vn_no_tickets will be 1. Если вы удалите rownum=1 в первом запросе, то vn_no_tickets will be greater than 1 и запрос ниже будет fail

    SELECT expiration_date, ticket_id, customer_firstname, customer_surname
    INTO vd_exp_date, vn_ticket_id, vc_customer_firstname,  vc_customer_surname
    FROM tickets
    WHERE ROWNUM <= vn_no_tickets;
...