SQL
SQL Commands overview

LedgyX SQL - A revolutionary query language

Introduction

LedgyX SQL is a unique query language that radically extends the capabilities of traditional SQL. The key difference: custom variables become typed data sources, and special object types support parameterized queries right in the FROM clause.

πŸš€ Unique capabilities

Custom variables as data sources

The main innovation: &variable variables can be used as tables with a typed schema:

-- The &users variable becomes a table with a schema!
SELECT u.id, u.name, u.email, u.active
FROM &users AS u(
    id INTEGER,
    name TEXT(100), 
    email TEXT(255),
    active BOOL
)
WHERE u.active = true
ORDER BY u.name
TYPE LIST;

Parameterized data sources

Data sources accept parameters right in the FROM clause:

-- LEDGER with parameters
SELECT account, balance, last_update
FROM LEDGER.account_balances(
    WHERE account_id = &user_id
    ORDER BY last_update DESC
    LIMIT 50
) AS balances
TYPE LIST;
 
-- CRYPTONET with filtering
SELECT "hash", "from", "to", "value"
FROM ETHEREUM.TRANSACTIONS.DATA(
    WHERE "blockNumber" > &start_block 
    AND "gasPrice" < &max_gas
    ORDER BY "blockNumber" DESC
    LIMIT 1000
) AS transactions
TYPE LIST;

The CALL system for external services

-- Telegram Bot API
SELECT CALL(TG_SEND_MESSAGE, '{"chat_id": ' || &chat_id || ', "text": "Order ready!"}') AS result;
 
-- AI integration
SELECT CALL(AI_CHAT_COMPLETION, '{"model": "gpt-4", "prompt": "' || &question || '"}') AS ai_response;
 
-- Blockchain operations  
SELECT CALL(CONTRACT_CALL, '{"address": "' || &contract || '", "method": "balanceOf", "params": ["' || &wallet || '"]}') AS balance;

πŸ“Š Object types and fields

Special field types

Field typePurposeExample
FIELDRegular field (default)name FIELD TEXT(100)
RESOURCEBalances and accumulatorsquantity RESOURCE DECIMAL(15,3)
METERINGAccounting dimensions (analytics)warehouse_id METERING UUID
PROPERTYAdditional propertiesmetadata PROPERTY JSON
CREATE LEDGER IF NOT EXISTS inventory (
    ref UUID DEFAULT UUID() NOT NULL,
    period TIMESTAMP NOT NULL,
    product_id UUID NOT NULL,
    
    -- Resource fields (balances)
    quantity RESOURCE DECIMAL(15,3) DEFAULT 0,
    cost_amount RESOURCE DECIMAL(15,2) DEFAULT 0,
    
    -- Accounting dimensions  
    warehouse_id METERING UUID,
    supplier_id METERING UUID,
    batch_number METERING TEXT(50),
    
    -- Additional properties
    serial_numbers PROPERTY JSON,
    certificates PROPERTY JSON,
    quality_data PROPERTY JSON,
    
    PRIMARY KEY (ref)
);

Object system fields

Every object automatically receives system fields:

-- System fields are available for all objects
SELECT 
    REF AS object_reference,      -- Object's unique reference
    ID AS numeric_id,             -- Numeric identifier
    PARENT_REF AS parent_link,    -- Reference to the parent
    OWNER_REF AS owner_link,      -- Reference to the owner
    STATE AS object_state,        -- Object state
    name,
    email
FROM dictionary.users
WHERE STATE = 'active'
TYPE LIST;

⚑ Built-in functions

System functions

FunctionParametersPurpose
UUID()-Generate a UUID
UUID(value)any valueUUID based on a value
NOW()-Current date and time
ISNULL(expr, replacement)expression, replacementReplace NULL values
NULLREF()-Empty UUID reference
VERSION()-System version
FIELDS(list)list of fieldsGet configuration fields
PARSE(data)data to parseParse data
-- Practical examples
SELECT 
    UUID() AS new_id,
    UUID(&input_value) AS deterministic_id,
    NOW() AS current_timestamp,
    ISNULL(description, 'No description') AS safe_description,
    NULLREF() AS empty_reference
FROM dictionary.products;

Special functions

-- FCOUNT for counting
SELECT FCOUNT(*) AS total_count FROM dictionary.users;
 
-- FSUBSTRING for working with strings  
SELECT FSUBSTRING(description, 1, 100) AS short_desc FROM dictionary.products;
 
-- FTRIM for trimming whitespace
SELECT FTRIM(user_input) AS clean_input FROM dictionary.form_data;

πŸ—οΈ Query structure

Basic syntax

SELECT [ALLOWED] [options] fields [TYPE return_type]
FROM source[(parameters)] [AS alias]  
[WHERE conditions]
[GROUP BY fields] [HAVING conditions]
[ORDER BY fields [ASC|DESC]]
[LIMIT count] [OFFSET offset]
[TYPE return_type];

Data sources

-- Reference tables
FROM dictionary.users
FROM dictionary.products
 
-- Registers with parameters
FROM LEDGER.transactions(
    WHERE account_id = &account
    ORDER BY date DESC
    LIMIT 100
)
 
-- Blockchain data
FROM ETHEREUM.TRANSACTIONS.DATA(WHERE "blockNumber" > &start)
 
-- Custom data as tables
FROM &input_data AS data(
    id INTEGER,
    value TEXT,
    amount DECIMAL(10,2)
)
 
-- Enumerations and constants
FROM enum.status_types
FROM const.system_settings

πŸ”— Object types

TypeSyntaxPurpose
DICTIONARYdictionary.nameReference tables
ENUMenum.nameEnumerations
CONSTconst.nameConstants
LEDGERledger.name(params)Accounting registers
INFOREGinforeg.name(params)Information registers
OPERATIONoperation.nameDocuments/operations
CONTRACTcontract.nameBlockchain contracts

πŸ“ Data operations

INSERT with conflict handling

-- Insert with conflict handling
INSERT INTO dictionary.users (id, name, email, phone)
SELECT &id, &name, &email, &phone
ON CONFLICT(id) DO UPDATE SET
    name = EXCLUDED.name,
    email = EXCLUDED.email,
    updated_at = NOW();
 
-- Ignoring conflicts
INSERT INTO dictionary.tags (name, description)
VALUES (&tag_name, &description)
ON CONFLICT(name) DO NOTHING;
 
-- Error on conflict
INSERT INTO dictionary.unique_codes (code, data)
VALUES (&code, &data)
ON CONFLICT(code) DO ERROR;

UPDATE with subqueries

-- Update with a subquery
UPDATE dictionary.products 
SET category_name = (
    SELECT name 
    FROM dictionary.categories 
    WHERE ref = products.category_ref
)
WHERE category_name IS NULL;
 
-- Update via JOIN
UPDATE dictionary.orders 
SET total_amount = calculated.total
FROM (
    SELECT 
        order_ref,
        SUM(quantity * price) AS total
    FROM &order_items AS items(
        order_ref UUID,
        quantity DECIMAL,
        price DECIMAL
    )
    GROUP BY order_ref
) AS calculated
WHERE orders.ref = calculated.order_ref;

Return types

-- Return a single object
SELECT id, name, email FROM dictionary.users 
WHERE id = &user_id 
TYPE OBJECT;
 
-- Return a list
SELECT id, name, price FROM dictionary.products 
WHERE category_id = &category
TYPE LIST;
 
-- API-formatted return  
SELECT 
    COUNT(*) AS total,
    AVG(price) AS average_price
FROM dictionary.products
TYPE API OBJECT;

🌐 Blockchain integration

Supported networks

-- Available CRYPTONET networks
ETHEREUM    -- Chain ID: 1
GOERLI      -- Chain ID: 5  
BSC         -- Chain ID: 56
MATIC       -- Chain ID: 137

Blockchain queries

-- Transactions with parameters
SELECT "hash", "from", "to", "value"::NUMBER / 1e18 AS eth_amount
FROM ETHEREUM.TRANSACTIONS.DATA(
    WHERE "blockNumber" BETWEEN &start_block AND &end_block
    ORDER BY "blockNumber" DESC
    LIMIT 1000
) AS txs
TYPE LIST;
 
-- Contract events
SELECT "topics", "data", "blockNumber"
FROM CONTRACT.events(
    WHERE "address" = &contract_address
    AND "blockNumber" > &from_block
    ORDER BY "blockNumber" ASC
) AS events  
TYPE LIST;

πŸ€– Integration with external services

CALL operation examples

-- Telegram notifications
SELECT CALL(TG_SEND_MESSAGE, 
    '{"chat_id": ' || &chat_id || 
    ', "text": "Order #' || &order_id || ' processed!"}') AS sent;
 
-- AI analysis
SELECT CALL(AI_ANALYZE_IMAGE,
    '{"image_url": "' || &image_url || '",
      "question": "Describe the image contents"}') AS analysis;
 
-- Sending a webhook
SELECT CALL(WEBHOOK,
    '{"url": "' || &webhook_url || '",
      "method": "POST", 
      "data": ' || &payload::TEXT || '}') AS webhook_result;

πŸ’‘ Practical examples

Complex query with custom data

-- Processing an order with custom data.
-- Ineron SQL has no CTEs (WITH ... AS) β€” compose steps with subqueries in FROM.
SELECT 
    op.order_id,
    op.product_name,
    op.quantity AS requested_qty,
    ISNULL(ic.available_qty, 0) AS available_qty,
    CASE 
        WHEN ISNULL(ic.available_qty, 0) >= op.quantity 
        THEN 'In stock'
        ELSE 'Insufficient stock'
    END AS status
FROM (
    -- Use custom data as a table
    SELECT 
        o.order_id,
        oi.product_id,
        p.name AS product_name,
        oi.quantity,
        oi.price
    FROM &order_data AS o(
        order_id UUID,
        customer_id UUID, 
        total_amount DECIMAL(12,2)
    )
    JOIN &order_items AS oi(
        order_id UUID,
        product_id UUID,
        quantity INTEGER,
        price DECIMAL(10,2)
    ) ON o.order_id = oi.order_id
    JOIN dictionary.products p ON oi.product_id = p.ref
) AS op
LEFT JOIN (
    -- Check balances via LEDGER
    SELECT 
        product_id,
        SUM(quantity) AS available_qty
    FROM LEDGER.inventory(
        WHERE warehouse_id = &warehouse_id
        AND quantity > 0
    ) AS inv
    GROUP BY product_id
) AS ic ON op.product_id = ic.product_id
ORDER BY op.order_id, op.product_name
TYPE LIST;

Working with system fields

-- Top-level categories
SELECT 
    c.REF,
    c.ID,
    c.name,
    c.name AS full_path
FROM dictionary.categories AS c
WHERE c.PARENT_REF = NULLREF()
ORDER BY c.name
TYPE LIST;
 
-- Direct children of a category, with a two-level path via a self-join
SELECT 
    c.REF,
    c.ID,
    c.name,
    parent.name || ' > ' || c.name AS full_path
FROM dictionary.categories AS c
JOIN dictionary.categories AS parent ON c.PARENT_REF = parent.REF
WHERE c.PARENT_REF = &parent_ref::uuid
ORDER BY c.name
TYPE LIST;

Ineron SQL has no recursive CTEs. Walk a hierarchy one level at a time by filtering on PARENT_REF (self-join for the parent's fields), or use a GRAPH.nodes MATCH (...) query for arbitrary-depth traversal.

πŸ“– Documentation navigation

Core concepts

Blockchain and external services

SQL operations

🏁 Quick start

1. Create a reference table with typed fields

CREATE DICTIONARY IF NOT EXISTS users (
    ref UUID DEFAULT UUID() NOT NULL,
    id INTEGER UNIQUE NOT NULL,
    name FIELD TEXT(100) NOT NULL,
    email FIELD TEXT(255) UNIQUE,
    phone FIELD TEXT(20),
    metadata PROPERTY JSON,
    created_at TIMESTAMP DEFAULT NOW(),
    PRIMARY KEY (ref)
);

2. Use custom data as a source

-- Insert from custom variables
INSERT INTO dictionary.users (id, name, email, phone)
SELECT u.id, u.name, u.email, u.phone
FROM &user_data AS u(
    id INTEGER,
    name TEXT, 
    email TEXT,
    phone TEXT
)
ON CONFLICT(id) DO UPDATE SET
    name = EXCLUDED.name,
    email = EXCLUDED.email,
    updated_at = NOW();

3. Create an API endpoint

-- GET /api/users/profile
SELECT 
    REF,
    ID,
    name,
    email,
    ISNULL(phone, 'Not specified') AS phone_display,
    created_at
FROM dictionary.users
WHERE ID = &user_id
TYPE OBJECT;

LedgyX SQL is not just an extension of SQL, but a completely new approach to working with data, where custom variables become typed data sources and external services are integrated directly into the query language!