Рекурсивная sql проблема

7
задан Gabriele Petrioli 28 January 2011 в 14:24
поделиться

11 ответов

Хорошо, я думаю, что у меня есть он. Это встречает ограничения, которые Вы обеспечили. Мог бы быть способ упростить это далее, но он съел мой мозг немного:

select distinct PO 
from POPI x 
where 
  PO not in (
    select PO 
    from POPI 
    where PI not in (10,11,12)
  ) 
  and PI not in (
    select PI 
    from POPI 
    where PO != x.PO 
      and PO not in (
        select PO 
        from POPI 
        where PI not in (10,11,12)
      )
  );

Это приводит только к результатам, кто заполняет данный набор, которые являются непересекающимися со всеми другими результатами, которые я думаю , то, что Вы просили. Для тестовых данных примеров:

  • Обеспечение 10,11,12 урожаев
  • Обеспечение 10,11,13 урожаев B, C
7
ответ дан 6 December 2019 в 23:14
поделиться

Редактирование: , Пока я думаю, что мой хорошо работает, ответ Adam без сомнения, более изящного и более эффективного - я просто оставлю мой здесь для потомства!

Извинения, так как я знаю это, были отмечены как проблема Oracle, так как я начал играть. Это - некоторый код SQL2008, который я думаю работы для всего изложившего свои доводы....

declare @test table
(
    [PI] int
)
insert @test values (10), (11), (13)

declare @testCount int
select @testCount = COUNT(*) from @test

;with PO_WITH_COUNTS as 
(
        select  PO_FULL.PO, COUNT(PO_FULL.[PI]) PI_Count
        from    ProductOffering PO_FULL
        left
        join    (
                select  PO_QUALIFYING.PO, PO_QUALIFYING.[PI]
                from    ProductOffering PO_QUALIFYING
                where   PO_QUALIFYING.[PI] in (select [PI] from @test)
                ) AS QUALIFYING
                on      QUALIFYING.PO = PO_FULL.PO
                and     QUALIFYING.[PI] = PO_FULL.[PI]
        group by
                PO_FULL.PO
        having  COUNT(PO_FULL.[PI]) = COUNT(QUALIFYING.[PI])
)
select  PO_OUTER.PO
from    PO_WITH_COUNTS PO_OUTER 
cross 
join    PO_WITH_COUNTS PO_INNER
where   PO_OUTER.PI_Count = @testCount
or      PO_OUTER.PO <> PO_INNER.PO
group by
        PO_OUTER.PO, PO_OUTER.PI_Count
having  PO_OUTER.PI_Count = @testCount 
or      PO_OUTER.PI_Count + SUM(PO_INNER.PI_Count) = @testCount

Не уверенный, если Oracle имеет CTEs, но могла бы просто заявить внутренний запрос как две полученных таблицы. Перекрестное объединение во внешнем запросе позволяет нам найти комбинации предложений, которые имеют все допустимые объекты. Я знаю, что это будет только работать на основе оператора в вопросе, что данные таковы, что существует только 1 допустимая комбинация для каждого требуемого набора, Без которого это еще более сложно, поскольку количеств недостаточно для удаления комбинаций, которые имеют дублирующиеся продукты в них.

2
ответ дан 6 December 2019 в 23:14
поделиться

У меня нет дб передо мной, но первое, что пришло на ум Вы хотите список POs, которые не имеют никаких ПИ не в Вашем входном списке, т.е.

select distinct po 
from tbl 
where po not in ( select po from tbl where pi not in (10,11,13) )

Редактирование: Вот является пример другими случаями:
, Когда введенный PI = 10,11,13 внутренний выбор возвращается, таким образом, внешний выбор возвращает B, C
, Когда введенный PI = 10 внутренний выбор возвращает A, B, C, таким образом, внешний выбор не возвращает строк
, Когда введенный PI = 10,11,12 внутренний выбор возвращает C, таким образом, внешний выбор возвращает A, Редактирование B

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

1
ответ дан 6 December 2019 в 23:14
поделиться
  Select Distinct PO
   From Table T
   -- Next eliminates POs that contain other PIs
   Where Not Exists 
       (Select * From Table 
        Where PO = T.PO
            And PI Not In (10, 11, 12))
     -- And this eliminates POs that do not contain all the PIs
     And Not Exists 
        (Select Distinct PI From Table  
         Where PI In (10, 11, 12)
           Except 
         Select Distinct PI From Table  
         Where PO = T.PO

или, если Ваша база данных не реализует КРОМЕ...

   Select Distinct PO
   From Table T
   -- Next predicate eliminates POs that contain other PIs
   Where Not Exists 
       (Select * From Table 
        Where PO = T.PO
            And PI Not In (10, 11, 12))
     -- And this eliminates POs that do not contain ALL the PIs
     And Not Exists 
         (Select Distinct PI From Table A
          Where PI In (10, 11, 12)
             And Not Exists
                 (Select Distinct PI From Table 
                  Where PO = T.PO 
                     And PdI = A.PI))                 
1
ответ дан 6 December 2019 в 23:14
поделиться

Действительно ли возможно, что клиенты просят продукт несколько раз?

, Например: он просит у предложения 10,10,11,11,12?

, Если это возможно, чем решения как

выбор... из..., где пи в (10,10,11,11,12)

не будет работать.

, поскольку 'пи в (10,10,11,11,12)' совпадает с 'пи в (10,11,12)'.

решением для А для 10,10,11,11,12 является A& B.

1
ответ дан 6 December 2019 в 23:14
поделиться

хорошо некоторый псевдо код от вершины моей головы здесь:

выбор из таблицы, где PI = 10 или пи =11, и т.д.

хранит результат во временной таблице

, выбирает отличную ПО и количество (PI) от временной таблицы.

теперь для каждой ПО можно получить общие доступные предложения PI. если количество ПИ доступные соответствия количество во временной таблице, это означает, что у Вас есть все ПИ для той ПО. добавьте весь POs и Вас авеню Ваш набор результатов.

0
ответ дан 6 December 2019 в 23:14
поделиться

Вам будет нужно количество объектов в Вашем списке, т.е. @list_count. Фигура, какие Предложения имеют Экземпляры, которые не находятся в списке. Выберите все Предложения, которые не находятся в , что список и делает , имеют Экземпляры в списке:

select P0,count(*) c from table where P0 not in (
select P0 from table where P1 not in (@list)
) and P1 in (@list) group by P0

я сохранил бы это во временной таблице и выборе * записи где c = @list_count

0
ответ дан 6 December 2019 в 23:14
поделиться

Если мы переопределяем немного проблема:

Позволяет, имеют клиентскую таблицу с экземплярами продукта:

crete table cust_pi (
pi varchar(5),
customer varchar(5));

И "product_catalogue" таблица:

CREATE TABLE PI_PO_TEST
   ("PO" VARCHAR2(5 CHAR),
   "PI" VARCHAR2(5 CHAR)
           );

Позволяет, заполняют его некоторыми демонстрационными данными:

insert into CUST_PI (PI, CUSTOMER)
values ('11', '1');
insert into CUST_PI (PI, CUSTOMER)
values ('10', '1');
insert into CUST_PI (PI, CUSTOMER)
values ('12', '1');
insert into CUST_PI (PI, CUSTOMER)
values ('13', '1');
insert into CUST_PI (PI, CUSTOMER)
values ('14', '1');
insert into PI_PO_TEST (PO, PI)
values ('A', '10');
insert into PI_PO_TEST (PO, PI)
values ('A', '11');
insert into PI_PO_TEST (PO, PI)
values ('A', '12');
insert into PI_PO_TEST (PO, PI)
values ('A', '13');
insert into PI_PO_TEST (PO, PI)
values ('B', '14');
insert into PI_PO_TEST (PO, PI)
values ('C', '11');
insert into PI_PO_TEST (PO, PI)
values ('C', '12');
insert into PI_PO_TEST (PO, PI)
values ('D', '15');
insert into PI_PO_TEST (PO, PI)
values ('D', '14');

Затем мое первое решение для охоты похоже на это:

select po1 po /* select all product offerings that match the product definition 
                (i.e. have the same number of product instances per offering as 
                in product catalogue */
  from (select po po1, count(c.pi) k1
          from cust_pi c, pi_po_test t
         where c.pi = t.pi
           and customer = 1
         group by po) t1,
       (select po po2, count(*) k2 from pi_po_test group by po) t2
 where k1 = k2
   and po1 = po2
minus /* add those, that are contained within others */
select slave
  from (select po2 master, po1 slave
  /* this query returns, that if you have po "master" slave should be removed from result, 
     as it is contained within*/
          from (select t1.po po1, t2.po po2, count(t1.po) k1
                  from pi_po_test t1, pi_po_test t2
                 where t1.pi = t2.pi
                 group by t1.po, t2.po) t1,
               (select po, count(po) k2 from pi_po_test group by po) t2
         where t1.po2 = t2.po
           and k1 < k2)
 where master in
 /* repeated query from begining. This could be done better :-) */
       (select po1 po
          from (select po po1, count(c.pi) k1
                  from cust_pi c, pi_po_test t
                 where c.pi = t.pi
                   and customer = 1
                 group by po) t1,
               (select po po2, count(*) k2 from pi_po_test group by po) t2
         where k1 = k2
           and po1 = po2)

Все это было сделано на Oracle, таким образом, Ваш пробег может варьироваться

0
ответ дан 6 December 2019 в 23:14
поделиться

Я протестировал это под 4 множествами значений, и они все возвратили корректный результат. Это использует функцию, которую я использую в SQL для генерации таблицы от строки параметров, разделенных точками с запятой.

DECLARE @tbl TABLE (
    po varchar(10),
    pii int)

INSERT INTO @tbl
SELECT 'A', 10
UNION ALL
SELECT 'A', 11
UNION ALL
SELECT 'A', 12
UNION ALL
SELECT 'B', 10
UNION ALL
SELECT 'B', 11
UNION ALL
SELECT 'C', 13

DECLARE @value varchar(100)
SET @value = '10;11;12;'
--SET @value = '11;10;'
--SET @value = '13;'
--SET @value = '10;'

SELECT DISTINCT po
FROM @tbl a
INNER JOIN fMultiValParam (@value) p ON
a.pii = p.paramid
WHERE a.po NOT IN (
    SELECT t.po
    FROM @tbl t
    LEFT OUTER JOIN (SELECT *
            FROM @tbl tt
            INNER JOIN fMultiValParam (@value) p ON
            tt.pii = p.paramid) tt ON
    t.pii = tt.pii
    AND t.po = tt.po
    WHERE tt.po IS NULL)

вот функция

CREATE    FUNCTION [dbo].[fMultiValParam]
(@Param varchar(5000))
RETURNS @tblParam TABLE (ParamID varchar(40))
AS
BEGIN

IF (@Param IS NULL OR LEN(@Param) < 2)
BEGIN
    RETURN
END

DECLARE @len INT
DECLARE @index INT
DECLARE @nextindex INT

SET @len = DATALENGTH(@Param)
SET @index = 0
SET @nextindex = 0

WHILE (@index < @len)
BEGIN
    SET @Nextindex = CHARINDEX(';', @Param, @index)

    INSERT INTO @tblParam
    SELECT SUBSTRING(@Param, @index, @nextindex - @index)

    SET @index = @nextindex + 1

END
RETURN
END
0
ответ дан 6 December 2019 в 23:14
поделиться

Попробуйте это:

SELECT DISTINCT COALESCE ( offer, NULL )
FROM products
WHERE instance IN ( @instancelist )
0
ответ дан 6 December 2019 в 23:14
поделиться

По моему скромному мнению, невозможный через чистый SQL без некоторого кода хранимой процедуры. Но... я не уверен.

Добавленный: , С другой стороны, я понимаю о рекурсивном запросе (в 2005 MSSQL существует такая вещь, которая позволяет Вам присоединяться к запросу со своими собственными результатами, пока больше нет возвращенных строк), который мог бы "собрать" корректные ответы путем перекрестного присоединения к результатам предыдущего шага со всеми продуктами и затем отфильтровывания недопустимых комбинаций. Вы однако получили бы все перестановки допустимых комбинаций, и это едва будет эффективно. И представление является довольно смутным, таким образом, я не могу гарантировать, что оно может на самом деле быть реализовано.

-1
ответ дан 6 December 2019 в 23:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: