Отображать строки как столбцы в SQL

У меня есть таблица со следующей структурой и образцами данных:

ПРОДАВЕЦ ЗАКАЗ ДАТА ДОСТАВКИ ПРИМЕЧАНИЯ ПОЛЬЗОВАТЕЛЬ ПЕПСИ 1122 20 декабря 22 ОТКРЫТ Джон ПЕПСИ 1122 22 декабря 22 ЗАПРОШЕНО Мартин ПЕПСИ 1122 26 декабря 22 В ПРОЦЕССЕ Вятт ПЕПСИ 1122 10 января 23 ОТЛОЖЕННЫЙ Хабиб ПЕПСИ 1122 22 января 23 В ПУТИ Карен

Таблица может содержать разные ПОСТАВЩИКИ и ЗАКАЗЫ. Мне нужно отображать в одной строке данные для каждого заказа и поставщика. Так:

ПРОДАВЕЦ ЗАКАЗ DELIVERY_DATE_1 ПРИМЕЧАНИЯ_1 USER_1 DELIVERY_DATE_2 ПРИМЕЧАНИЯ_2 USER_2 ДОСТАВКА_DATE_3 ПРИМЕЧАНИЯ_3 USER_3 ПЕПСИ 1122 20 декабря 22 ОТКРЫТ Джон 22 декабря 22 ЗАПРОШЕНО Мартин 26 декабря 22 В ПРОЦЕССЕ Вятт

и т. д.

Я пробовал PIVOT, но он не работает:

SELECT VENDOR,
         order_number,
        -- delivery_date,
         pickup_date
         reasonf_of_delay,
         user_name
from table
PIVOT
(count(delivery_date)
 FOR order_number
 )

🤔 А знаете ли вы, что...
SQL позволяет создавать индексы на нескольких столбцах для оптимизации поиска данных.


2
55
4

Ответы:

Пожалуйста, прочтите документацию для Pivot. Например: https://oracle-base.com/articles/11g/pivot-and-unpivot-operators-11gr1

Если вы хотите выполнить поворот, вы должны знать, для каких значений, возвращаемых для столбца в строке, у вас будут разные столбцы. Используя простой SQL, а не динамический SQL, вы не можете иметь неопределенное количество столбцов. Я не очень понял, какие столбцы должен возвращать ваш SQL.


Решено

Вы можете построить что-то подобное со следующим:

CREATE TABLE VENDOR_ORDERS (
    VENDOR VARCHAR2(50),
    ORDER_NUMBER NUMBER,
    DELIVERY_DATE DATE,
    REMARKS VARCHAR2(50),
    USER_NAME VARCHAR2(50)
);

INSERT INTO VENDOR_ORDERS VALUES ('PEPSI', 1122, TO_DATE('20-DEC-2022', 'DD-MON-YYYY'), 'OPENED', 'John');
INSERT INTO VENDOR_ORDERS VALUES ('PEPSI', 1122, TO_DATE('22-DEC-2022', 'DD-MON-YYYY'), 'REQUESTED', 'Martin');
INSERT INTO VENDOR_ORDERS VALUES ('PEPSI', 1122, TO_DATE('26-DEC-2022', 'DD-MON-YYYY'), 'IN PROCESS', 'Wyatt');
INSERT INTO VENDOR_ORDERS VALUES ('PEPSI', 1122, TO_DATE('10-JAN-2023', 'DD-MON-YYYY'), 'DELAYED', 'Khabib');
INSERT INTO VENDOR_ORDERS VALUES ('PEPSI', 1122, TO_DATE('22-JAN-2023', 'DD-MON-YYYY'), 'IN TRANSIT', 'Karen');

SELECT *
FROM
(
     SELECT VENDOR
           ,ORDER_NUMBER
           ,DELIVERY_DATE
           ,REMARKS
           ,USER_NAME
           ,ROW_NUMBER() OVER (PARTITION BY VENDOR, ORDER_NUMBER ORDER BY DELIVERY_DATE ASC) AS  rn
     FROM VENDOR_ORDERS vo
) DS
PIVOT
(
     MAX(DELIVERY_DATE) AS DT, MAX(REMARKS) AS R, MAX(USER_NAME) AS UN FOR RN IN ('1', '2', '3', '4', '5')
) PVT 

Проблема в том, что в этом случае столбцы PIVOT статичны. Итак, вы можете добавить 10 или 20, что наиболее подходит для вашего случая, и иметь значение NULL, если таких записей не существует.


SELECT Vendor, 'Order 1' AS OrderNumber, 
   MAX(CASE WHEN RowNum = 1 THEN Delivery_Date END) AS Delivery_Date_1,
   MAX(CASE WHEN RowNum = 1 THEN Remarks END) AS Remarks_1,
   MAX(CASE WHEN RowNum = 1 THEN User END) AS User_1,
   MAX(CASE WHEN RowNum = 2 THEN Delivery_Date END) AS Delivery_Date_2,
   MAX(CASE WHEN RowNum = 2 THEN Remarks END) AS Remarks_2,
   MAX(CASE WHEN RowNum = 2 THEN User END) AS User_2,
   MAX(CASE WHEN RowNum = 3 THEN Delivery_Date END) AS Delivery_Date_3,
   MAX(CASE WHEN RowNum = 3 THEN Remarks END) AS Remarks_3,
   MAX(CASE WHEN RowNum = 3 THEN User END) AS User_3,
   MAX(CASE WHEN RowNum = 4 THEN Delivery_Date END) AS Delivery_Date_4,
   MAX(CASE WHEN RowNum = 4 THEN Remarks END) AS Remarks_4,
   MAX(CASE WHEN RowNum = 4 THEN User END) AS User_4,
   MAX(CASE WHEN RowNum = 5 THEN Delivery_Date END) AS Delivery_Date_5,
   MAX(CASE WHEN RowNum = 5 THEN Remarks END) AS Remarks_5,
   MAX(CASE WHEN RowNum = 5 THEN User END) AS User_5 FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY Vendor, Order ORDER BY Id) AS RowNum FROM [[your_table]]

) т ГДЕ Заказ = 1122 СГРУППИРОВАТЬ ПО ПРОДАВЦАМ

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


Самый простой способ сделать это — использовать предложение PIVOT, как вы начали. Но вам нужно добавить столько агрегированных показателей, сколько у вас есть столбцов (DELIVERY_DATE, REMARKS, USER#). Кроме того, вам необходимо ранжировать (номер_строки) все строки для ПОСТАВЩИКА, ЗАКАЗА № перед использованием предложения PIVOT, как показано ниже. Наконец, вы можете изменить псевдонимы, созданные предложением PIVOT для ваших столбцов в верхнем SELECT.

SELECT *
  FROM (
   SELECT T.*,
    ROW_NUMBER() OVER(PARTITION BY VENDOR, ORDER# ORDER BY DELIVERY_DATE, ROWNUM) RN
   FROM TAB_NAME T
) PIVOT(
  MAX(DELIVERY_DATE) AS DELIVERY_DATE
, MAX(REMARKS) AS REMARKS
, MAX(USER#) AS USER#
   FOR RN IN (1, 2, 3, 4, 5)
);

демо на db<>fiddle