Oracle implicit conversion depends on concatenated tables or views

I am facing some strange problem. The request itself is huge, so I won't post it here (I could post it in case someone needs to see it). I now have a table, TABLE1, with a CHAR (1) column, COL1. This table column is being queried as part of my query. When I filter the recordset for this column, I say:

WHERE TAB1.COL1=1

      

Thus, the query is executed and returns a very large set of results. I recently updated one of the subqueries to speed up the query. But after that when I write WHERE TAB1.COL1 = 1 it returns nothing, but if I change it to WHERE TAB1.COL1 = '1' it gives me the records I want. Note the WHERE clause with and without quotes. So to make it clearer, I didn't have to put quotes to check the COL1 value before updating one of the subqueries, but after updating I need to. What feature of Oracle is that I am not aware of?

EDIT: I am posting two versions of the request in case someone can find it useful

Version 1:

SELECT p.ssn,
  pss.pin,
  pd.doc_number,
  p.surname,
  p.name,
  p.patronymic,
  to_number(p.sex, '9') as sex,
  citiz_c.short_name citizenship,
  p.birth_place,
  p.birth_day as birth_date,
  coun_c.short_name as country,
  di.name as leg_city,
  trim( pa.settlement
  || ' '
  || pa.street) AS leg_street,
  pd.issue_date,
  pd.issuing_body,
  irs.irn,
  irs.tpn,
  irs.reg_office,
  to_number(irs.insurer_type, '9') as insurer_type,
  TO_CHAR(sa.REG_CODE)
  ||CONVERT_INT_TO_DOUBLE_LETTER(TO_NUMBER(SUBSTR(TO_CHAR(sa.DOSSIER_NR, '0999999'), 2, 3)))
  ||SUBSTR(TO_CHAR(sa.DOSSIER_NR, '0999999'), 5, 4) CONVERTED_SSN_DOSSIER_NR,
  fa.snr
FROM
  (SELECT pss_t.pin,
    pss_t.ssn
  FROM EHDIS_INSURANCE.pin_ssn_status pss_t
  WHERE pss_t.difference_status < 5
  ) pss
INNER JOIN SSPF_CENTRE.file_archive fa
ON fa.ssn = pss.ssn
INNER JOIN SSPF_CENTRE.persons p
ON p.ssn = fa.ssn
INNER JOIN
  (SELECT pd_2.ssn,
    pd_2.type,
    pd_2.series,
    pd_2.doc_number,
    pd_2.issue_date,
    pd_2.issuing_body
  FROM

--The changed subquery starts here
    (SELECT ssn,
      MIN(type) AS type
    FROM SSPF_CENTRE.person_documents
    GROUP BY ssn
    ) pd_1
  INNER JOIN SSPF_CENTRE.person_documents pd_2
  ON pd_2.type       = pd_1.type
  AND pd_2.ssn       = pd_1.ssn
  ) pd
--The changed subquery ends here


ON pd.ssn = p.ssn
INNER JOIN SSPF_CENTRE.ssn_archive sa
ON p.ssn = sa.ssn
INNER JOIN SSPF_CENTRE.person_addresses pa
ON p.ssn = pa.ssn
INNER JOIN
  (SELECT i_t.irn,
    irs_t.ssn,
    i_t.tpn,
    i_t.reg_office,
    (
    CASE i_t.insurer_type
      WHEN '4'
      THEN '1'
      ELSE i_t.insurer_type
    END) AS insurer_type
  FROM sspf_centre.irn_registered_ssn irs_t
  INNER JOIN SSPF_CENTRE.insurers i_t
  ON i_t.irn                   = irs_t.new_irn
  OR i_t.old_irn               = irs_t.old_irn
  WHERE irs_t.is_registration IS NOT NULL
  AND i_t.is_real             IS NOT NULL
  ) irs ON irs.ssn             = p.ssn
LEFT OUTER JOIN SSPF_CENTRE.districts di
ON di.code = pa.city
LEFT OUTER JOIN SSPF_CENTRE.countries citiz_c
ON p.citizenship = citiz_c.numeric_code
LEFT OUTER JOIN SSPF_CENTRE.countries coun_c
ON pa.country_code  = coun_c.numeric_code
WHERE pa.address_flag = '1'--Here the column value with quotes
AND fa.form_type    = 'Q3';

      

And version 2:

SELECT p.ssn,
  pss.pin,
  pd.doc_number,
  p.surname,
  p.name,
  p.patronymic,
  to_number(p.sex, '9') as sex,
  citiz_c.short_name citizenship,
  p.birth_place,
  p.birth_day as birth_date,
  coun_c.short_name as country,
  di.name as leg_city,
  trim( pa.settlement
  || ' '
  || pa.street) AS leg_street,
  pd.issue_date,
  pd.issuing_body,
  irs.irn,
  irs.tpn,
  irs.reg_office,
  to_number(irs.insurer_type, '9') as insurer_type,
  TO_CHAR(sa.REG_CODE)
  ||CONVERT_INT_TO_DOUBLE_LETTER(TO_NUMBER(SUBSTR(TO_CHAR(sa.DOSSIER_NR, '0999999'), 2, 3)))
  ||SUBSTR(TO_CHAR(sa.DOSSIER_NR, '0999999'), 5, 4) CONVERTED_SSN_DOSSIER_NR,
  fa.snr
FROM
  (SELECT pss_t.pin,
    pss_t.ssn
  FROM EHDIS_INSURANCE.pin_ssn_status pss_t
  WHERE pss_t.difference_status < 5
  ) pss
INNER JOIN SSPF_CENTRE.file_archive fa
ON fa.ssn = pss.ssn
INNER JOIN SSPF_CENTRE.persons p
ON p.ssn = fa.ssn
INNER JOIN

 --The changed subquery starts here
 (SELECT ssn,
    type,
    series,
    doc_number,
    issue_date,
    issuing_body
  FROM
    (SELECT ssn,
      type,
      series,
      doc_number,
      issue_date,
      issuing_body,
      ROW_NUMBER() OVER (partition BY ssn order by type) rn
    FROM SSPF_CENTRE.person_documents
    )
  WHERE rn = 1
  ) pd --
 --The changed subquery ends here

ON pd.ssn = p.ssn
INNER JOIN SSPF_CENTRE.ssn_archive sa
ON p.ssn = sa.ssn
INNER JOIN SSPF_CENTRE.person_addresses pa
ON p.ssn = pa.ssn
INNER JOIN
  (SELECT i_t.irn,
    irs_t.ssn,
    i_t.tpn,
    i_t.reg_office,
    (
    CASE i_t.insurer_type
      WHEN '4'
      THEN '1'
      ELSE i_t.insurer_type
    END) AS insurer_type
  FROM sspf_centre.irn_registered_ssn irs_t
  INNER JOIN SSPF_CENTRE.insurers i_t
  ON i_t.irn                   = irs_t.new_irn
  OR i_t.old_irn               = irs_t.old_irn
  WHERE irs_t.is_registration IS NOT NULL
  AND i_t.is_real             IS NOT NULL
  ) irs ON irs.ssn             = p.ssn
LEFT OUTER JOIN SSPF_CENTRE.districts di
ON di.code = pa.city
LEFT OUTER JOIN SSPF_CENTRE.countries citiz_c
ON p.citizenship = citiz_c.numeric_code
LEFT OUTER JOIN SSPF_CENTRE.countries coun_c
ON pa.country_code  = coun_c.numeric_code
WHERE pa.address_flag = 1--Here the column value without quotes
AND fa.form_type    = 'Q3';

      

I added separating comments for modified subqueries and WHERE clauses in both queries. Both versions of subqueries return the same result, one of them is only slower, so I decided to update it.

+3


source to share


2 answers


In the most simplistic example, I cannot reproduce your problem on 11.2.0.3.0 or 11.2.0.1.0.

SQL> create table tmp_test ( a char(1) );

Table created.

SQL> insert into tmp_test values ('1');

1 row created.

SQL> select *
  2    from tmp_test
  3   where a = 1;

A
-
1

      

If I then insert a non-numeric value into the table, I can confirm Chris's comment "what Oracle will rewrite tab1.col1 = 1

to to_number(tab1.col1) = 1

", which means you only have numeric characters in the column.

SQL> insert into tmp_test values ('a');

1 row created.

SQL> select *
  2    from tmp_test
  3   where a = 1;
ERROR:
ORA-01722: invalid number



no rows selected

      



If you are interested in tracking this, you should gradually reduce the complexity of the query until you find a minimal, reproducible example. Oracle can pre-compute the conversion to be used in the JOIN, which, since your query is complex, seems like a possible explanation of what's going on.

Oracle explicitly recommends using implicit conversion , so it makes sense not to use it at all; how do you know. For starters, there is no guarantee that your indexes will be used correctly.

Oracle recommends specifying explicit conversions rather than relying on implicit or automatic conversions for the following reasons:

  • SQL statements are easier to understand when you use explicit data type conversion functions.

  • Implicit data type conversion can adversely affect performance, especially if the data type of the column value is being converted to a constant value rather than the other way around.

  • Implicit conversion depends on the context in which it occurs and may not work the same in every case. For example, an implicit conversion from a datetime value to a VARCHAR2 value might return an unexpected year, depending on the value of the NLS_DATE_FORMAT parameter.

  • Algorithms for implicit conversion are subject to change across all software versions and among Oracle products. Explicit conversions are more predictable.

If you only have numeric characters in a column, I would highly recommend changing that to a NUMBER (1) column, and I would always recommend an explicit conversion to avoid a lot of pain in the long run.

+2


source


It's hard to tell without actually asking. I would expect that TAB1.COL1 is somehow different before and after refactoring.

Candidate Differences: Number vs. CHAR (1) vs. CHAR (x> 1) vs. VARCHAR2



It's easy to introduce differences like this with subqueries where you join two tables that are of different types in the join column and you return different columns in your subquery.

To find this problem, you can check the exact data types of your request. Not sure how to do this right now. But the idea would be to take a look at it and use sqlplus desc on it.

+1


source







All Articles