Возврат нескольких значений в одной строке на основе значения в одной таблице - PullRequest
1 голос
/ 01 ноября 2011

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

У нас есть значения, например, APPLES. Каждое яблоко имеет свой серийный номер, SERIAL. для некоторых ПРИЛОЖЕНИЙ существует несколько (до 6) значений SERIAL.

ID      APPLE       SERIAL
2052    5035        1
2055    5035        4
2058    5035        8
2070    5040        5

В своих результатах я хочу вернуть каждый APPLE один раз и присвоить ему все серийные номера, например:

APPLE   SERIAL_1    SERIAL_2    SERIAL_3    SERIAL_4
5035    1           4           8
5040    5

Я попытался сделать запрос, который в основном объединяет одну и ту же таблицу 4 раза, указав serial_x not in (другие серийные номера). Проблема в том, что он даст несколько результатов, например:

APPLE   SERIAL_1    SERIAL_2    SERIAL_3    SERIAL_4
5035    1           4           8
5035    1           8           4
5035    4           1           8
5035    4           8           1
5035    8           1           4
5035    4           4           1
5040    5

Это очевидно, потому что apple 5035 с другим серийным номером встречается в таблице несколько раз, и он получает все возможные комбинации трех назначенных ему серийных номеров. Я уверен, что есть простой способ сделать это, но я пытался в течение долгого времени и не смог добиться хорошего результата. Кто-нибудь может помочь?

Ответы [ 5 ]

1 голос
/ 02 ноября 2011

Вы можете попробовать это, это не элегантно, но работает:

SELECT DISTINCT t1.apple, 
    (SELECT serial FROM your_table
     WHERE apple = t1.apple
     ORDER BY serial LIMIT 0,1) serial_1,
    (SELECT serial FROM your_table
     WHERE apple = t1.apple
     ORDER BY serial LIMIT 1,1) serial_2,
    (SELECT serial FROM your_table
     WHERE apple = t1.apple
     ORDER BY serial LIMIT 2,1) serial_3,
    (SELECT serial FROM your_table
     WHERE apple = t1.apple
     ORDER BY serial LIMIT 3,1) serial_4,
    (SELECT serial FROM your_table
     WHERE apple = t1.apple
     ORDER BY serial LIMIT 4,1) serial_5,
    (SELECT serial FROM your_table
     WHERE apple = t1.apple
     ORDER BY serial LIMIT 5,1) serial_6
FROM your_table t1
0 голосов
/ 11 июля 2013

Немного опоздал к игре, но, поскольку в Oracle нет ответа на вопрос об использовании предложения PIVOT, он, тем не менее, может быть интересным.

SELECT *
FROM (
  SELECT apple, serial
  FROM fruits
) t
PIVOT ( 
  max(serial) for serial in (1,2,3,4,5,6)
) 

Пример SQLFiddle: http://sqlfiddle.com/#!4/3cede/2

0 голосов
/ 02 ноября 2011

Я бы сделал что-то вроде этого:

with data as (
    select 2052 id, 5035 apple, 1 serial from dual union all
    select 2055 id, 5035 apple, 4 serial from dual union all
    select 2058 id, 5035 apple, 8 serial from dual union all
    select 2070 id, 5040 apple, 5 serial from dual
)
select
    apple,
    serial_1,
    serial_2,
    serial_3,
    serial_4,
    serial_5,
    serial_6
from (
    select
        apple,
        serial as serial_1,
        lead(serial,1) over (partition by apple order by serial) as serial_2,
        lead(serial,2) over (partition by apple order by serial) as serial_3,
        lead(serial,3) over (partition by apple order by serial) as serial_4,
        lead(serial,4) over (partition by apple order by serial) as serial_5,
        lead(serial,5) over (partition by apple order by serial) as serial_6,
        row_number() over (partition by apple order by serial) rn
    from data
)
where rn = 1;

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

Это даст следующий вывод:

 APPLE   SERIAL_1   SERIAL_2   SERIAL_3   SERIAL_4   SERIAL_5   SERIAL_6

  5035          1          4          8
  5040          5
0 голосов
/ 02 ноября 2011

Oracle 11g имеет функцию LISTAGG , которая, кажется, делает то, что вы ищете. У меня нет 11g здесь, но следующее должно быть близко:

SELECT apple, listagg(serial, ',') WITHIN GROUP (ORDER BY serial) "Serial Numbers"
  FROM tbl
 GROUP BY apple;

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

0 голосов
/ 02 ноября 2011

Вы можете попробовать использовать агрегатную функцию GROUP_CONCAT и GROUP BY APPLE

SELECT 
    a.APPLE,
    GROUP_CONCAT(DISTINCT s.SERIAL) AS serials
FROM 
    apples a
    LEFT JOIN apples s ON s.APPLE = a.APPLE
GROUP BY a.APPLE


Протестировано в MySQL:

mysql> select * from apples;
+------+-------+--------+
| ID   | APPLE | SERIAL |
+------+-------+--------+
| 2052 |  5035 |      1 |
| 2055 |  5035 |      4 |
| 2058 |  5035 |      8 |
| 2070 |  5040 |      5 |
+------+-------+--------+
4 rows in set (0.00 sec)

mysql> SELECT 
    ->     a.APPLE,
    ->     GROUP_CONCAT(DISTINCT s.SERIAL) AS serials
    -> FROM 
    ->     apples a
    ->     LEFT JOIN apples s ON s.APPLE = a.APPLE
    -> GROUP BY a.APPLE;
+-------+---------+
| APPLE | serials |
+-------+---------+
|  5035 | 1,4,8   |
|  5040 | 5       |
+-------+---------+
2 rows in set (0.00 sec)

mysql> 
...