Как добавить значение нескольких столбцов? - PullRequest
0 голосов
/ 29 июня 2018

Изображение таблицы в базе данных

Мне нужно запросить водителей, которые преодолели более 430 000 миль в период с января 2010 года по декабрь 2012 года. За что я пытаюсь

SELECT t.DRIVERID 
FROM BBI_BC.TRUCKS t
WHERE t.JAN_2010_MILES + t. FEB_2010_MILES + .....+ t.DEC_2012_MILES > 43000;

Ответы [ 3 ]

0 голосов
/ 29 июня 2018

Если значения могут содержать NULL значений, вам нужно будет использовать COALESCE или NVL:

SELECT DRIVERID 
FROM   BBI_BC.TRUCKS
WHERE  COALESCE( JAN_2010_MILES, 0)
     + COALESCE( FEB_2010_MILES, 0)
     + .....
     + COALESCE( DEC_2012_MILES, 0) > 430000;

Если вы хотите автоматически сгенерировать запрос, то:

SELECT 'SELECT DRIVERID 
FROM   BBI_BC.TRUCKS
WHERE  ' || LISTAGG( 'COALESCE( ' || TO_CHAR( ADD_MONTHS( DATE '2010-01-01', LEVEL - 1 ), 'MON_YYYY' ) || '_MILES, 0)', '
     + ' ) WITHIN GROUP ( ORDER BY LEVEL ) || ' > 430000;' AS sql
FROM   DUAL
CONNECT BY ADD_MONTHS( DATE '2010-01-01', LEVEL - 1 ) <= DATE '2012-12-01';

Какие выходы:

SELECT DRIVERID 
FROM   BBI_BC.TRUCKS
WHERE  COALESCE( JAN_2010_MILES, 0)
     + COALESCE( FEB_2010_MILES, 0)
     + COALESCE( MAR_2010_MILES, 0)
     + COALESCE( APR_2010_MILES, 0)
     + COALESCE( MAY_2010_MILES, 0)
     + COALESCE( JUN_2010_MILES, 0)
     + COALESCE( JUL_2010_MILES, 0)
     + COALESCE( AUG_2010_MILES, 0)
     + COALESCE( SEP_2010_MILES, 0)
     + COALESCE( OCT_2010_MILES, 0)
     + COALESCE( NOV_2010_MILES, 0)
     + COALESCE( DEC_2010_MILES, 0)
     + COALESCE( JAN_2011_MILES, 0)
     + COALESCE( FEB_2011_MILES, 0)
     + COALESCE( MAR_2011_MILES, 0)
     + COALESCE( APR_2011_MILES, 0)
     + COALESCE( MAY_2011_MILES, 0)
     + COALESCE( JUN_2011_MILES, 0)
     + COALESCE( JUL_2011_MILES, 0)
     + COALESCE( AUG_2011_MILES, 0)
     + COALESCE( SEP_2011_MILES, 0)
     + COALESCE( OCT_2011_MILES, 0)
     + COALESCE( NOV_2011_MILES, 0)
     + COALESCE( DEC_2011_MILES, 0)
     + COALESCE( JAN_2012_MILES, 0)
     + COALESCE( FEB_2012_MILES, 0)
     + COALESCE( MAR_2012_MILES, 0)
     + COALESCE( APR_2012_MILES, 0)
     + COALESCE( MAY_2012_MILES, 0)
     + COALESCE( JUN_2012_MILES, 0)
     + COALESCE( JUL_2012_MILES, 0)
     + COALESCE( AUG_2012_MILES, 0)
     + COALESCE( SEP_2012_MILES, 0)
     + COALESCE( OCT_2012_MILES, 0)
     + COALESCE( NOV_2012_MILES, 0)
     + COALESCE( DEC_2012_MILES, 0) > 430000;
0 голосов
/ 29 июня 2018

Это решение похоже на APC, но возвращает результат динамически. (работает на 12с +)

DECLARE
    miles_cond   VARCHAR2(20) := ' > 43000';
    v_where      VARCHAR2(1000);
    x            SYS_REFCURSOR;
BEGIN
    SELECT
        ' WHERE '
        ||
            LISTAGG(column_name,' + ') WITHIN GROUP(
                ORDER BY
                    column_name
            )
        || miles_cond
    INTO v_where
    FROM
        all_tab_columns
    WHERE
        owner = 'BBI_BC'
        AND table_name = 'TRUCKS'
        AND REGEXP_LIKE ( column_name,
                          '201[0-2]_MILES' )
    ORDER BY
        column_id;

    OPEN x FOR 'SELECT * FROM TRUCKS' || v_where;

    dbms_sql.return_result(x);
END;
/

И, конечно, вы можете добавить аналогичную логику, например, MT0, для обработки нулей.

0 голосов
/ 29 июня 2018

Итак, вопрос в том, как избежать ввода всех этих столбцов в предложении WHERE. Ответ: ты не можешь. Разработчик этой таблицы решил игнорировать общепринятые отраслевые стандартные правила нормализации базы данных. Узнайте больше. Почему они это сделали, не имеет значения: в результате каждый, кто запрашивает таблицу, должен писать утомительные и сложные в обслуживании запросы.

Существует возможность динамической генерации запроса: запустите этот запрос, а затем вставьте вывод в строку WHERE:

select ' + t.' || column_name
from all_tab_columns
where owner = 'BBI_BC'
and table_name = 'TRUCKS'
and (column_name like '%2010_MILES'
     or column_name like '%2011_MILES'
     or column_name like '%2012_MILES')
order by column_id;

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

Даже то, как столбцы таблицы были названы, плохое: было бы лучше, если бы они были названы MILES_2010_01, MILES_2010_02 и т. Д., Потому что по крайней мере тогда вы могли бы написать динамический запрос как

where column_name between 'MILES_2010_01' and 'MILES_2012_12'

С правильно смоделированной таблицей, то есть с записями за каждый месяц и двумя столбцами для MONTHLY_MILES и MONTHLY_GAS, запрос будет выглядеть так:

SELECT t.DRIVERID 
FROM BBI_BC.TRUCKS t
WHERE t.year between 2010 and 2012
group by t.driverid having sum(t.monthly_miles) >43000
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...