oracle поддерживает вложенные наборы результатов? - PullRequest
2 голосов
/ 22 апреля 2020

Простите, если это не имеет смысла. Я не делал SQL годами. Опять мокрые ноги, поэтому, пожалуйста, поправьте меня, если мои предположения здесь неверны.

Насколько я помню, SQL Сервер (или, возможно, это был объект ADO. NET) имел удобную функцию, где вы может вложить подмножество «дочерних» строк в родительско-дочерние отношения вместе с их соответствующей родительской строкой, как вложенный результирующий набор для этой родительской строки.

Например, если у вас были следующие три таблицы: .

  • Заказы (ID, имя)
  • Продукты (ID, имя)
  • OrderDetails (Order_ID, Product_ID)

Итак в качестве примера, скажем, у вас было десять заказов, каждый из которых, скажем, пять предметов Стандартное объединение вернет пятьдесят строк.

Я имею в виду функцию, которая возвращает мне десять строк - по одной на заказ - тогда, когда вы курсировали через эти результаты, вы бы запросили вложенные результаты для этой строки (то есть, по сути, второй курсор над продуктами в указанном порядке.)

Имеет ли Oracle такую ​​функцию / возможность?

Ответы [ 3 ]

3 голосов
/ 22 апреля 2020

Вы можете использовать CURSOR выражения :

SELECT id AS orderid,
       CURSOR(
         SELECT p.id,
                p.name
         FROM   OrderedProducts op
                INNER JOIN Products p
                ON ( op.products_id = p.id )
         WHERE  op.orders_id = o.id
       )
FROM   orders o

Выражения курсора не поддерживаются многими интерфейсами, но вы должны иметь возможность заставить его работать, используя Java через JDB C и, возможно, некоторые другие.


Другой альтернативой является использование коллекций и типов объектов:

CREATE TYPE product_type AS OBJECT(
  id   NUMBER,
  name VARCHAR2(200)
);
/

CREATE TYPE product_table AS TABLE OF product_type;
/

Тогда:

SELECT id AS Order_Id,
       CAST(
         MULTISET (
           SELECT  product_type( P.id, P.name )
           FROM    OrderDetails OD
           JOIN    Products P
           ON      OD.Product_Id = P.Id
           WHERE   OD.Order_Id   = O.Id
         )
         AS product_table
       ) AS products
FROM   Orders O;

дБ <> fiddle (db <> fiddle успешно выполняет запрос; хотя он не знает, как отобразить коллекцию в окончательном наборе результатов, чтобы он не отображал никаких строк)


Или Вы можете использовать XML:

SELECT id AS order_id,
       ( SELECT XMLELEMENT(
                  "Products",
                  XMLAGG(
                    XMLElement(
                      "Product",
                      XMLFOREST(
                        p.id AS "ProductID",
                        p.name AS "ProductName"
                      )
                    )
                  )
                )
         FROM   OrderDetails OD
         JOIN   Products P
         ON     OD.Product_Id = P.Id
         WHERE  OD.Order_Id   = O.Id
       ) AS products
FROM   Orders o

Какие выходы:

ORDER_ID | PRODUCTS                                                                                                                                                                                                                                                      
-------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
       1 | <Products><Product><ProductID>202</ProductID><ProductName>car</ProductName></Product></Products>                                                                                                                                                              
       2 | <Products><Product><ProductID>201</ProductID><ProductName>orange</ProductName></Product><Product><ProductID>202</ProductID><ProductName>car</ProductName></Product><Product><ProductID>203</ProductID><ProductName>airplane</ProductName></Product></Products>

Или JSON:

SELECT id AS order_id,
       ( SELECT JSON_ARRAYAGG(
                  JSON_OBJECT(
                    'id' VALUE p.id,
                    'name' VALUE p.name
                  )
                )
         FROM   OrderDetails OD
         JOIN   Products P
         ON     OD.Product_Id = P.Id
         WHERE  OD.Order_Id   = O.Id
       ) AS products
FROM   Orders o

Какие выходы :

ORDER_ID | PRODUCTS                                                                         
-------: | :--------------------------------------------------------------------------------
       1 | [{"id":202,"name":"car"}]                                                        
       2 | [{"id":201,"name":"orange"},{"id":202,"name":"car"},{"id":203,"name":"airplane"}]

дБ <> скрипка здесь

1 голос
/ 22 апреля 2020

SQL Сервер не имел такой функции. Единственный способ вернуть "фасонные" данные из SQL запроса к серверу - использовать XML или JSON в качестве выходных данных.

Вы можете вернуть несколько отдельных наборов результатов из одного запроса пакета или вызова хранимой процедуры.

Таким образом, пакет

select * from orders where id = @id
select * from order_details where order_id = @id

просто возвратит два отдельных набора результатов, которые клиент видит в порядке.

Oracle действительно имеет вложенные курсоры, но я не уверен, насколько широко они используются или какие клиентские API поддерживают их.

Это был вложенный набор результатов, который вы могли бы доступ через возвращенные объекты. Мне интересно, если это была функция ADO. NET, а не базы данных.

ADO. NET имеет DataSet , который хранит связанные данные из нескольких таблиц в памяти. Но данные всегда загружаются и записываются с отдельными запросами на таблицу. И ADO. NET DataSets, и более новый. Net API доступа к данным API Entity Framework работают с Oracle.

Еще дальше, в темное время, было ADO Data Shaping .

0 голосов
/ 22 апреля 2020

Может быть, я ошибаюсь, но - это выглядит как обычное соединение. Смотрите пример:

with 
-- sample data
orders (id, name) as
  (select 1, 'Order 1' from dual union all
   select 2, 'Order 2' from dual 
  ),
products (id, name) as
  (select 200, 'apple' from dual union all
   select 201, 'orange' from dual union all
   select 202, 'car' from dual union all
   select 203, 'airplane' from dual
  ),
orderedproducts (orders_id, products_id) as
  (select 1, 202 from dual union all
   select 2, 201 from dual union all
   select 2, 202 from dual union all
   select 2, 203 from dual
  )
-- query you need (I think)  
select o.id oid, o.name oname, p.id, p.name
from orders o join orderedproducts op on op.orders_id = o.id
              join products p on p.id = op.products_id
where 
  -- get everything for order ID = 2
  o.id = 2
order by o.id, p.id;

        ID NAME            ID NAME
---------- ------- ---------- --------
         2 Order 2        201 orange
         2 Order 2        202 car
         2 Order 2        203 airplane

Если это не это , не могли бы вы опубликовать то, что вы действительно ожидаете от него? Вы знаете - желаемый результат?


Если вы хотите пропустить повторение значений из таблицы orders, это зависит от используемого вами инструмента. В SQL* Plus вы можете BREAK в этих столбцах, например,

SQL> break on oid on oname
SQL>
SQL> with
  2  -- sample data
  3  orders (id, name) as
  4    (select 1, 'Order 1' from dual union all
<snip>
 23  where
 24    -- get everything for order ID = 2
 25    o.id = 2
 26  order by o.id, p.id;

       OID ONAME           ID NAME
---------- ------- ---------- --------
         2 Order 2        201 orange
                          202 car
                          203 airplane

SQL>

Или, если вы используете какой-либо инструмент отчетности (например, Oracle Построитель отчетов или даже Apex Interactive или Classi) c отчетов), у них также есть такая возможность.


Если это все еще не "это", PL / SQL вариант для вас? Некоторые называют это «хранимыми процедурами» (хотя это не совсем то, что есть, но «процедуру» легче понять, чем «PL / SQL»). Там у вас есть разные варианты, такие как курсоры и циклы.

...