Подсчет без использования функций (например, подсчет) oracle

#sql #oracle

Вопрос:

У меня есть два стола:

ТАБЛИЦА А :

 CREATE TABLE z_ostan ( id NUMBER PRIMARY KEY,
                       name  VARCHAR2(30) NOT NULL CHECK (upper(name)=name) 
                     );
 

ТАБЛИЦА В:

 CREATE TABLE z_shahr ( id NUMBER PRIMARY KEY,
                       name  VARCHAR2(30) NOT NULL CHECK (upper(name)=name),
                       ref_ostan NUMBER,
                       CONSTRAINT fk_ref_ostan FOREIGN KEY (ref_ostan) REFERENCES z_ostan(id)
                    );
 

Как я могу найти «идентификатор» второго и третьего места из таблицы A-Наименее используемой таблицы B в таблице? Без использования предопределенных функций, таких как «count()»

Комментарии:

1. Почему «без использования count() ? Это самый естественный и быстрый способ решить проблему. Еще быстрее, если у вас есть индекс ref_ostan — если я правильно понимаю вашу проблему: найдите три идентификатора из таблицы A, которые отображаются наименьшее количество раз, как ref_ostan в таблице B. Это правда? (И если идентификатор из A вообще не отображается в B, считается ли это «появляется 0 раз», так что это наименьшее количество раз?)

2. Без использования предопределенных функций, таких как «count()» — означает ли это «без каких-либо агрегатных или аналитических функций»? Следует ли вам делать это на чистом SQL или на любом другом языке? В последнем случае напишите процедуру PL/SQL и посчитайте строки самостоятельно. Если это какое — то упражнение, возможно, стоит проверить, в каком контексте оно появляется-какие функции обсуждаются и т. Д.

3. 1) решите проблему с помощью COUNT (на самом деле не ясно, какова цель). 2) перепишите его без ПОДСЧЕТА , например SUM , можно легко имитировать ПОДСЧЕТ. Если даже это не нравится , напишите свой собственный код…

4. Какого поведения вы хотели бы в случае совпадения подсчетов? Вы хотите обработать это как DENSE_RANK, где мы можем увидеть более одного 2-го и/или 3-го наименее используемого числа, или вы хотите произвольно разорвать связи с первичным ключом? Лучше всего показывать фактические случаи с ожидаемыми результатами для каждого из различных случаев.

5. @mathguy Это практика, и Из-За Этого Я не Могу Использовать count. Но Вопрос: У нас есть FK В ТАБЛИЦЕ B Из Таблицы A. Мы Хотим Подсчитать, Сколько раз Идентификатор Из Таблицы A Использовался В Таблице B, и Напечатать 2-й и 3-й, Которые минимально повторяются в Таблице B

Ответ №1:

Это обрабатывает только существующие ссылки на таблицу A.

Обновлено для oracle (используется 12c)

Без использования каких-либо агрегатных или оконных функций:

Пример данных для таблицы: tblb

  ---- --------- --------- 
| id | name    | tbla_id |
 ---- --------- --------- 
|  1 | TBLB_01 |       1 |
|  2 | TBLB_02 |       1 |
|  3 | TBLB_03 |       1 |
|  4 | TBLB_04 |       1 | 4 rows
|  5 | TBLB_05 |       2 |
|  6 | TBLB_06 |       2 |
|  7 | TBLB_07 |       2 | 3 rows
|  8 | TBLB_08 |       3 |
|  9 | TBLB_09 |       3 |
| 10 | TBLB_10 |       3 |
| 11 | TBLB_11 |       3 |
| 12 | TBLB_12 |       3 |
| 13 | TBLB_13 |       3 | 6 rows
| 14 | TBLB_14 |       4 |
| 15 | TBLB_15 |       4 |
| 16 | TBLB_16 |       4 | 3 rows
| 17 | TBLB_17 |       5 | 1 row
| 18 | TBLB_18 |       6 |
| 19 | TBLB_19 |       6 | 2 rows
| 20 | TBLB_20 |       7 | 1 row
 ---- --------- --------- 
 

Есть много способов выразить эту логику.

Шаг за шагом с условиями CTE. Цель такова (для каждого набора строк tbla_id в tblb)

  1. создайте номер строки (n) для строк в каждом разделе. Обычно для этого мы используем оконные функции. Но я предполагаю, что это запрещено.
  2. Используйте этот номер строки (n) для определения количества строк в каждом разделе tbla_id. Чтобы найти это количество для каждого раздела, найдите последнюю строку в каждом разделе (начиная с шага 1).
  3. Упорядочите результаты шага 2 по n из этих последних строк. Выберите 2-ю и 3-ю строки этого результата.
 WITH first AS (  -- Find the first row per tbla_id
          SELECT t1.*
            FROM      tblb t1
            LEFT JOIN tblb t2
              ON t1.id > t2.id
             AND t1.tbla_id = t2.tbla_id
           WHERE t2.id IS NULL
     )
   , rnum (id, name, tbla_id, n) AS (  -- Generate a row_number (n) for each tbla_id partition
          SELECT f.*, 1 FROM first f UNION ALL
          SELECT n.id, n.name, n.tbla_id, c.n 1
            FROM rnum  c
            JOIN tblb  n
              ON c.tbla_id = n.tbla_id
             AND c.id < n.id
            LEFT JOIN tblb n2
              ON n.tbla_id = n2.tbla_id
             AND c.id < n2.id
             AND n.id > n2.id
           WHERE n2.id IS NULL
     )
   , last AS (  -- Find the last row in each partition to obtain the count of tbla_id references
          SELECT t1.*
            FROM      rnum t1
            LEFT JOIN rnum t2
              ON t1.id < t2.id
             AND t1.tbla_id = t2.tbla_id
           WHERE t2.id IS NULL
     )
SELECT * FROM last
 ORDER BY n, tbla_id OFFSET 1 ROWS FETCH NEXT 2 ROWS ONLY
;
 

Конечный результат, где n — количество ссылок на tbla:

  ------ --------- --------- ------ 
| id   | name    | tbla_id | n    |
 ------ --------- --------- ------ 
|   20 | TBLB_20 |       7 |    1 |
|   19 | TBLB_19 |       6 |    2 |
 ------ --------- --------- ------ 
 

Некоторые промежуточные результаты…

last Результат срока CTE. 2-я и 3-я строки этого становятся конечным результатом.

  ------ --------- --------- ------ 
| id   | name    | tbla_id | n    |
 ------ --------- --------- ------ 
|   17 | TBLB_17 |       5 |    1 |
|   20 | TBLB_20 |       7 |    1 |
|   19 | TBLB_19 |       6 |    2 |
|    7 | TBLB_07 |       2 |    3 |
|   16 | TBLB_16 |       4 |    3 |
|    4 | TBLB_04 |       1 |    4 |
|   13 | TBLB_13 |       3 |    6 |
 ------ --------- --------- ------ 
 

rnum Результат срока CTE. Это обеспечивает номер строки над разделами tbla_id, упорядоченными по идентификатору

  ------ --------- --------- ------ 
| id   | name    | tbla_id | n    |
 ------ --------- --------- ------ 
|    1 | TBLB_01 |       1 |    1 |
|    2 | TBLB_02 |       1 |    2 |
|    3 | TBLB_03 |       1 |    3 |
|    4 | TBLB_04 |       1 |    4 |
|    5 | TBLB_05 |       2 |    1 |
|    6 | TBLB_06 |       2 |    2 |
|    7 | TBLB_07 |       2 |    3 |
|    8 | TBLB_08 |       3 |    1 |
|    9 | TBLB_09 |       3 |    2 |
|   10 | TBLB_10 |       3 |    3 |
|   11 | TBLB_11 |       3 |    4 |
|   12 | TBLB_12 |       3 |    5 |
|   13 | TBLB_13 |       3 |    6 |
|   14 | TBLB_14 |       4 |    1 |
|   15 | TBLB_15 |       4 |    2 |
|   16 | TBLB_16 |       4 |    3 |
|   17 | TBLB_17 |       5 |    1 |
|   18 | TBLB_18 |       6 |    1 |
|   19 | TBLB_19 |       6 |    2 |
|   20 | TBLB_20 |       7 |    1 |
 ------ --------- --------- ------ 
 

Есть несколько других способов решения этой проблемы только в SQL.