Write SQL joins faster in SSMS: a free, no-AI helper that reads your foreign keys
Type JOIN and SQL Sage for SSMS lists the related tables with a ready ON clause and alias — built from your foreign keys, free, with no AI and no API key.
Writing a join by hand is a small, repeated tax. You pause to remember which column points at which, whether the key is customer_id or CustomerID, which direction the relationship runs, and what alias you used three lines up. None of it is hard. All of it breaks your flow, and on an unfamiliar schema you end up flipping to the Object Explorer to check.
A new feature in SQL Sage for SSMS (0.31) removes that tax. The release note for it is deliberately blunt: write faster, free and with no AI. Type JOIN and SQL Sage lists the tables related to the one you are joining from, each with a complete ON clause and an alias already filled in. You pick one and keep typing.
Disclosure: this blog is published by LumaSoft (LUMA sp. z o.o.), and I work on the tool described here.
What the JOIN suggestions actually do
The trigger is the keyword you were going to type anyway. Write a SELECT, add JOIN, and SQL Sage shows a list of the tables that are related to your current table. Each entry is not just a table name — it is the whole join, ready to insert:
SELECT o.order_id, o.total
FROM dbo.orders AS o
JOIN dbo.customers AS c ON c.customer_id = o.customer_id
You did not type the ON condition, and you did not invent the alias c. SQL Sage filled in the matching columns and gave the joined table a short alias, so the join is complete the moment you accept it. If several tables are related, they are all offered; you choose the one you meant.
That is the entire interaction. There is no panel to open, no prompt to write, no model to wait on. It is a lookup that happens where your cursor already is.
Where the relationships come from: foreign keys first
The suggestions are not guesses. SQL Sage builds them by reading the relationships your database already declares — its foreign keys. A foreign key is the database’s own statement that this column references that table’s key, so a join derived from it is correct by construction: the columns line up because the schema says they line up.
That covers the well-modelled case. Plenty of real databases, though, have no foreign keys at all — they were dropped for load performance, never added, or the convention lives only in the team’s heads. SQL Sage still helps there, but it is honest about how. When there is no foreign key to lean on, it matches on key column names instead: if your table has customer_id and another table has a customer_id that looks like its key, that is a plausible join. Every suggestion built this way is labelled a name match, and the label matters. A name match is a reasonable hypothesis, not a declared relationship — two columns sharing a name is not the same guarantee as a foreign key, and SQL Sage says so rather than letting the two blur together. You get the convenience either way; you are never misled about which kind of evidence it rests on.
Why “no AI” is the point, not a limitation
It would be easy to assume a feature that writes your joins must be calling a language model. This one deliberately does not, and that is a feature rather than a shortcoming.
Nothing here is executed, and nothing is sent to an AI. SQL Sage reads your schema — the foreign keys and column names that are already there — and composes the join locally. That is a deterministic helper: given the same schema it produces the same ON clause every time, because it is reading a fact, not sampling a probability. There is no key column it might hallucinate, no plausible-but-wrong relationship it could invent, because it is not inventing anything.
This is the same principle that runs through the rest of SQL Sage, the one we have written about at length: prove, don’t guess. An AI assistant earns trust by grounding its answers in your real schema instead of a statistical prior. A join helper earns it the same way — by reading the relationship rather than predicting it. The difference shows up exactly where it counts: the ON clause either reflects a key that exists, or it is flagged as a name match you should sanity-check. It is never a confident guess dressed up as a fact.
There is also a privacy dividend that falls out of the design for free. Because the whole thing runs against your local schema and talks to no model, nothing about your database leaves your machine to make a join suggestion. For anyone working against production or under a data-handling policy, “no AI” and “nothing sent anywhere” are the reassuring part, not the caveat.
Qualified names, schemas, and when it cannot help
Table names in SQL Server are not always unambiguous. Write orders with no schema and the server has rules for what that resolves to; so does SQL Sage. It resolves an unqualified table name the way SQL Server does — your default schema first, then dbo — which is exactly what you want when the same table name exists in more than one schema and you typed the short form out of habit.
That same ambiguity used to be a sharp edge. An earlier issue could make the JOIN suggestions confuse two tables that share a name across different schemas; 0.31.0 fixes that, so a JOIN from sales.orders offers the relationships of that table, not an accidental namesake in another schema. And when SQL Sage genuinely cannot resolve what you meant, it tells you why in a single line instead of showing an empty list — a blank dropdown makes you wonder whether the feature is broken; one line of explanation tells you it is working and what it needs from you.
Finding the object before you join to it
A sibling feature is worth a mention because it covers the step just before a join: finding where something lives. SQL Sage Search (Ctrl+Alt+D, or Tools > SQL Sage Tools > Find object) searches across every database on the server for tables, views, procedures, functions and columns — by name, and by the text inside object definitions, so you can find the procedure that mentions a column, not just the column. Databases it cannot read are listed rather than silently skipped, so an incomplete result never passes for a complete one. Like the JOIN suggestions, it runs nothing and sends nothing to an AI; it reads the catalog and reports what is there.
The takeaway
Joins are the part of SQL where hand-typing is most error-prone and least interesting, and they are exactly the part a tool can get right from information the database already holds. SQL Sage for SSMS turns JOIN into a lookup: from your foreign keys you get a complete ON clause and an alias with no typing; where there are no foreign keys it offers name matches, labelled as such so you know what you are accepting. It is free, it uses no AI and no API key, and because it reads your schema locally, nothing leaves your machine to do it.
SQL Sage for SSMS is an add-in for SQL Server Management Studio that puts an AI copilot in the query editor — writing, explaining and optimizing SQL grounded in your real schema — and stays read-only by default and keyless (you sign in with your own Claude or ChatGPT account, no API key to manage). The JOIN suggestions and SQL Sage Search described above are the parts that need no AI at all. You can see it on the SQL Sage for SSMS product page. SQL Sage is made by LumaSoft (LUMA sp. z o.o.) and is not affiliated with Microsoft.