Oracle Минус запрос. Как получить результат с NULLS, если верхний SQL и нижний SQL не содержат NULL? - PullRequest
5 голосов
/ 02 июня 2010

Как мог этот SQL ...

CREATE TABLE NewTable AS
    SELECT A,B,C FROM Table1
    minus
    SELECT A, B, C From Table2

... создать новую таблицу со значениями NULL в столбце A когда ни в Table1, ни в Table2 значения NULL не указаны в столбце A?

Но с другой стороны, этот SQL ...

SELECT * FROM
(
   SELECT A,B,C FROM Table1
    minus
    SELECT A, B, C From Table2
) 
WHERE A IS NULL 

не возвращать строк!

Это кажется противоречивым!

Я думаю, что это ошибка в Oracle.

Конечно, настоящий SQL гораздо сложнее, но я считаю, что это точно иллюстрирует природу проблемы.

UPDATE

Вот АКТУАЛЬНЫЙ SQL:

Я выполнил это утверждение:

CREATE TABLE MyMinus
AS
select 
*
FROM
---begin main query 
(
SELECT expenditure_item_date, expenditure_org, expenditure_type,
       f_amount_billed, f_amount_billed_fc, f_amount_billed_us,
       f_bl_creation_date, f_catalog_source, f_catalog_type, f_company,
       f_company_code, f_cost_center_num, f_cuic, f_currency_code,
       f_destination_type_code, f_distribution_id, f_distribution_num,
       f_exchange_rate, f_extract_date, f_gl_account,
       f_isms_jamis_project_num, f_line_id, f_local_use, f_location_num,
       f_need_by_date, f_org_id, f_po_line_num, f_po_num, f_po_release_num,
       f_project, f_project_num, f_promised_date, f_quantity_billed,
       f_quantity_cancelled, f_quantity_delivered, f_quantity_ordered,
       f_rel_approved_flag, f_rel_cancelled_flag, f_rel_cancel_date,
       f_rel_closed_code, f_rel_hold_flag, f_rel_revision_num, f_task_num
  FROM dw_mgr.po_distributions_curr_fct a
 WHERE EXISTS (
          SELECT 1
            FROM dw_mgr.po_distributions_curr_fct b,
                 dw_mgr.po_lines_curr_fct,
                 dw_mgr.po_header_curr_fct
           WHERE a.ROWID = b.ROWID
             AND b.f_cuic = dw_mgr.po_lines_curr_fct.f_cuic
             AND b.f_line_id = dw_mgr.po_lines_curr_fct.f_line_id
             AND dw_mgr.po_lines_curr_fct.f_cuic =
                                              dw_mgr.po_header_curr_fct.f_cuic
             AND dw_mgr.po_lines_curr_fct.f_header_id =
                                         dw_mgr.po_header_curr_fct.f_header_id
             AND dw_mgr.po_header_curr_fct.f_header_creation_date <
                                      ADD_MONTHS (TRUNC (SYSDATE, 'YEAR'),
                                                  -48)
             AND dw_mgr.po_header_curr_fct.f_po_status IN
                                                 ('CLOSED', 'FINALLY CLOSED'))

MINUS 

SELECT expenditure_item_date, expenditure_org, expenditure_type,
       f_amount_billed, f_amount_billed_fc, f_amount_billed_us,
       f_bl_creation_date, f_catalog_source, f_catalog_type, f_company,
       f_company_code, f_cost_center_num, f_cuic, f_currency_code,
       f_destination_type_code, f_distribution_id, f_distribution_num,
       f_exchange_rate, f_extract_date, f_gl_account,
       f_isms_jamis_project_num, f_line_id, f_local_use, f_location_num,
       f_need_by_date, f_org_id, f_po_line_num, f_po_num, f_po_release_num,
       f_project, f_project_num, f_promised_date, f_quantity_billed,
       f_quantity_cancelled, f_quantity_delivered, f_quantity_ordered,
       f_rel_approved_flag, f_rel_cancelled_flag, f_rel_cancel_date,
       f_rel_closed_code, f_rel_hold_flag, f_rel_revision_num, f_task_num
  FROM arch_fct.po_distributions_curr_fct a
 WHERE EXISTS (
          SELECT 1
            FROM arch_fct.po_distributions_curr_fct b,
                 arch_fct.po_lines_curr_fct,
                 arch_fct.po_header_curr_fct
           WHERE a.ROWID = b.ROWID
             AND b.f_cuic = arch_fct.po_lines_curr_fct.f_cuic
             AND b.f_line_id = arch_fct.po_lines_curr_fct.f_line_id
             AND arch_fct.po_lines_curr_fct.f_cuic =
                                            arch_fct.po_header_curr_fct.f_cuic
             AND arch_fct.po_lines_curr_fct.f_header_id =
                                       arch_fct.po_header_curr_fct.f_header_id
             AND arch_fct.po_header_curr_fct.f_header_creation_date <
                                      ADD_MONTHS (TRUNC (SYSDATE, 'YEAR'),
                                                  -48)
             AND arch_fct.po_header_curr_fct.f_po_status IN
                                                 ('CLOSED', 'FINALLY CLOSED'))

) 

А потом это. Обратите внимание, что строки с NULL-значениями F_DISTRIBUTION_ID были вставлены в созданную таблицу.

SELECT COUNT(*) from MyMinus WHERE F_DISTRIBUTION_ID IS NULL

- 17 строк

И все же, когда я выполню это:

select 
*
FROM
---begin main query 
(
SELECT expenditure_item_date, expenditure_org, expenditure_type,
       f_amount_billed, f_amount_billed_fc, f_amount_billed_us,
       f_bl_creation_date, f_catalog_source, f_catalog_type, f_company,
       f_company_code, f_cost_center_num, f_cuic, f_currency_code,
       f_destination_type_code, f_distribution_id, f_distribution_num,
       f_exchange_rate, f_extract_date, f_gl_account,
       f_isms_jamis_project_num, f_line_id, f_local_use, f_location_num,
       f_need_by_date, f_org_id, f_po_line_num, f_po_num, f_po_release_num,
       f_project, f_project_num, f_promised_date, f_quantity_billed,
       f_quantity_cancelled, f_quantity_delivered, f_quantity_ordered,
       f_rel_approved_flag, f_rel_cancelled_flag, f_rel_cancel_date,
       f_rel_closed_code, f_rel_hold_flag, f_rel_revision_num, f_task_num
  FROM dw_mgr.po_distributions_curr_fct a
 WHERE EXISTS (
          SELECT 1
            FROM dw_mgr.po_distributions_curr_fct b,
                 dw_mgr.po_lines_curr_fct,
                 dw_mgr.po_header_curr_fct
           WHERE a.ROWID = b.ROWID
             AND b.f_cuic = dw_mgr.po_lines_curr_fct.f_cuic
             AND b.f_line_id = dw_mgr.po_lines_curr_fct.f_line_id
             AND dw_mgr.po_lines_curr_fct.f_cuic =
                                              dw_mgr.po_header_curr_fct.f_cuic
             AND dw_mgr.po_lines_curr_fct.f_header_id =
                                         dw_mgr.po_header_curr_fct.f_header_id
             AND dw_mgr.po_header_curr_fct.f_header_creation_date <
                                      ADD_MONTHS (TRUNC (SYSDATE, 'YEAR'),
                                                  -48)
             AND dw_mgr.po_header_curr_fct.f_po_status IN
                                                 ('CLOSED', 'FINALLY CLOSED'))

MINUS 

SELECT expenditure_item_date, expenditure_org, expenditure_type,
       f_amount_billed, f_amount_billed_fc, f_amount_billed_us,
       f_bl_creation_date, f_catalog_source, f_catalog_type, f_company,
       f_company_code, f_cost_center_num, f_cuic, f_currency_code,
       f_destination_type_code, f_distribution_id, f_distribution_num,
       f_exchange_rate, f_extract_date, f_gl_account,
       f_isms_jamis_project_num, f_line_id, f_local_use, f_location_num,
       f_need_by_date, f_org_id, f_po_line_num, f_po_num, f_po_release_num,
       f_project, f_project_num, f_promised_date, f_quantity_billed,
       f_quantity_cancelled, f_quantity_delivered, f_quantity_ordered,
       f_rel_approved_flag, f_rel_cancelled_flag, f_rel_cancel_date,
       f_rel_closed_code, f_rel_hold_flag, f_rel_revision_num, f_task_num
  FROM arch_fct.po_distributions_curr_fct a
 WHERE EXISTS (
          SELECT 1
            FROM arch_fct.po_distributions_curr_fct b,
                 arch_fct.po_lines_curr_fct,
                 arch_fct.po_header_curr_fct
           WHERE a.ROWID = b.ROWID
             AND b.f_cuic = arch_fct.po_lines_curr_fct.f_cuic
             AND b.f_line_id = arch_fct.po_lines_curr_fct.f_line_id
             AND arch_fct.po_lines_curr_fct.f_cuic =
                                            arch_fct.po_header_curr_fct.f_cuic
             AND arch_fct.po_lines_curr_fct.f_header_id =
                                       arch_fct.po_header_curr_fct.f_header_id
             AND arch_fct.po_header_curr_fct.f_header_creation_date <
                                      ADD_MONTHS (TRUNC (SYSDATE, 'YEAR'),
                                                  -48)
             AND arch_fct.po_header_curr_fct.f_po_status IN
                                                 ('CLOSED', 'FINALLY CLOSED'))

) 
WHERE

f_distribution_id is null

Я получаю 0 строк.

Почему при вставке записей во временную таблицу появляются строки с идентификаторами NULL DIST?

Этот минус SQL-запрос, который динамически генерировался пользовательской программой архивирования данных, пытается проверить, что данные, которые СЛЕДУЕТ архивировать в схеме DW_MGR, действительно были скопированы в схему ARCH_FCT (архив). Он возвращает различия, которые включали 17 записей, в которых F_DISTRIBUTION_ID в временной таблице MyMinus не совпадают с данными в исходной таблице DW_MG.PO_DISTRIBUTIONS_CURR_FCT, поскольку они имеют значение NULL. Следовательно, процесс архивирования является разработкой, когда различия найдены. Вопрос заключается в том, почему существуют различия, т. Е. Как значения NULL попадают в таблицу MyMinus, когда их нет в таблице SOURCE PO_DISTRIBUTIONS_CURR_FCT?

РЕДАКТИРОВАТЬ:

Может ли кто-нибудь с доступом к Oracle META опубликовать информацию о следующих ошибках Oracle. Меня направили к ним, но по контракту я нашел кого-то из моих сотрудников, который может сказать мне, что такое ID # нашей поддержки. Я узнаю в конце концов, но было бы неплохо узнать раньше. Если вы не хотите публиковать его, рассмотрите следующие ссылки на ошибки в качестве потенциально связанной информации по моему вопросу:

Bug 8209309: MINUS IS SHOWING DIFFERENCES WITH CTAS + INSERT 
Bug 7834950: WRONG RESULTS WITH MINUS OPERATOR

Ответы [ 6 ]

4 голосов
/ 08 июня 2010

Перестань ломать отбивные. Это ошибка Oracle. Я докажу это тебе:

Прежде всего, это должен быть первый SQL, который возвращает NULLS для идентификатора DISTRIBUTION, поэтому выделите этот SQL и назовем его «SQL1».

ОК, давайте для упрощения обсудим SQL1 и скажем, что он имеет такой формат:

CREATE TABLE TempTable AS 
SELECT
   F_DISTRIBUTION_ID,
   FIELD2,
   FIELD3,...FIELD99

FROM WHATEVER 
WHERE WHATEVER

Затем вы обнаруживаете, что когда вы выполняете это, вы находите строки, которые имеют NULL DIST ID:

SELECT COUNT(*) FROM TempTable WHERE F_DISTRIBUTION_ID IS NULL
--Some positive number of rows returned.

Если бы Oracle не был дерьмом, вы могли бы изменить количество выбранных полей таким образом, чтобы был выбран только F_DISTRIBUTION_ID, и вы получили бы тот же результат, когда подсчитали количество строк со значением NULL F_DISTRIBUTION_ID, верно? Правильно! Но это не так, потому что Оракул ненадежный динозавр.

Попробуйте это:

CREATE TABLE TempTable AS 
SELECT
   F_DISTRIBUTION_ID
FROM WHATEVER 
WHERE WHATEVER

SELECT COUNT(*) FROM TempTable WHERE F_DISTRIBUTION_ID IS NULL

Ставлю доллары на пончики, которые возвращают 0 строк.

Теперь позвоните в Microsoft и скажите, что вы хотите перейти на SQL Server 2008 R2.

2 голосов
/ 06 июня 2010

Во-первых, я бы избавился от присоединения ROWID к ROWID. Затем я получу уникальные псевдонимы таблицы (без повторного использования «a» и «b» в запросе выше MINUS и в запросе ниже MINUS).

Наконец, я посмотрю на эти 17 строк и попытаюсь найти соответствующие записи в "dw_mgr.po_distributions_curr_fct" и посмотрим, используя DUMP (F_DISTRIBUTION_ID), где в значениях столбцов есть что-то странное

1 голос
/ 10 сентября 2010

Возможно, у меня возникла проблема, которая возникла как проблема с MINUS при использовании множества сложных представлений и существует. Я сузил его до возможной проблемы с оптимизатором - вы можете обойти его, не давая оптимизатору возиться с вещами, основанными на «F_DISTRIBUTION_ID IS NULL», используя что-то вроде «upper (F_DISTRIBUTION_ID) IS NULL».

В этих случаях почти невозможно создать упрощенный контрольный пример для отчета об ошибке - скорее всего, это происходит только в очень специфических сценариях (в отличие от того, что МИНУС будет полностью сломан). С моей проблемой я вообще не смог уменьшить запрос, и он по-прежнему возникает.

К вашему сведению, мой вопрос был запросом, который в основном объединял кучу вещей в исходную таблицу, называемую Employee. У меня было предложение where по первичному ключу Employee - если бы я сделал where EmployeeId = foo, он бы возвратил дополнительную строку с пустыми значениями там, где их не должно быть (столбцы из таблицы, в которой было внутреннее соединение) - если бы я это сделал где upper (EmployeeId) = foo, тогда я получу правильный результат. Очевидно, что значение EmployeeId было получено из одной и той же ячейки во всех строках, соответствующих предикату, так что это была явно ошибка.

1 голос
/ 07 июня 2010

Единственный способ, которым я могу думать, что F_DISTRIBUTION_ID может быть NULL при вставке в MyMinus, был бы, если он каким-либо образом возвращает NULL, каким-то образом в первом запросе.

Чтобы воспроизвести это (на 9i и 10g):

SQL> INSERT INTO table1 VALUES (NULL, 2, 3);

1 row created.

SQL> INSERT INTO table2 VALUES (1, 2, 3);

1 row created.

SQL> SELECT * 
  2  FROM (
  3    SELECT a, b, c FROM table1
  4    MINUS
  5    SELECT a, b, c FROM table2);

         A          B          C
---------- ---------- ----------
                    2          3

Однако, что касается запроса, который не возвращает строк при запуске сам по себе ... это нечто другое. Ошибка меня не удивит ... но ты пытался убрать эти СУЩЕСТВУЮЩИЕ? Конечно, есть много разных подходов, но, возможно, все эти подзапросы вызывают что-то забавное в памяти.

Например:

SELECT expenditure_item_date, expenditure_org, expenditure_type,
       f_amount_billed, f_amount_billed_fc, f_amount_billed_us,
       f_bl_creation_date, f_catalog_source, f_catalog_type, f_company,
       f_company_code, f_cost_center_num, f_cuic, f_currency_code,
       f_destination_type_code, f_distribution_id, f_distribution_num,
       f_exchange_rate, f_extract_date, f_gl_account,
       f_isms_jamis_project_num, f_line_id, f_local_use, f_location_num,
       f_need_by_date, f_org_id, f_po_line_num, f_po_num, f_po_release_num,
       f_project, f_project_num, f_promised_date, f_quantity_billed,
       f_quantity_cancelled, f_quantity_delivered, f_quantity_ordered,
       f_rel_approved_flag, f_rel_cancelled_flag, f_rel_cancel_date,
       f_rel_closed_code, f_rel_hold_flag, f_rel_revision_num, f_task_num
  FROM dw_mgr.po_distributions_curr_fct a
       dw_mgr.po_lines_curr_fct,
       dw_mgr.po_header_curr_fct
  WHERE a.f_cuic = dw_mgr.po_lines_curr_fct.f_cuic
    AND a.f_line_id = dw_mgr.po_lines_curr_fct.f_line_id
    AND dw_mgr.po_lines_curr_fct.f_cuic = dw_mgr.po_header_curr_fct.f_cuic
    AND dw_mgr.po_lines_curr_fct.f_header_id = dw_mgr.po_header_curr_fct.f_header_id
    AND dw_mgr.po_header_curr_fct.f_header_creation_date < ADD_MONTHS (TRUNC (SYSDATE, 'YEAR'), -48)
    AND dw_mgr.po_header_curr_fct.f_po_status IN ('CLOSED', 'FINALLY CLOSED')
MINUS 
SELECT expenditure_item_date, expenditure_org, expenditure_type,
       f_amount_billed, f_amount_billed_fc, f_amount_billed_us,
       f_bl_creation_date, f_catalog_source, f_catalog_type, f_company,
       f_company_code, f_cost_center_num, f_cuic, f_currency_code,
       f_destination_type_code, f_distribution_id, f_distribution_num,
       f_exchange_rate, f_extract_date, f_gl_account,
       f_isms_jamis_project_num, f_line_id, f_local_use, f_location_num,
       f_need_by_date, f_org_id, f_po_line_num, f_po_num, f_po_release_num,
       f_project, f_project_num, f_promised_date, f_quantity_billed,
       f_quantity_cancelled, f_quantity_delivered, f_quantity_ordered,
       f_rel_approved_flag, f_rel_cancelled_flag, f_rel_cancel_date,
       f_rel_closed_code, f_rel_hold_flag, f_rel_revision_num, f_task_num
  FROM arch_fct.po_distributions_curr_fct a,
       arch_fct.po_lines_curr_fct,
       arch_fct.po_header_curr_fct
 WHERE a.f_cuic = arch_fct.po_lines_curr_fct.f_cuic
   AND a.f_line_id = arch_fct.po_lines_curr_fct.f_line_id
   AND arch_fct.po_lines_curr_fct.f_cuic = arch_fct.po_header_curr_fct.f_cuic
   AND arch_fct.po_lines_curr_fct.f_header_id = arch_fct.po_header_curr_fct.f_header_id
   AND arch_fct.po_header_curr_fct.f_header_creation_date < ADD_MONTHS (TRUNC (SYSDATE, 'YEAR'), -48)
   AND arch_fct.po_header_curr_fct.f_po_status IN ('CLOSED', 'FINALLY CLOSED')   
1 голос
/ 05 июня 2010

Как правило, не должно.

Единственный раз, когда это возможно, если у вас есть некоторые расширенные функции безопасности (детальный контроль доступа), когда оптимизатор может видеть, что A не может быть нулевым в table1 / table2, поэтому возвращает ноль строк, но FGAC включает, чтобы остановить вас увидеть фактические значения в столбце, возвращая ноль.


EDIT. «В режиме маскирования столбцов [Virtual Private Database] отображаются все строки, даже те, которые ссылаются на чувствительные столбцы. Однако конфиденциальные столбцы отображаются в виде значений NULL.»

http://download.oracle.com/docs/cd/E11882_01/network.112/e10574/vpd.htm#i1014682

0 голосов
/ 27 мая 2011

Я только что столкнулся с той же ошибкой.и создайте условие if else для получения этих значений: D

таблица 1

A      !      B

null          35

условие 'if else': P

select 
Case
WHEN  a."Add" >= '0' THEN to_number(a."Add" - b."Cease" )

ELSE (b."Cease")*-1
End  as "X"
from table 1

Ответ

-35

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...