#oracle #plsql
#Oracle #plsql
Вопрос:
Я задавал этот вопрос раньше, но я не получил никакой помощи. Я хочу получить количество строк в двух разных таблицах с заданным атрибутом. Это мой код . Вместо того, чтобы извлекать общее количество там, где выполняется условие, я получаю весь подсчет таблицы
create or replace PROCEDURE p1( suburb IN varchar2 )
as
person_count NUMBER;
property_count NUMBER;
BEGIN
SELECT count(*) INTO person_count
FROM person p WHERE p.suburb = suburb ;
SELECT count(*) INTO property_count
FROM property pp WHERE pp.suburb = suburb ;
dbms_output.put_line('Number of People :'|| person_count);
dbms_output.put_line('Number of property :'|| property_count);
END;
/
Есть ли какой-либо другой способ сделать это, чтобы я мог получить реальное общее количество людей в этом ПРИГОРОДЕ
Некоторые данные из ТАБЛИЦЫ PERSON
PEID FIRSTNAME LASTNAME
---------- -------------------- --------------------
STREET SUBURB POST TELEPHONE
---------------------------------------- -------------------- ---- ------------
30 Robert Williams
1/326 Coogee Bay Rd. Coogee 2034 9665-0211
32 Lily Roy
66 Alison Rd. Randwick 2031 9398-0605
34 Jack Hilfgott
17 Flood St. Bondi 2026 9387-0573
НЕКОТОРЫЕ ДАННЫЕ из ТАБЛИЦЫ СВОЙСТВ
PNO STREET SUBURB POST
---------- ---------------------------------------- -------------------- ----
FIRST_LIS TYPE PEID
--------- -------------------- ----------
48 66 Alison Rd. Randwick 2031
12-MAR-11 Commercial 8
49 1420 Arden St. Clovelly 2031
27-JUN-10 Commercial 82
50 340 Beach St. Clovelly 2031
05-MAY-11 Commercial 38
Извините за то, как выглядит таблица.
Это значение, которое я получаю при запуске вышеупомянутого скрипта.
SQL> exec p1('Randwick')
Number of People :50
Number of property :33
Я изменил ПРОЦЕДУРУ, вот что я получаю.
SQL> create or replace PROCEDURE p1( location varchar2 )
IS
person_count NUMBER;
property_count NUMBER;
BEGIN
SELECT count(p.peid) INTO person_count
FROM person p WHERE p.suburb = location ;
SELECT count(pp.pno) INTO property_count
FROM property pp WHERE pp.suburb = location ;
dbms_output.put_line('Number of People :'|| person_count);
dbms_output.put_line('Number of property :'|| property_count);
END;
/
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Procedure created.
SQL> exec p1('KINGSFORD')
Number of People :0
Number of property :0
PL/SQL procedure successfully completed.
SQL>
SQL>
SQL> exec p1('Randwick')
Number of People :0
Number of property :0
PL/SQL procedure successfully completed.
SQL>
Решение должно быть таким
SQL> exec p1('randwick');
Number of People: 7
Number of Property: 2
Комментарии:
1. пожалуйста, покажите некоторые данные из 2 таблиц и значение параметра
suburb
2. Ваши последние два примера отличаются. В предпоследнем указано, что вы указываете ‘Randwick’, а в последнем указано, что вы указываете ‘randwick’ (со строчной буквы «r»). Ваша проблема, вероятно, связана с тем, как вы сохраняете свое значение suburb и в каком случае ему передаются ваши параметры. Вы должны стандартизировать их, чтобы убедиться, что соответствие выполнено.
Ответ №1:
Вы назвали переменную так же, как поле. В запросе suburb
сначала ищется в области запроса и соответствует полю suburb
, даже если оно не использует pp
псевдоним таблицы.
Таким образом, вы фактически сравниваете поле с самим собой, поэтому получаете все записи (то есть, где suburb
НЕ NULL). Параметр процедуры вообще не используется в запросе.
Решение: измените имя параметра процедуры.
Чтобы предотвратить подобные ошибки, я всегда использую P_
в качестве префикса для параметров процедуры / функции и V_
в качестве префикса для локальных переменных. Таким образом, они никогда не смешиваются с именами полей.
Комментарии:
1. Если я изменю suburb на vsuburb , я получу 0 в качестве общего количества.
2. Тогда значение, переданное в vsuburb, также неверно. Обратите внимание, что поиск чувствителен к регистру. Должно быть точное совпадение. Если вы сомневаетесь, пожалуйста, измените свой вопрос и добавьте новую процедуру и код, который ее вызывает (включая передаваемое значение).
3. Я вижу вашу правку и думаю, что знаю проблему (или «a»): если вы используете
count(pp.pno)
,pp.pno
не должно быть NULL , иначеcount
возвращает 0. Измените его на*
или на постоянное значение типа1
или'x'
, если вы не хотите считать только записи, где значение действительно не равно null.4. Также обратите внимание, что
location
это зарезервированное слово, хотя я точно не знаю, можно ли его использовать здесь. Пожалуйста, попробуйте другое имя или добавьте префикс, как я предлагал ранее.5. «Я всегда использую P_ в качестве префикса для параметров процедуры / функции и V_ в качестве префикса для локальных переменных» — я знаю, что это очень распространенная привычка, но я ненавижу беспорядок, который она создает в интерфейсе к коду pl / sql.
Ответ №2:
Хотя я согласен, что причиной проблемы является проблема с пространством имен между SQL и PL / SQL, поскольку механизм SQL «захватил» имя переменной PL / SQL, я не считаю, что изменение имени параметра является наилучшим подходом. Если вы сделаете это, то вы обрекаете каждого разработчика на то, чтобы начать добавлять к каждому имени параметра префикс «p_» или какой-либо другой бесполезный довесок и убедиться, что они никогда не создают столбец с префиксом P_.
Если вы просмотрите документацию по поставляемым пакетам PL / SQL, вы увидите очень мало, если вообще есть, случаев, когда Oracle сами делают это, хотя в прошлом они делали раздражающе непоследовательные вещи, такие как ссылка на имя_таблицы как «tabname».
Более надежный подход заключается в том, чтобы префиксить имя переменной именем процедуры pl / sql при ссылке на нее в операторах SQL:
SELECT count(*)
INTO person_count
FROM person p WHERE p.suburb = p1.suburb ;
В вашем случае вы явно не назвали бы свою процедуру «P1», так что на самом деле у вас было бы что-то вроде:
SELECT count(*)
INTO person_count
FROM person p WHERE p.suburb = count_suburb_objects.suburb ;
Теперь ваш код защищен от захвата имени переменной — в качестве бонуса ваш текстовый редактор может выделить все случаи, когда вы использовали имя переменной в инструкции SQL при двойном щелчке по имени процедуры.
Комментарии:
1. 1 Этот подход также помогает определить область действия переменной при наличии вложенных процедур.
Ответ №3:
Сначала создайте индексы для поиска без учета регистра:
CREATE INDEX idx_person_suburb_u ON person(upper(suburb))
/
CREATE INDEX idx_property_suburb_u ON property(upper(suburb))
/
Во-вторых, используйте префиксы для параметров процедуры и локальных переменных:
CREATE OR REPLACE PROCEDURE p1(p_location VARCHAR2)
IS
v_person_count NUMBER;
v_property_count NUMBER;
v_location VARCHAR2(32767);
BEGIN
IF p_location IS NOT NULL THEN
v_location := upper(p_location);
SELECT count(*) INTO v_person_count
FROM person WHERE upper(suburb) = v_location ;
SELECT count(*) INTO v_property_count
FROM property WHERE upper(suburb) = v_location ;
ELSE
SELECT count(*) INTO v_person_count
FROM person WHERE upper(suburb) IS NULL;
SELECT count(*) INTO v_property_count
FROM property WHERE upper(suburb) IS NULL;
END IF;
dbms_output.put_line('Number of People :' || v_person_count);
dbms_output.put_line('Number of Property :' || v_property_count);
END;
/
Комментарии:
1. count(1) и count(*) одинаковы: asktom.oracle.com/pls/asktom /…