Your specific table variable example isn't literally true since table types exist (https://docs.microsoft.com/en-us/sql/t-sql/statements/create-type-transact-sql). So if you have an exact same structure to reuse in different stored procedures, you can add its definition to the database and then use that type in multiple places:
-- constraints and IDENTITY added just to show they can be
CREATE TYPE NameAmountTable AS TABLE (
RowNum INT IDENTITY PRIMARY KEY,
Name VARCHAR(35) NOT NULL UNIQUE,
Amount DECIMAL(12,2)
);
GO
CREATE OR ALTER PROCEDURE Proc1 AS
BEGIN
DECLARE @NameAmountTable NameAmountTable;
INSERT INTO @NameAmountTable
(Name, Amount)
VALUES
('Example 1', 12345.67),
('Example 2', 12345.67);
SELECT * FROM @NameAmountTable;
END;
GO
CREATE OR ALTER PROCEDURE Proc2 AS
BEGIN
DECLARE @NameAmountTable NameAmountTable;
INSERT INTO @NameAmountTable
(Name, Amount)
VALUES
('Example 3', 12345.67),
('Example 4', 12345.67);
SELECT * FROM @NameAmountTable;
END;
That said, table types aren't the equivalent of classes in C#, and are barely the equivalent of structs. In fact one of their main purposes is interop with application code: declare a stored procedure parameter as a table type, and it enables passing data in bulk from (say) C# in a strongly-typed fashion, 'strongly typed' in both a general and database-y sense (hence the ability to include most sorts of constraints in a table type's definition). Try to use table types more broadly however, and you will quickly come up against their limitations - hard to change once something else is using the type in its own signature, impossible to nest, no encapsulation or inheritance, etc. So you're right, T-SQL is an absolute disaster when it comes to even a 1990s OOP paradigm, let alone anything more modern.
However, the usage cases of procedural SQL (whether that's T-SQL or PL/pgSQL or whatever) are typically fairly boring, repetitive bulk data preparation and manipulation tasks, like your wider example actually illustrates. Essentially the work is about glueing together a sequence of INSERT
, UPDATE
or DELETE
statements (= pure database SQL things) with a bit of conditional logic, not too much though, with the ability to raise a custom error when needed.
Now, the overall sequence of those INSERT
, UPDATE
and DELETE
statements will likely be important to get right; it will likely require knowledge of the underlying database design (e.g. knowledge of foreign keys, check constraints and other database-y things). Moreover, for performance, the best implementation will probably need to consider topics such as temporary tables, indexes and so forth (so more database-y things). What you need, then, is a language that enables working with the database directly, making pure SQL calls trivial, and includes just enough general programming features to tie things altogether. And that, in a nutshell, is pretty much what T-SQL provides, ditto the equivalent procedural SQL extension languages of other RDBMSs.