How to Query Infor LN by Company When the Company Number Is in the Table Name

One Infor LN table lands in your warehouse as many tables, one per company, and not one of them has a company column. The semantic model is where the company becomes a column you can group by.

An Infor LN table company number, decoded out of the physical table name tdsls401300 into package, module, table number, and company, beside the tables the replication landed.
The name decomposition is quoted from Infor's Technical Reference Guide for the SQL Server Database Driver, release 10.7. The mapping notation is from Infor's own LN Analytics mapping guide, read on 2026-10-09.

Query your Infor LN data with AI against a replicated database, ask what each company sold last quarter, and the question turns out not to be expressible. Infor puts the company number in the physical table name. One logical sales-order-lines table lands in your warehouse as several tables that differ only by a numeric suffix, and not one of them carries a column saying which company it is. So an agent reasoning over columns has nothing to group by, and an agent that picks a single table returns a confident number for one company out of several.

Before you start

  • An LN database already replicated into a warehouse. No managed application connector exists for Infor. fivetran.com/docs/connectors/applications/infor and docs.airbyte.com/integrations/sources/infor-ln both return 404, re-checked this morning; they're cited rather than linked, because the 404 is the finding. LN runs on SQL Server or Oracle, so the route is a database connector such as Fivetran's SQL Server connector.
  • Or Infor's own route. LN publishes to Data Lake over ION messaging, extracted through Data Fabric.
  • No free instance exists. Infor ships no free or developer-tier LN, so every query here runs against your own estate.
  • Read access to information_schema in your destination. That's where the one thing you can't assume gets settled.
  • Which company numbers are production. That's institutional knowledge, and it's the one input no query supplies.

The question

"What did each of our companies sell last quarter?"

In a multi-company LN estate that's the ordinary monthly question, and a finance team expects it to be a group-by. The data is all in the warehouse. Every row of it landed.

What breaks

Point an agent at the replicated schema and ask. It finds a sales-order-lines table, reads the columns, filters on the invoice date, and writes what a competent analyst would write:

-- WRONG: one company's order lines, reported as the company's order lines.
SELECT COUNT(*)               AS invoiced_lines,
       COUNT(DISTINCT t_orno)  AS orders
FROM   tdsls401300
WHERE  t_invd <> 0
AND    t_invd >= '2026-07-01'
AND    t_invd <  '2026-10-01';

That query runs. It's fast, the column names are right, and the result is a plausible number. It's also one company's activity presented as the business's activity, and nothing in the output says so.

Ask the agent to group by company instead and it can't. No column in tdsls401300 records a company. The grouping key the question asks for isn't in the data; it's in the table's name.

Why it breaks

The company number is part of the table name

Infor specifies LN's physical table names, and the specification is explicit. From the Technical Reference Guide for the SQL Server Database Driver, release 10.7, page 16:

The name of an LN table stored in SQL Server has the following format.

t<Package><Module><Table number><Company number>

The same guide defines the last component:

Company Number Within LN, three digit company numbers are used to isolate datasets used for different purposes (for example; demo data, training data, production data). There must be a company with the number 000. Company 000 contains master data common to all companies.

and gives its own worked example:

For example, the table 999 in module adv with company number 000 is created in SQL Server as tttadv999000.

This isn't a quirk of one database engine. Infor states the same rule in its Oracle, DB2, and EnterpriseDB driver guides, each in its own wording and each with a Company Number component. One wording difference matters and is worth recording: only the SQL Server guide describes company numbers as isolating demo, training, and production data. The other three say the company number differentiates areas of functionality, which is a weaker claim.

Decoding tdsls401 with that rule gives package td for Distribution, module sls for Sales, and table number 401. So tdsls401300 and tdsls401500 are two physical tables with identical structure, identical grain, and different data. A database connector replicates tables as the database names them, so all of this arrives in your warehouse exactly as LN wrote it. An application connector would have had the chance to normalise it away. There isn't one.

Infor's own analytics product gives the trap away

The clearest evidence that this is a real gap rather than a naming preference is in Infor's own BI mapping. The LN Analytics mapping guide binds each Birst attribute to its source, and the notation is consistent: a genuine column is written table.column, with a dot.

Attribute Mapping
Sales Order tdsls401.orno
Invoice Date tdsls401.invd
Order Date tdsls401.odat
Planned Delivery Date tdsls401.ddta
Company tdsls401_compnr

Every attribute on that page uses a dot. Company uses an underscore. The Sales Order dimension page does the same thing with tdsls400_compnr beside tdsls400.orno. Infor's own analytics product can't dot into a company column, because the column doesn't exist, so it manufactures the attribute and its notation records the difference.

Infor LN table name decomposition beside Infor's own mapping notation

Every real column in Infor's mapping guide is bound with a dot. The company attribute, on all three pages that publish one, is bound with an underscore.

Three moves, none of them safe

Picking one table omits silently. tdsls401300 is fully populated and plausible. A query against it answers for one company and the result carries no signal about the rest.

Unioning every match overcounts. Sweeping in every tdsls401* table pulls in the demo and training companies that Infor's own guide says are there. The total comes out high, by an amount nobody can estimate without first knowing which suffixes are real.

The suffix doesn't always mean what it looks like. LN has a table-sharing feature, and Infor's page on logical and physical company numbers states it plainly:

Logical tables belong to a logical company but are physically stored under another company.

Example Logical company : 100 Physical company: 500

User 1 works under company 100, which means that he works with the data of company 100. On forms and menus, the user sees: Company 100. Physically, the data of the tables of the Item Based Data module is stored under company 500.

So for a shared module, the number in the table name is the physical company and the logical company appears nowhere in the name. A rule that says "the suffix is the business unit" is correct until somebody enables table sharing, and then it's quietly wrong.

Two more things the schema won't help with

Nothing is ever NULL. The SQL Server guide, page 19: "All columns created by the LN MSQL driver have the NOT NULL constraint. LN does not currently support NULL values in the data." The Oracle, DB2, and EnterpriseDB guides all say the same. Absence is a sentinel instead, which is why Infor's own mapping defines Invoiced as tdsls401.invd <> 0 rather than as a null check. An agent that writes WHERE invoice_date IS NOT NULL gets every row back.

That sentinel is a real date. The same page: "The LN date 0 is mapped to the earliest possible date in the SQL Server (01-Jan-1753)." On Oracle it maps to 4712 B.C. An average-days-to-ship calculation over unshipped orders produces nonsense, and different nonsense on each database.

Infor contradicts itself on the suffix width. The driver guides say "three digit company numbers". Infor's Creating the first company guide says of the same field: "this number must contain four digits." Both are current Infor pages, read this morning. Settling it needs a live instance, so nothing below parses a fixed-width suffix.

That last page carries one more number worth keeping. Of the Create Tables step, Infor notes: "LN creates more than 2000 tables. This process can take some time." That's per company. Your warehouse holds more than two thousand tables for each company, and not one of them has a company column.

A third party reaches the same conclusion independently. NAZDAQ, which sells LN reporting tools, describes the problem in its own words: "tables of the same type residing in different companies are stored as different tables. This means that when you build a report for, say, the purchase orders of company 300, you will use table tdpur041300 (the last 3 characters specify the number of the company in the database.)"

Why nobody inside LN ever noticed

Inside the application, none of this is visible. A user works under a company and LN resolves every table name for them, including the shared-module redirection above: "On forms and menus, the user sees: Company 100."

So the person who asks what each company sold has spent years in a product where the company was a mode rather than a column, and was never once asked to think about it. The schema fact appears only when the data is replicated, and it appears to a different person.

The fix

The semantic model's job here is to state what the schema can't: which physical tables are one logical entity, which company each one holds, and which of them are real.

# Infor LN sales order lines, declared across companies.
# Company numbers are per-deployment. Discover them with the first query in
# "Reproduce it yourself" and have a person confirm which are production.
tables:
  - name: sales_order_lines
    description: >
      Sales order lines from Infor LN (data-dictionary table tdsls401),
      unioned across the production companies only. The company number is
      part of the physical table name and is projected here as a column.
    # Source for the naming rule: Infor Enterprise Server Technical Reference
    # Guide for SQL Server Database Driver 10.7, p16:
    # t<Package><Module><Table number><Company number>
    union_of:
      - physical_table: tdsls401300
        constants: { company_number: "300" }
      - physical_table: tdsls401500
        constants: { company_number: "500" }
    excluded_physical_tables:
      # Demo and training companies. SQL Server driver guide p16: company
      # numbers isolate "demo data, training data, production data".
      - tdsls401000   # company 000 holds master data common to all companies
      - tdsls401100   # confirmed a demo estate by a person, not by a query
    columns:
      - name: company_number
        type: string
        description: >
          The PHYSICAL company this row was stored under. Not necessarily the
          logical company the business uses: under table sharing, a module's
          tables live under another company number.
        # Source: "To define logical and physical company numbers", 10.7
      - name: t_orno
        maps_to: order_number
        description: Sales order number. On Oracle this column is t$orno.
        # Source: LN Analytics mapping guide, Sales Order Line dimension,
        # "Sales Order | tdsls401.orno"
      - name: t_invd
        maps_to: invoice_date
        description: >
          Invoice date. NOT NULL, like every LN column, and 0 means never
          invoiced rather than unknown.
        # Sources: SQL Server driver guide p19; LN Analytics mapping guide,
        # which defines Invoiced as "tdsls401.invd <> 0"
        default_filter_candidate: "t_invd <> 0"

metrics:
  - name: invoiced_sales_order_lines
    calculation: COUNT(sales_order_lines.*)
    required_filters:
      - "t_invd <> 0"
    grain: one row per sales order line
    description: >
      Invoiced sales order lines across production companies. Grouping by
      company_number is valid because the column is declared here. It does
      not exist in any of the underlying tables.

Three things that declaration buys, in this post's own terms:

  1. company_number exists as a column, so "by company" becomes a group-by.
  2. The demo and training companies are excluded by name, once, in a file a person signed, instead of by a filter somebody has to remember.
  3. t_invd <> 0 travels with the metric, so the 1753 sentinel can't quietly enter an average.

One thing deliberately missing from that YAML: a revenue metric. Infor publishes column codes for dates, identifiers, and codes, and no amount column for tdsls401 appears anywhere in the mapping guide. Rather than guess a four-letter code, bind yours after the second discovery query below.

Reproduce it yourself

No free LN instance exists, so this runs against your own warehouse. Three steps, and the first two are read-only.

Step one: find out how many companies your warehouse actually holds. Don't assume the suffix width, because Infor's own pages disagree about it. Read it off the result.

-- Every physical sales-order-lines table the replication landed.
SELECT table_schema,
       table_name
FROM   information_schema.tables
WHERE  table_name LIKE 'tdsls401%'
ORDER  BY table_name;

The row count is the number of companies in scope, and it's a number this post can't supply because it's a property of your estate. Infor's list of defined companies lives in the Companies (ttaad1100m000) session, which is where the names behind those numbers are. Join the suffixes you found against that to see which are production.

Step two: get the column spellings on your release. The column prefix differs by database, so this is a catalogue query rather than a list to trust. The SQL Server guide, page 17: "when an LN column name is created in the SQL Server, it is preceded by the string t_. For example, the LN column with the name cpac is created in the SQL Server with the name t_cpac." On Oracle the prefix is t$, and Oracle then uppercases the name when it stores it in the dictionary.

-- Column names on one landed sales-order-lines table.
SELECT column_name,
       data_type
FROM   information_schema.columns
WHERE  table_name = 'tdsls401300'   -- a suffix from step one
ORDER  BY ordinal_position;

This is also where you find your amount column, which is the one identifier this post won't print.

Step three: run the question both ways and compare. The first query is what an agent writes against the raw schema. The second is what the declaration above makes possible.

-- RIGHT: the declared production companies, with company as a real column.
WITH order_lines AS (
    SELECT '300' AS company_number, t_orno AS order_number, t_invd AS invoice_date
    FROM   tdsls401300
    UNION ALL
    SELECT '500' AS company_number, t_orno AS order_number, t_invd AS invoice_date
    FROM   tdsls401500
)
SELECT company_number,
       COUNT(*)                     AS invoiced_lines,
       COUNT(DISTINCT order_number)  AS orders
FROM   order_lines
WHERE  invoice_date <> 0
AND    invoice_date >= '2026-07-01'
AND    invoice_date <  '2026-10-01'
GROUP  BY company_number
ORDER  BY company_number;

300 and 500 stand for whatever step one returned and a person confirmed is production. The gap between this result and the single-table query is your own exposure. Swap COUNT(*) for a sum over the amount column you found in step two and the same shape answers the revenue question.

Two things to settle with a person before signing any of this off. Which company numbers are production, which is institutional knowledge rather than anything discoverable. And whether table sharing is enabled, and for which modules, because where it is, the physical suffix isn't the logical company and the mapping has to be declared explicitly.

What this looks like in Agami

Agami is a trust layer between an AI assistant and your warehouse. A company number that lives in a table name is a clean example of what that buys, because it's a case where no amount of prompting helps: the information an agent needs isn't in the data it can see.

  • A declared union turns several physical tables into one queryable entity. Naming tdsls401300 and tdsls401500 as one sales_order_lines entity, with company_number projected as a constant per table, is what makes "by company" a group-by. The knowledge lives in one reviewed file instead of in one engineer's memory.
  • Excluded tables are refused by name rather than by convention. The demo and training suffixes are listed once, as exclusions, and those rules are enforced where the query runs instead of being suggested in a prompt. That's what makes the scope auditable: a question that would have reached tdsls401100 doesn't, and the refusal is recorded.
  • A required filter rides with the metric, so the sentinel date can't leak in. t_invd <> 0 is part of the metric definition rather than something the next person has to remember about 1753.
  • Receipts record which declarations an answer used. When somebody questions a company's total next quarter, the trail says which suffixes were in scope and which were excluded. The argument becomes one about the declaration rather than one about the number.
  • The declaration is portable across LLMs and databases. It's YAML, so the next assistant or warehouse inherits it. Fixing this inside one BI tool's semantic layer helps that tool alone, which is exactly what Infor's own mapping guide shows happening.

What Agami can't do is tell you which of your company numbers are real. That's a sign-off, and it should be asked for by name rather than inferred. We also have no measurement of how far off a single-table query runs on any LN estate, because we have no LN warehouse behind this post. The queries above are how you get your own number, and the sign-off is the part no query can do.

Frequently asked questions

Why does my Infor LN warehouse have several copies of the same table? Because the company number is part of the physical table name. Infor's Technical Reference Guide for the SQL Server Database Driver specifies the format as t<Package><Module><Table number><Company number>, so one logical table becomes one physical table per company. A database connector replicates them as named, and no application connector exists to normalise it away.

Which Infor LN table suffix is my production company? No query can tell you, and that's the honest answer. The suffixes are discoverable by selecting table names from information_schema.tables, and the names behind the numbers are in the Companies (ttaad1100m000) session. Which ones hold production rather than demo or training data is institutional knowledge, and it's the single sign-off a semantic model needs here.

Is the company number three digits or four? Infor's own pages disagree. The driver guides for all four supported databases say "three digit company numbers", and every worked example is three digits. The 2024.x guide on creating the first company says of the company number "this number must contain four digits". Don't parse a fixed width. Enumerate the table names instead.

Can I just union every table that matches the pattern? No, and that's the trap's second half. The SQL Server driver guide says company numbers isolate "demo data, training data, production data", so a blanket union pulls in estates that were never real. The total comes out high by an amount you can't estimate until you know which suffixes are production.

Why doesn't a date filter behave the way I expect? Because LN has no nulls. All four driver guides state that every column the driver creates carries a NOT NULL constraint, and the LN date 0 maps to 01-Jan-1753 on SQL Server. An unset invoice date is a real date in 1753 rather than a null, which is why Infor's own analytics mapping defines Invoiced as tdsls401.invd <> 0.

References

Make your Infor LN companies a column

Agami is the trust layer between your AI assistant and your warehouse. It records which physical tables are one logical entity, which company each suffix holds, and which of them are production, so "by company" becomes a question your estate can answer.

Start a free trial or talk to us →