Выберите строку из таблицы, в которой значение столбца имеет наивысший приоритет

У меня есть таблица базы данных со столбцами DOC1, DOC2 и CLIENT. Я пытаюсь выбрать одну строку для каждого КЛИЕНТА, столбец DOC1 которого имеет наивысший приоритет в следующем порядке, от наивысшего к низшему: ITCI> ITPP> ITPS> ITPT.

Вот пример.

ВВОД

DOC1  DOC2  CLIENT
ITCI  GG319  101
ITPS  YB311  102  
ITPT  GG319  101
ITPP  YB311  102

ВЫХОД

В целевой таблице должен быть CLIENT с уникальным ключом, и мне нужно добавить два столбца DOC1 и DOC2, взяв строку с DOC1 с наивысшим приоритетом.

CLIENT DOC2 DOC1
101   GG319 ITCI
102   YB311 ITPP

Я написал подпрограмму select single in end, но возникла синтаксическая ошибка:

Select single doc1  doc2 (W_doc1, W_doc2)
        FROM /BI0/Pdoctax
        WHERE  client eq <RESULT_FIELDS>-client. 

person Wafa El Maizi    schedule 25.07.2019    source источник
comment
В DOC2 сейчас нет правил, не могли бы вы рассказать нам, что вам нужно?   -  person András    schedule 26.07.2019


Ответы (4)


Поскольку ваш порядок приоритета от самого высокого до самого низкого полностью соответствует алфавитному порядку, вам не нужно ничего, кроме использования GROUP BY с агрегированием MIN:

SELECT client, MIN( doc2 ) AS doc2, MIN( doc1 ) AS doc1
INTO TABLE @DATA(itab)
FROM /BI0/Pdoctax
GROUP BY client.

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

person Suncatcher    schedule 25.07.2019
comment
Я думаю, что OP не хочет MIN (DOC2), ему нужно значение DOC2, которое соответствует строке, содержащей минимальное значение DOC1 для данного клиента. - person Sandra Rossi; 26.07.2019
comment
Не знаю, но результат выглядит именно так, как хотелось. Возможно, в более сложных цепочках приоритетов это не удастся, но в приведенном выше случае это работает. - person Suncatcher; 26.07.2019

Если я правильно понимаю, вы хотите, чтобы при выборе выводилась только одна строка для каждого КЛИЕНТА, выбирая строку из исходной таблицы на основе этих приоритетов DOC1.

Такой выбор невозможен.

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

  1. Вы можете выбрать все, ПРОВЕРИТЬ и создать свой формат с условиями ЕСЛИ и т. Д.

  2. Если у вас действительно есть только эти 4 возможности DOC1, вы можете выбрать все, отсортировать внутреннюю таблицу по КЛИЕНТУ и DOC1, а затем удалить смежные дубликаты, сравнивая только КЛИЕНТ. Это будет работать, потому что «ITCI> ITPP> ITPS> ITPT» находится в алфавитном порядке.

  3. Опять же, если у вас есть только эти 4 возможности DOC1, вы можете выбрать их друг за другом, проверяя между ними, есть ли еще КЛИЕНТЫ, которые отсутствуют.

person Legxis    schedule 25.07.2019
comment
привет, Легикс! «Если я правильно понимаю, вы хотите, чтобы при выборе выводилась только одна строка для каждого КЛИЕНТА, выбирая строку из исходной таблицы на основе этих приоритетов DOC1». «Да, я пытаюсь это сделать. Можете ли вы помочь мне с кодом, у меня есть 6 типов документов1 - person Wafa El Maizi; 25.07.2019

Поскольку ваши значения приоритета doc1 на самом деле шесть, это должно сработать.

SELECT b~client,
       coalesce( p1~doc1, p2~doc1, p3~doc1, p4~doc1, p5~doc1, p6~doc1 ),
       coalesce( p1~doc2, p2~doc2, p3~doc2, p4~doc2, p5~doc2, p6~doc2 )
  FROM /bi0/pdoctax AS b
                 LEFT OUTER JOIN /bi0/pdoctax AS p1
                 ON  p1~client = b~client
                 AND p1~doc1   = 'ITCI'
                 LEFT OUTER JOIN /bi0/pdoctax AS p2
                 ON  p2~client = b~client
                 AND p2~doc1   = 'ITPS'
                 LEFT OUTER JOIN /bi0/pdoctax AS p3
                 ON  p3~client = b~client
                 AND p3~doc1   = 'ITPT'
                 LEFT OUTER JOIN /bi0/pdoctax AS p4
                 ON  p4~client = b~client
                 AND p4~doc1   = 'ITPT'
                 LEFT OUTER JOIN /bi0/pdoctax AS p5
                 ON  p4~client = b~client
                 AND p4~doc1   = 'P5'
                 LEFT OUTER JOIN /bi0/pdoctax AS p6
                 ON  p4~client = b~client
                 AND p4~doc1   = 'P6'
  WHERE b~client = @<result_fields>-client
   INTO @DATA(ls_doctax).

Я предполагаю, что вы ищете ответ, который делает это в одном операторе SELECT, иначе вы можете выполнить цикл:

  DATA lt_priorities TYPE STANDARD TABLE OF /bi0/pdoctax-doc1.
  lt_priorities = VALUE #( ( 'ITCI' ) ( 'ITPS' ) ( 'ITPT' ) ( 'ITPP' ) ( 'P500' ) ( 'P600' ) ).

  SELECT b~client,
         doc1,
         doc2
    FROM /bi0/pdoctax AS b
   WHERE b~client = @<result_fields>-client
   ORDER BY doc1 ASCENDING
    INTO TABLE @DATA(lt_doctax).

  DATA ls_doctax_filtered LIKE LINE OF lt_doctax.

  LOOP AT lt_priorities ASSIGNING FIELD-SYMBOL(<fs_priority>).
    READ TABLE lt_doctax ASSIGNING FIELD-SYMBOL(<fs_doctax>)
      WITH KEY doc1 = <fs_priority> BINARY SEARCH.
    IF sy-subrc = 0.
      ls_doctax_filtered = <fs_doctax>.
*     --->
      EXIT.
    ENDIF.
  ENDLOOP.
person Pilot    schedule 26.07.2019

Вот «простое» решение с ABAP 7.52.

Я использовал другой пример для тестов, чтобы каждый мог с ним поиграть: я использовал демонстрационную таблицу SFLIGHT, которая предоставляется с любой установкой ABAP. Запустите программу SAPBC_DATA_GENERATOR, чтобы сгенерировать данные, если таблица пуста.

Как уже упоминалось другими людьми, предполагается, что ваш приоритет основан на алфавитном порядке, поэтому можно использовать агрегатную функцию MIN.

Приведенный ниже код получает строки SFLIGHT, которые соответствуют каждому отдельному значению столбца CARRID (эквивалентно CLIENT в вашем вопросе) и его минимальному значению в столбце PAYMENTSUM (DOC1) (оба внутри подзапроса EXISTS):

SELECT carrid, fldate AS doc2, paymentsum AS doc1
FROM sflight AS a
WHERE EXISTS (
        SELECT carrid
        FROM sflight
        WHERE carrid = a~carrid
        GROUP BY carrid
        HAVING MIN( paymentsum ) = a~paymentsum )
INTO TABLE @DATA(itab).

Содержимое таблицы базы данных SFLIGHT (через SE16 / ожидаемый результат выделен):  введите описание изображения здесь

Содержимое внутренней таблицы itab (через отладку / как ожидалось):  введите описание изображения здесь

Примечание о коде ABAP SQL:

  • Любой выбор результата агрегирования может быть выполнен только после HAVING, а не после WHERE (классическое правило SQL).
  • Если несколько строк SFLIGHT имеют одинаковые значения для CARRID и PAYMENTSUM, то одна из этих строк выбирается случайным образом (классическое правило SQL).
  • Он работает в ABAP 7.52, но может не работать в более старых версиях.
  • Это решение может быстро стать невозможным для будущих посетителей с более сложным запросом.
  • В "родном SQL" (прямое использование базы данных SQL) могут быть более простые решения, например, использование SELECT ... FROM ( SELECT ... ) (не разрешено до ABAP SQL 7.53)
person Sandra Rossi    schedule 26.07.2019