Oracle Fusion Balances to the Cent. Your Warehouse Can't Prove It.
Oracle's ledger balances to the cent because the amounts are decimal. The connector lands them as floating point, and the semantic model is the only place that records they used to be exact.
Query your Oracle Fusion Cloud ERP data with AI against a replicated ledger, ask whether last quarter's debits equalled its credits, and you'll get an answer. On a ledger that balances exactly, that answer can be no. Oracle holds those amounts in a decimal type, which is why the ledger ties to the cent in the first place. The connector that lands them in your warehouse rewrites them to binary floating point, and whether a given column gets rewritten depends partly on how its name ends.
Before you start
- A Fusion estate already replicated into a warehouse. Fivetran's Oracle Fusion Cloud Applications connector is the managed route, and ERP is the FSCM connector specifically. The Hybrid deployment model needs an Enterprise or Business Critical plan.
- BICC enabled, with the offerings you care about configured. Fivetran drives Oracle's Business Intelligence Cloud Connector and supports only Universal Content Management as the file store. It creates and manages the extract jobs itself, so don't edit them or add schedules by hand.
- No free instance exists. Oracle Cloud's free tier covers infrastructure services and excludes the Fusion applications, so there's nothing to sign up for and follow along on. Every query here runs against your own estate.
- Read access to
information_schemain your destination. That's where the one thing you can't assume gets settled. - Airbyte has no Fusion source.
docs.airbyte.com/integrations/sources/oracle-fusionreturns 404, re-checked this morning. It's cited rather than linked, because the 404 is the finding.
The question
"Do our debits equal our credits for last quarter?"
Every period close rests on that identity. It's also the first thing a finance team asks of a newly replicated ledger, because it's the one question whose right answer they already know. The books balanced inside Oracle. If the warehouse agrees, the pipeline earned some trust. If it doesn't, something upstream needs finding.
What breaks
Point an agent at the replicated Fusion schema and ask. It finds the journal lines, reads the debit and credit columns, and writes the query a controller would write by hand:
-- WRONG. Both sums are floating point, so the difference is not
-- reliably zero even on a ledger that balances exactly.
SELECT l.gl_je_lines_period_name AS period_name,
SUM(l.gl_je_lines_accounted_dr) AS total_debits,
SUM(l.gl_je_lines_accounted_cr) AS total_credits,
SUM(l.gl_je_lines_accounted_dr)
- SUM(l.gl_je_lines_accounted_cr) AS out_of_balance
FROM journal_line_extract_pvo l
GROUP BY l.gl_je_lines_period_name
HAVING SUM(l.gl_je_lines_accounted_dr)
<> SUM(l.gl_je_lines_accounted_cr);Nothing about that is wrong as SQL. The columns are real, the grain is right, and the aggregate is the obvious one.
What comes back is a short list of periods out of balance by a fraction of a cent. Or nothing comes back on one run and something on the next. Nothing errors, and nothing in the output says the arithmetic was approximate.
Four amounts are enough to show it. These are synthetic, chosen to be ledger shaped, with two large lines and two small ones:
the four amounts, in an exact decimal type
210.29
43,417,128.92
391.90
46,503,450.20
------------
89,921,181.31 <- the total, and it is the total
the same four amounts accumulated as DOUBLE
smallest first -> 89921181.31
largest first -> 89921181.31000002
difference -> 0.000000014901161193847656So a balance check can report a ledger out of balance because of the order the warehouse happened to add it up in. Those strings are reproducible on any engine, because a warehouse DOUBLE is IEEE 754 binary64 and so is the arithmetic above. They're a property of the type rather than a measurement of anybody's books.
Why it breaks
These aren't the tables you know
Someone who knows Oracle Financials goes looking for GL_JE_LINES and doesn't find it. BICC doesn't extract tables. It extracts View Objects, which Oracle calls data stores and names with a dotted path, and Fivetran names the landed table after the last component of that path. GL_JE_LINES arrives as journal_line_extract_pvo.
Four of the General Ledger and Payables data stores, with the Oracle tables actually behind them:
| Landed table | Oracle source table(s) |
|---|---|
JournalLineExtractPVO |
GL_JE_LINES |
JournalHeaderExtractPVO |
GL_JE_HEADERS, GL_JE_BATCHES, GL_ENCUMBRANCE_TYPES_TL, FUN_SEQ_VERSIONS |
CodeCombinationExtractPVO |
GL_CODE_COMBINATIONS |
InvoiceHeaderExtractPVO |
AP_INVOICES_ALL, AP_PAYMENT_SCHEDULES_ALL |
That mapping isn't in your warehouse. It's in a spreadsheet Fivetran publishes, which is public and needs no login. It holds 1,199 rows covering 902 landed tables, 1,022 of those rows for the FSCM connector and 177 for CRM, counted from the file this morning. Nothing in the destination records any of it.
Two consequences worth carrying into the queries below. First, the landed name goes through Fivetran's standard renaming rules, where adjacent capitals count as one word, so casing and separators vary by destination. Second, a landed name is unique only inside its schema: InvoiceHeaderExtractPVO is published by Payables over AP_INVOICES_ALL and by Project Billing over PJB_INVOICE_HEADERS. Same table name, different data, and 15 of the 886 landed names are reused that way.
One caution, which is a different post rather than this one. 24 of the 191 Financials data stores are backed by more than one Oracle table, so the view has already joined something before you see it. JournalHeaderExtractPVO folds in GL_JE_BATCHES, which means the batch is on the header row and must not be joined again. In Procurement it goes much further, and SourcingObjectiveNegotiationPVO sits over twelve source tables.
Two rules decide which amounts stay exact
The connector's own page states both of them. Quoted:
"Fivetran converts the data types for columns withamount,duration,price, andweightingsuffixes from NUMERIC to DOUBLE in the destination."
"Fivetran converts the data types for columns where thescale value is not equal 0 or precision value is greater than 18, from NUMERIC to DOUBLE in the destination."
A third rule names two specific columns and converts them whatever their original type: FaBalanceExtractBeginningBalance in FA_BALANCES_EXTRACT_PVO, and reverse_uom_rate in UOM_INTERCLASS_PVO.
Rule one bites hard, because Oracle's own naming convention hands it the match. Oracle names money attributes ending in Amount. Counted from Oracle's published attribute lists on 2026-10-08:
| Data store | Attributes ending in amount, duration, price, or weighting |
|---|---|
InvoiceHeaderExtractPVO |
12, including ApInvoicesInvoiceAmount, the invoice amount itself |
InvoiceDistributionExtractPVO |
12, including ApInvoiceDistributionsUnitPrice |
BalanceExtractPVO |
16, which is nearly all of them |
JournalLineExtractPVO |
1 |

One table, five numeric columns, two different rules. Rule text quoted from Fivetran's connector documentation; attribute counts recomputed from Oracle's own pages on 2026-10-08.
The debit and credit columns aren't called amounts
That last row is the sharp one, and it's the reason this post exists.
The General Ledger journal line is where debits and credits actually live. It carries 93 attributes, and exactly one of them ends in a converted suffix: GlJeLinesStatAmount, the statistical amount, which is not money. The four columns that carry the money are named GlJeLinesAccountedDr, GlJeLinesAccountedCr, GlJeLinesEnteredDr, and GlJeLinesEnteredCr. Oracle describes the first as "The journal line debit amount in the ledger currency", so it is an amount in every sense except the one the rule reads.
So on a single journal line, the statistical amount is converted because of how its name ends. The four money columns are converted only if rule two catches them on scale or precision, which depends on what BICC reports for each attribute and isn't stated on any page you can read. Two columns in the same table, decided by two different rules, one of which looks at the last six letters of a column name.
That's why the discovery query below is a catalogue query and not a column list. Which of your columns landed as floating point is a fact about your destination, and the honest answer is to go and look.
What the conversion actually costs
A double holds roughly 15 to 17 significant decimal digits, so one invoice amount survives the trip intact. The damage is to three properties a ledger is built to have.
- Summation stops being associative. Warehouses aggregate in parallel and don't fix the order, so the same query over the same rows can return different trailing digits on different runs. That's the four-amount example above.
- Exact equality stops holding. A close rests on debits equalling credits, which is an equality against zero. In binary floating point the difference of two sums of decimal values isn't reliably zero.
- Reconciliation to the cent is the whole job, and it's exactly the guarantee the type no longer carries.
How large the error gets on a real ledger isn't something this post can tell you. It depends on row counts, magnitudes, and the engine's summation order, and we haven't measured it on any estate. The usual case is sub-cent, which is worse than it sounds: the symptom is intermittent, so it reads as a glitch rather than as a defect, and it gets closed as one.
What the application did for you
Inside Fusion, amounts sit in Oracle NUMBER columns, which are decimal rather than binary. Debits equal credits to the cent because decimal arithmetic makes that checkable, and the application refuses to post a journal that doesn't balance. Every report, every close, and every statutory filing built on that ledger inherits the guarantee for nothing. Nobody writes a rounding rule, because none is needed.
Then the extract converts the number on the way out. The rows all arrive, the account strings are intact, the periods are intact, and the one property the ledger was built to have is the thing that didn't make the trip. No column, no comment, and no constraint in the destination records that it used to hold.
This is the series' recurring shape in its most literal form. Oracle E-Business Suite leaves a boundary behind, so every operating unit lands and the total comes out too big. SAP S/4HANA leaves a display rule behind, so the filter matches nothing. Both of those deliver the value intact and drop a rule about it. Fusion alters the value itself in transit, which is a category this series hasn't written about before.
The fix
Nothing in the destination records that an amount used to be exact, so the semantic model has to. Two declarations carry it: one that says what these columns are, and one that says what may never be done to them.
In the semantic model
No foreign key lands, because BICC delivers CSV extracts through UCM and the destination inherits no constraints. Every join is therefore declared, and each declaration carries the Oracle page it came from.
relationships:
- from_table: journal_line_extract_pvo
from_column: je_header_id
to_table: journal_header_extract_pvo
to_column: je_header_id
relationship: many_to_one
confidence: proposed
review_state: unreviewed
description: >
Many journal lines per journal header. Oracle states the line view
object's unique identifier is jeHeaderId plus jeLineNum, and the header
view object's primary key is jeHeaderId alone. The header view object has
already folded in GL_JE_BATCHES, so the batch is on this row and must not
be joined again.
source: https://docs.oracle.com/en/cloud/saas/financials/26c/oadsr/JournalLineExtractPVO.html
- from_table: journal_line_extract_pvo
from_column: code_combination_id
to_table: code_combination_extract_pvo
to_column: code_combination_code_combination_id
relationship: many_to_one
confidence: proposed
review_state: unreviewed
description: >
The account combination on the journal line. Oracle documents this
attribute as "The unique identifier of the account combination. This is a
foreign key of the Code Combination view object." The target column name
is doubled in Oracle's own attribute list, which is not a transcription
error; confirm the landed spelling against information_schema.
source: https://docs.oracle.com/en/cloud/saas/financials/26c/oadsr/CodeCombinationExtractPVO.htmlThen the part carrying the weight. An entity says what a Fusion money column is, what happened to it in transit, and which questions may not be asked of it as it stands.
entities:
- name: oracle_fusion_ledger_amount
description: >
Any monetary column landed from Oracle Fusion Cloud ERP through BICC.
Inside Fusion these are Oracle NUMBER columns and the arithmetic is
decimal, which is why the ledger balances to the cent. The connector
rewrites NUMERIC to DOUBLE in the destination under two rules: a name
rule on the amount, duration, price, and weighting suffixes, and a scale
rule on any column whose scale is not zero or whose precision exceeds 18.
A DOUBLE sum is order dependent and does not support exact equality, so
every total built on these columns is approximate unless it is cast first.
resolves_to:
table: journal_line_extract_pvo
columns:
- gl_je_lines_accounted_dr
- gl_je_lines_accounted_cr
- gl_je_lines_entered_dr
- gl_je_lines_entered_cr
cast_on_read:
exact_type: DECIMAL(38,2)
forbidden_selectors:
- >
Any equality or inequality comparison between two sums of these
columns, including the debits-equals-credits check. In floating point
the difference is not reliably zero on a ledger that balances.
- >
Any CAST applied to the result of SUM rather than to the column. It
preserves the accumulation error it was meant to remove.
- >
Any claim that a total ties to the ledger, unless the aggregate cast to
an exact type first.
caveats:
- >
Which columns were actually converted is per destination and must be
read from information_schema rather than assumed. The name rule is
visible;
the scale rule is not.
- >
The exact scale is a decision per currency. Two minor units is the
common case and not a universal one.
confidence: proposed
review_state: unreviewed
source: https://fivetran.com/docs/connectors/applications/oracle-fusion-cloud-applicationsAnd the balance check itself, declared once as a metric so the next person asking gets the cast version rather than the obvious one:
metrics:
- name: oracle_fusion_gl_balance_check
calculation: >
Total debits minus total credits by accounting period, with both sides
cast to an exact decimal type before aggregation. Returns zero on a
balanced ledger. Computed on the floating-point columns directly it does
not reliably return zero, which is the defect this metric removes.
requires_entity: oracle_fusion_ledger_amount
source_tables: [journal_line_extract_pvo]
primary_table: journal_line_extract_pvo
other_names: [out of balance, debits equal credits, trial balance check]
bindings:
Snowflake: >
SUM(CAST(gl_je_lines_accounted_dr AS DECIMAL(38,2)))
- SUM(CAST(gl_je_lines_accounted_cr AS DECIMAL(38,2)))
confidence: proposed
review_state: unreviewed
notes: >
Not a trial balance and not a statutory report. It is the arithmetic
identity the ledger already guarantees inside Fusion, restated where the
type no longer guarantees it.Two things about that binding are worth saying out loud.
Cast the column, not the sum. SUM(CAST(x AS DECIMAL(38,2))) is exact. CAST(SUM(x) AS DECIMAL(38,2)) rounds whatever the floating-point accumulation already produced, which is the error you were trying to remove. On a thousand synthetic ledger lines with one very large line among them, casting after aggregating gave a total a full cent apart depending on the order, while casting before gave the same answer either way. That's the same IEEE 754 arithmetic as the four-amount example, run at a size where the error survives rounding.
Pick the scale per currency. Two minor units suits most currencies and not all of them, so DECIMAL(38,2) is a decision somebody makes once and writes down.
Reproduce it yourself
No free Fusion instance exists, so this runs against your own estate. Three steps, and the first two are read-only.
Step one: find out which of your columns landed as floating point. The name rule is predictable, the scale rule isn't, so this is a catalogue query rather than a list to trust. Adjust the schema pattern to whatever your destination prefix produced.
-- Which of your Oracle Fusion columns landed as floating point?
-- Run this before you sum, reconcile, or compare anything for equality.
SELECT table_schema,
table_name,
column_name,
data_type,
numeric_precision,
numeric_scale
FROM information_schema.columns
WHERE table_schema LIKE '%fin_extract%'
AND (data_type ILIKE '%float%'
OR data_type ILIKE '%double%'
OR data_type ILIKE '%real%')
ORDER BY table_schema, table_name, column_name;Every row that comes back is a column where exact decimal arithmetic is no longer available to you. The count is your own exposure, and it's a number this post can't supply because it depends entirely on your destination.
Step two: run the balance check both ways and diff them. This is the five minutes that settles the argument, because it compares your estate against itself.
SELECT l.gl_je_lines_period_name AS period_name,
SUM(l.gl_je_lines_accounted_dr)
- SUM(l.gl_je_lines_accounted_cr) AS float_diff,
SUM(CAST(l.gl_je_lines_accounted_dr AS DECIMAL(38,2)))
- SUM(CAST(l.gl_je_lines_accounted_cr AS DECIMAL(38,2)))
AS exact_diff
FROM journal_line_extract_pvo l
GROUP BY l.gl_je_lines_period_name
ORDER BY l.gl_je_lines_period_name;exact_diff is zero on a ledger that balances. Any period where float_diff isn't zero is a period where the floating-point check would have raised a question nobody needed to answer. Run it twice; the second run is the interesting one.
Step three: write the answer down once, in the semantic model, rather than in the next query. The cast belongs in the metric definition, so the person who asks "did we balance in September" next quarter gets the exact answer without knowing any of this.
A note on names. Oracle's attribute list prefixes attribute names with the entity, so the journal line page documents GlJeLinesCodeCombinationId while the Data Store Key block names the keys unprefixed as JeHeaderId, JeLineNum. The account combination key is CodeCombinationCodeCombinationId, doubled, and that isn't a typo. Confirm the landed spelling against information_schema rather than against either form.
One thing to know about this post's shelf life. Oracle's own integration playbook says BICC "is getting replaced with the Data Extraction tool", read on that page in October 2026. No timeline is given and this post doesn't offer one. Two things hold regardless: extracts already in your warehouse will outlive any migration, and a successor extraction tool doesn't change what a destination does to a NUMERIC column.
What this looks like in Agami
Agami is a trust layer between an AI assistant and your warehouse, and amount columns are a clean example of what that buys. Four mechanisms apply directly to a converted numeric type.
- An entity records that a column used to be exact, because no column type does. Declaring
oracle_fusion_ledger_amountover the four debit and credit columns is what makes "did we balance" resolvable. The fact that BICC rewrote the type lives in one reviewed file instead of in one engineer's memory. - A metric definition carries the cast, so the cast stops being optional.
oracle_fusion_gl_balance_checkcasts before aggregating. Anybody who asks for the balance check gets that arithmetic, whether or not they knew to ask for it. - Forbidden selectors refuse a question that the data can't answer honestly. Comparing two floating-point sums for equality is on that list by name. Those rules are enforced where the query runs rather than suggested in a prompt, which is what makes them auditable instead of advisory.
- Receipts record which declarations an answer used. When a controller questions a total next quarter, the trail says whether the cast was applied. The argument becomes one about the declaration rather than one about the number.
- The declaration is portable across warehouses and assistants. It's YAML, so the next tool that connects inherits it. Fixing the type in one warehouse's views helps that warehouse alone.
What Agami can't do is tell you how far off your totals currently are. That depends on your row counts, your magnitudes, and your engine's summation order, and we have no measurement of it on any Fusion estate. The two queries above are how you find your own number. We also can't restore precision that the extract already discarded; casting on read makes the arithmetic exact from that point on, and a value that arrived rounded arrived rounded.
Frequently asked questions
Why does my Oracle Fusion general ledger not balance in the warehouse? Most likely because the debit and credit columns landed as binary floating point rather than as an exact decimal type. Fivetran's BICC connector rewrites NUMERIC to DOUBLE under two rules, one matching column names that end in amount, duration, price, or weighting, and one matching any column whose scale is not zero or whose precision exceeds 18. A sum of doubles is order dependent, so the difference between two sums is not reliably zero even on a ledger that balanced exactly inside Oracle.
Which Oracle Fusion columns get converted to DOUBLE? It depends on your destination, so query the catalogue rather than assuming. The name rule is predictable: Oracle names money attributes ending in Amount, so 12 of the attributes on the Payables invoice header and 16 on the general ledger balance data store match it. The scale rule is not predictable from any readable page. Select from information_schema.columns filtering on float, double, and real types to get your own list.
Where did GL_JE_LINES go in my warehouse? It became journal_line_extract_pvo. BICC extracts View Objects rather than tables, Oracle names them with a dotted path, and Fivetran names the landed table after the last component of that path. The mapping from landed table back to Oracle source table is published only in a downloadable spreadsheet, which holds 1,199 rows. Nothing in the destination records it.
Should I cast the column or cast the sum? Cast the column. SUM(CAST(x AS DECIMAL(38,2))) aggregates in exact decimal arithmetic. CAST(SUM(x) AS DECIMAL(38,2)) rounds the result of a floating-point accumulation, which keeps the error it was supposed to remove. Pick the scale per currency; two minor units is the common case rather than a universal one.
Is BICC still the right route for Oracle Fusion data? Oracle's integration playbook says BICC is getting replaced with the Data Extraction tool, read in October 2026, and gives no timeline. Fivetran's connector runs on BICC today. Two things hold whatever happens: extracts already landed in your warehouse outlive any migration, and a different extraction tool does not change what your destination does to a NUMERIC column.
One more worth knowing. This post is written against the Fusion SaaS applications reached through BICC. Oracle E-Business Suite is a different product with a reachable database and roughly 25,000 documented tables, and nothing here transfers to it. Fivetran's Oracle BI Publisher connector is also a different route, for when you need the underlying Fusion tables rather than the extracts, and it does not have this trap in the same form.
References
- Fivetran, Oracle Fusion Cloud Applications. The authority for what the destination does, and the source of both type-conversion rules quoted above. Also the BICC and UCM mechanism, the table-naming rule, and the default-columns behaviour. Re-read on 2026-10-08.
- Fivetran, Oracle Fusion Cloud Applications FSCM (ERP and SCM). The ERP connector specifically, with its deployment models and plan requirement.
- Fivetran, View Object to database lineage spreadsheet. Public, no login, 1,199 rows. Landed schema and table mapped back to Oracle source table. Every count in this post's lineage paragraph was recomputed from this file on 2026-10-08.
- Oracle, Journal Line Extract data store. Oracle's own reference, fully public: the grain, the primary keys, and every attribute with a description. The source for the four debit and credit column names and for the attribute count.
- Oracle, Invoice Header Extract data store and Balance Extract data store. The other two attribute counts in the table above.
- Oracle, Extract Data Stores for Financials, full PDF. The whole book in one file, if you would rather search it offline.
- Oracle, Integration Playbook: Business Intelligence Cloud Connector. Where the "BICC is getting replaced with the Data Extraction tool" note lives.
- Fivetran, naming conventions. Destination renaming, including the rule that keeps adjacent capitals as one word.
- Fivetran, choosing between the Oracle connectors. BICC versus BI Publisher, and the sentence that says the BICC route gives you extracts and views rather than tables.
- Airbyte,
docs.airbyte.com/integrations/sources/oracle-fusion. Returns 404, which is the evidence that no Airbyte source exists for Fusion SaaS, so it's cited rather than linked. Worth re-checking yourself, because catalogs move. - Oracle EBS Secured Every Operating Unit in a Session Variable. Your Warehouse Copied the Table.. The other half of the Oracle estate, and a boundary dropped in replication rather than a value altered.
- Two Columns, One SAP Material Number, and the Join Uses the Padded One. A display rule left behind, where the value arrives intact and the filter matches nothing.
- One NetSuite Dollar, Counted Twice, Until the Semantic Model Says Otherwise. Another ledger whose totals need a declaration before they can be trusted.
- How to Sum JD Edwards Actuals Without Adding the Labor Hours to the Dollars. The same question asked of a different ledger, where what breaks is the unit rather than the type.
- Six of Eight Business Central Dimension Columns Are Computed on Read. A ledger where the answer is a missing field rather than a wrong value.
- agami-core on GitHub
Make your Oracle Fusion numbers tie
Agami is the trust layer between your AI assistant and your warehouse. It records that your ledger amounts arrived as floating point, and casts them before it sums them, so the balance check answers the question it was asked.