2016-04-08 1 views
0

нужна помощь со сложным запросом. Это выдержка из моего стола:Oracle XE, подсчет и отображение различных комбинаций строк на основе одного столбца

USERID SERVICE 
1   A 
1   B 
2   A 
3   A 
3   B 
4   A 
4   C 
5   A 
6   A 
7   A 
7   B 

Хорошо, я хотел бы запрос, чтобы вернуться и отобразить все возможные комбинации, которые существуют в моей таблице с их подсчетами, основанных на колонке SERVICE. Например, у первого пользователя есть служба A и B, это одна комбинация, которая произошла один раз. Следующий пользователь имеет только службу A, это еще одна комбинация, которая произошла один раз. Третий пользователь имеет услугу А и В, это произошло когда-то уже и счет для этой комбинации 2 в настоящее время, и т.д. Так что мой выход на основе этого конкретного входа будет таблица, как это:

A AB AC ABC B BC 
3 3 1 0 0 0 

Так уточнить немного больше, если есть 3 услуги, то есть 3! возможные комбинации; 3x2x1 = 6, и они A, B, C, AB, AC, BC и ABC. И моя таблица должна содержать количество пользователей, которым присвоена эта комбинация услуг.

Я пытался строить матрицу, используя этот запрос, а затем получить все отсчеты с помощью функции CUBE:

select service_A, service_B, service_C from 
    (select USERID, 
    max(case when SERVICE =A then 1 else null end) service_A, 
    max(case when SERVICE =B then 1 else null end) service_B, 
    max(case when SERVICE =C then 1 else null end) service_C 
    from SOME_TABLE) 
group by CUBE(service_A, service_B,service_C); 

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

+0

У вас множество возможных комбинаций? то есть, знаете ли вы заранее, сколько столбцов будет возвращено вашему запросу? Если нет, вы не можете сделать это с помощью простого запроса, но вам нужно что-то динамическое (и тогда его будет сложно обработать набор результатов с неизвестным числом столбцов) – Aleksej

+0

Я знаю, какие службы доступны, например, есть 10 услуги, которые человек может иметь. Так что можно сделать расчет и найти, что есть 10! количество различных комбинаций услуг, что является огромным числом. Таким образом, это будет максимальное количество столбцов. Но у большинства из них будет счет 0, проблема в том, что я не знаю, какие из них мне нужны, чтобы рассчитать все. – Hrvoje85

ответ

2

Не выводить его как динамические столбцы (это сложно сделать без использования PL/SQL и динамического SQL), но выводить его как строки вместо этого (если у вас есть интерфейс, то он обычно может переводить строки в столбцы много проще, чем оракула может):

Oracle Setup:

CREATE TABLE some_table (USERID, SERVICE) AS 
SELECT 1, 'A' FROM DUAL UNION ALL 
SELECT 1, 'B' FROM DUAL UNION ALL 
SELECT 2, 'A' FROM DUAL UNION ALL 
SELECT 3, 'A' FROM DUAL UNION ALL 
SELECT 3, 'B' FROM DUAL UNION ALL 
SELECT 4, 'A' FROM DUAL UNION ALL 
SELECT 4, 'C' FROM DUAL UNION ALL 
SELECT 5, 'A' FROM DUAL UNION ALL 
SELECT 6, 'A' FROM DUAL UNION ALL 
SELECT 7, 'A' FROM DUAL UNION ALL 
SELECT 7, 'B' FROM DUAL; 

Запрос:

SELECT service, 
     COUNT(userid) AS num_users 
FROM (
    SELECT userid, 
     LISTAGG(service) WITHIN GROUP (ORDER BY service) AS service 
    FROM some_table 
    GROUP BY userid 
) 
GROUP BY service; 

Выход:

SERVICE NUM_USERS 
------- ---------- 
AC    1 
A    3 
AB    3 

PL/SQL для динамических столбцов:

VARIABLE cur REFCURSOR; 

DECLARE 
    TYPE string_table IS TABLE OF VARCHAR2(4000); 
    TYPE int_table IS TABLE OF INT; 
    t_services string_table; 
    t_counts int_table; 
    p_sql  CLOB; 
BEGIN 
    SELECT service, 
     COUNT(userid) AS num_users 
    BULK COLLECT INTO t_services, t_counts 
    FROM (
    SELECT userid, 
      CAST(LISTAGG(service) WITHIN GROUP (ORDER BY service) AS VARCHAR2(2)) AS service 
    FROM some_table 
    GROUP BY userid 
) 
    GROUP BY service; 

    p_sql := EMPTY_CLOB() || 'SELECT '; 
    p_sql := p_sql || t_counts(1) || ' AS "' || t_services(1) || '"'; 
    FOR i IN 2 .. t_services.COUNT LOOP 
    p_sql := p_sql || ', ' || t_counts(i) || ' AS "' || t_services(i) || '"'; 
    END LOOP; 
    p_sql := p_sql || ' FROM DUAL'; 

    OPEN :cur FOR p_sql; 
END; 
/

PRINT cur; 

Выходные:

AC A AB 
--- --- --- 
1 3 3 
+0

Ничего себе, спасибо за быстрый и точный ответ, это именно то, что я хотел !!!! – Hrvoje85

Смежные вопросы