September 3, 2026
SQL SIG Monthly Meeting
SQL knowledge for people and agents
September connected the databases introduced in August to a practical question: how can the work we capture in SQL help both a developer and an AI agent understand what happened?
The session revisited SQL DDL history and the virtual copy of STAR, followed the warehouse from source rows to enforced relationships, and then moved into a second brain built from mail and agent activity. The closing demo ran a small language model locally from C#.
The working pattern throughout was to capture useful information once, give it a clear structure, and retrieve the part needed for the next question.
Monthly Meeting
1h 9m
Recording length12 Participants
Across multiple firmsRecording
AvailableWhat this meeting covered
Build, learn, then simplify
The opening discussion set the tone: AI is useful for trying an idea quickly, but the code still needs an owner. Amine described iterating on a proof of concept, then rewriting the useful parts into a tool he could understand and maintain.
The same discipline appears in the databases: small foundations, explicit relationships, and enough recorded DDL history to check what was actually deployed.

SQL Server DDL history and schema snapshots
Capture the SQL DDL changes made to the instance
The sqlserver database begins with one table, ddl.events. Two server-scoped DDL (Data Definition Language) triggers pass EVENTDATA() into ddl_event.new, which extracts the event type, time, database, object, login, and command text while retaining the original XML.
This records SQL DDL changes such as creating or altering a view, adding an index, and dropping a table. It is separate from Change Data Capture (CDC): the DDL log captures changes to database structures, not row-level inserts, updates, or deletes. The DDL history starts when the triggers are installed; it cannot reconstruct earlier DDL changes.
That history is useful when a procedure was overwritten or someone needs to establish what ran. It also gives an agent evidence of the implementation, which may differ from the script it originally suggested.
A DDL log and a schema snapshot answer different questions
An ALTER event preserves the command that was issued. It does not automatically preserve the old definition immediately before that command. The session paired the event log with smo.generate_scripts so the current schema could also be captured.
The procedure accepts a database name or ID and returns an XML tree through its @xmlreturn output parameter. Database-level scripts and object folders are represented separately, with filenames and script contents ready for a program to write to disk. This is a schema snapshot; it is not a backup of the database rows.
Read a time window without overlapping its boundary
ddl.events_range uses an inclusive start and an exclusive end: post_time >= start and post_time < end. Adjacent windows can share a boundary without both including it. The example below reads the meeting day using the timestamps stored by the server.
use sqlserver; go declare @from_inclusive_date datetime2 = '2026-09-03T00:00:00'; declare @to_exclusive_date datetime2 = '2026-09-04T00:00:00'; select e.post_time, e.event_type, e.database_name, e.schema_name, e.object_name, e.command_text from ddl.events_range(@from_inclusive_date, @to_exclusive_date) as e order by e.post_time, e.id;
Look across the instance from one place
The custom system schema brings together catalog views from accessible databases. For example, system.objects exposes each object with its database identity, while sys.objects describes the current database. system.build_views generates the cross-database definitions and aligns string collations.
The DDL event-capture procedure rebuilds those views after CREATE_DATABASE and DROP_DATABASE. That uses the existing DDL signal to handle those two maintenance cases. Renames, permission changes, or other changes to database availability still need to be considered in an operational deployment.
The query below shows recently created or modified objects. GREATEST chooses the later of the two dates; this function is available from SQL Server 2022 onward.
use sqlserver; go select top (50) o.database_name, o.name, o.type_desc, o.create_date, o.modify_date from system.objects as o where o.is_ms_shipped = 0 order by greatest(o.create_date, o.modify_date) desc, o.database_name, o.object_id;

A local STAR copy and a warehouse with clear relationships
Keep the source copy close to the work
The virtual database holds the STAR tables and columns a consumer needs. The table and column names retain their source meaning. The source rowversion value is stored as binary(8), so copying a row preserves STAR’s counter instead of generating a new local one.
The incremental pass uses that counter to bring over inserts and updates. An unchanged table has no changed rows to transfer. This makes frequent synchronization practical and lets reporting use a local copy instead of repeatedly reaching across a linked server to the operational database.
A rowversion cannot identify a deleted row: the row carrying the value is gone. The session described comparing source and local key buckets after the insert/update pass, then reconciling the buckets that differ. Bucket size is configurable. The point is to narrow the work needed to find deletions rather than pull every row on every cycle.
Turn source identifiers into declared relationships
The warehouse reads through synonyms and exposes transformations as dbsource table-valued functions. The matching db tables hold the results. A common synchronization procedure uses those matching names to generate the transfer statements.
In the job example, a source identifier is checked against its lookup table. A missing match can resolve to a deliberate zero record in the appropriate dimension. That gives an unknown or absent relationship somewhere explicit to land, instead of allowing a dangling identifier.
The physical tables then declare foreign keys. This makes joins predictable, but the qualification matters: a foreign key proves that the referenced row exists; it does not by itself prove that an accounting classification or amount is correct. The transformation rules still need their own evidence.
Give WIP and nominal rows a business meaning
STAR’s wide WIP and nominal tables contain several kinds of records. September revisited splitting those into narrower tables: time, expenses, billing, billing lines, receipts, invoices, and provisions. A query about bill headers can read db.wipBilling; a query needing the lines can follow db.wipBillingLine.bill_id to that header.
The AR example is equally specific: db.arInvoiceFeeProvision.invoiceFee_id refers to an invoice fee. Where a relationship needs to reach across several record kinds, the db.wip and db.ar identity tables provide a common parent. These were described as spines in the demonstration.
Removing unused and repeated fields also reduced the data footprint in the demonstrated warehouse. Amine reported that data plus indexes was roughly comparable to the raw source tables without indexes. That was an observation about this implementation, not a storage guarantee for every STAR environment.
Inspect the relationship instead of relying on its name
This metadata query shows the two relationships discussed above and the other foreign keys on those tables. An enabled, trusted constraint has is_disabled = 0 and is_not_trusted = 0. These are read-only checks; they do not run warehouse synchronization.
-- Run in the warehouse database. This reads metadata only.
select
s.name as schema_name,
t.name as table_name,
c.name as column_name,
rs.name as referenced_schema,
rt.name as referenced_table,
rc.name as referenced_column,
fk.is_disabled,
fk.is_not_trusted
from sys.foreign_keys as fk
inner join sys.foreign_key_columns as fc
on fc.constraint_object_id = fk.object_id
inner join sys.tables as t on t.object_id = fc.parent_object_id
inner join sys.schemas as s on s.schema_id = t.schema_id
inner join sys.columns as c
on c.object_id = t.object_id and c.column_id = fc.parent_column_id
inner join sys.tables as rt on rt.object_id = fc.referenced_object_id
inner join sys.schemas as rs on rs.schema_id = rt.schema_id
inner join sys.columns as rc
on rc.object_id = rt.object_id and rc.column_id = fc.referenced_column_id
where s.name = 'db'
and t.name in ('wipBillingLine', 'arInvoiceFeeProvision')
order by t.name, c.name;Release status
At the September meeting, the warehouse was being exercised in one of Amine’s products before wider release. The newer download bundle is planned after the October 1 meeting. The August page remains the source for the previously shared SQL Server and virtual-database scripts.

A second brain starts with information worth keeping
Retrieve the relevant context in stages
The first second-brain experiment used a folder structure for projects, areas, and accumulated knowledge. A short index routed the agent toward the relevant material. This is progressive disclosure: begin with enough information to choose where to look, then load the detail needed for the question.
Keeping a large knowledge collection does not mean putting all of it into every conversation. The session connected this to a familiar constraint: an agent has a limited context window, so the retrieval path matters as much as the amount of information stored.
Multiple sessions working in the same collection introduced another problem: concurrent edits to shared files. Moving structured records into SQL was an experiment in using database transactions and a defined schema to manage that shared state.
The mail import is a recognizable ETL job
A small C# importer used XstReader to read Outlook PST and OST files, then called stored procedures to store what it found. For a SQL developer, the process is familiar: extract the source records, transform them into a useful structure, and load them into tables.
The demonstrated mail schema separates mailboxes, folders, messages, recipients, and attachments. Shared object information and MAPI properties sit beneath them. This retains details that would be lost if the import stored only a message subject and body.
The structure also needs to accommodate a message attached to another message. Views expose useful fields from the stored properties so later processing can work with recognizable values instead of repeatedly decoding property identifiers.
Stored source material is the foundation
The mail extraction was working; the more structured brain built on top was still being explored. Several versions had been tried, and Amine had not settled on the design. The useful distinction is between retaining source information and deciding how an agent should interpret or retrieve it.

Give the agent context before it answers
A suggestion is not evidence of what was deployed
The agent workflow began with a practical frustration. An agent suggests SQL DDL; the developer reviews it, changes it, and deploys a different version. The next answer needs to start from that actual implementation.
Amine described keeping the agent’s access to his own databases read-only while giving it a separate workspace database for experiments. The next improvement was to stop spending each turn asking the agent to rediscover the SQL DDL changes.
Capture the hook, then decide what work it needs
Claude Code hooks invoke a small hook.exe program. That program sends the hook payload and execution context into the agents database. agent.hooks records the event and its timings; agent.tools records work associated with it.
agent.hook creates the hook record and loads the applicable work. The program asks agent.tool for pending work and reports its result. SQL decides which tool should run; the C# program carries out work such as writing files.
The following queries inspect timing and status without returning prompt text, environment details, or tool-result payloads.
use agents; go select top (25) h.id, h.name, h.begin_date, h.end_date, h.error_date, h.duration_seconds from agent.hooks as h order by h.id desc; select top (25) t.id, t.hook_id, t.name, t.begin_date, t.end_date, t.error_date, t.is_success_status_code from agent.tools as t order by t.id desc;
Use SQL DDL history to refresh the right database scripts
For UserPromptSubmit, the SqlDatabaseHarvest workflow checks whether a database has recorded SQL DDL changes since its last completed harvest. A database without a completed harvest needs an initial snapshot.
For a database that needs refreshing, the workflow calls smo.generate_scripts and sends the XML to the file-writing tool. The resulting scripts give the agent a current representation it can read from disk. A short result tells it which files were written, removed, or unchanged before it handles the prompt.
The harvesting table keeps inclusive and exclusive timestamps plus completion and file counts. The implementation takes its next starting point from completed work. This is why the SQL DDL history and the schema snapshot introduced earlier belong in the same session: one selects the databases to inspect; the other supplies their current definitions.
use agents; go select top (25) h.database_name, h.from_inclusive_date, h.to_exclusive_date, h.end_date, h.written, h.pruned, h.unchanged from tool.SqlDatabaseHarvests as h order by h.id desc;
Keep retrieval distinct from a future search feature
Saved hook history can help an agent recover detail after a conversation has been compacted. It also lets the developer inspect which hooks and tools ran and how long they took.
Embeddings and a SQL Server vector column were discussed as a possible next enhancement for finding history by meaning. That was a proposed extension, not a completed semantic-search demonstration in this meeting.

Run a language model locally
A model file and a short C# program
The closing demo used LLamaSharp to load a downloaded language-model file, submit a prompt, and print the response on the same machine. The model shown was small, approximately half a gigabyte. Once the model and runtime dependencies are present, this kind of inference can run locally without sending the prompt to a hosted model service.
LLamaSharp is a .NET interface to llama.cpp. Model size, hardware, and the selected backend affect memory use and response time; downloading a larger model is not by itself a guarantee of a better fit.
The proposed SQL connection
The next step proposed in the meeting was to expose the local model through an endpoint and call it from SQL Server. The September demonstration stopped at local C# inference; the SQL-to-model call was left for a follow-up.
SQL Server 2025’s sys.sp_invoke_external_rest_endpoint requires HTTPS and accepts a timeout of 1 to 230 seconds. A slow local model can exceed that window. This was the reason given for revisiting SQLX as another way to make .NET capabilities available from SQL.

SQL gives AI a place to start.
SQL keeps useful information in a form we can query and check: source records, SQL DDL history, and the steps an agent has taken. AI can use that context to explore a question, suggest a query, and help a developer decide what to investigate next. The more clearly the data can be understood, the more useful that conversation can become.
Keep Context
Ask Questions
Check Results
Build Understanding
Now bring that idea back to STAR. We have spent the last few meetings making the warehouse easier for people to understand. What happens when an AI can begin to make sense of it too? That is where October 1 begins.
About the Host
Amine Fayad is the STAR SQL SIG Leader and Co-Founder of Encapsulated. For nearly three decades, his work has spanned .NET, SQL Server, and the construction of reporting engines, automation platforms, workflow systems, enterprise integrations, and SODA-inspired database service architectures.
This meeting showed how he uses AI to test ideas, then turns useful experiments into code he can maintain. SQL supplies the data and DDL history; he reviews the work, decides what to deploy, and gives the agent the context it needs to continue from the implementation actually in place.
