Unlike mathematical relations, SQL tables have ordered columns, but please don’t depend on it.

In other words, try to treat these tables as the same because it’s super-awkward to turn one into the other:

CREATE TABLE PEOPLE
(
LastName varchar(200),
FirstName varchar(200)
)
CREATE TABLE PEOPLE
(
FirstName varchar(200),
LastName varchar(200)
)

 

Don’t Omit Column Specification

And don’t forget to specify the columns in your INSERT statement. No excuses.

You’re depending on the column ordering if you write INSERT statements like this:

INSERT PEOPLE /* no column spec */
VALUES ('Rob', 'Farley'),
('Angela', 'Henry'),
('Andy', 'Leonard'),
('Richard', 'Douglas'),
('David', 'Maxwell'),
('Aaron', 'Nelson'),
('Paul', 'Randal');

We recently got burned by something like this

 

Find Missing Column Specifications

Thomas LaRock recently encouraged DBAs to branch out horizontally. In that spirit, don’t be too afraid of the C#. I’ve got a program here that finds procedures with missing column specifications.

  • If for some reason, you don’t care about enforcing this rule for temp tables and table variables, then uncomment the line // visitor.TolerateTempTables = true;
  • It uses ScriptDom which you can get from Microsoft as a nuget package.
  • The performance is terrible in Visual Studio because ScriptDom uses Antlr which uses exceptions for flow control and this leads to lots of “first chance exceptions” which slows down debugging. Outside of Visual Studio, it’s just fine.
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using Microsoft.SqlServer.TransactSql.ScriptDom;
 
class Program {
 
static void Main(string[] args) {

SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder {
DataSource = ".",
InitialCatalog = "test_database",
IntegratedSecurity = true
};
 
using (SqlConnection conn = new SqlConnection(builder.ToString())) {
conn.Open();
SqlCommand command = new SqlCommand(@"
SELECT OBJECT_SCHEMA_NAME(object_id) [schema],
OBJECT_NAME(object_id) [procedure],
OBJECT_DEFINITION(object_id) [sql]
FROM sys.procedures
ORDER BY OBJECT_SCHEMA_NAME(object_id), OBJECT_NAME(object_id) ;", conn);
SqlDataReader reader = command.ExecuteReader();
while (reader.Read()) {
string schema = reader["schema"].ToString();
string procedure = reader["procedure"].ToString();
string sql = reader["sql"].ToString();
if (SqlHasInsertWithoutColumnList(sql)) {
Console.WriteLine( $"{schema}.{procedure}" );
}
}
}
}
 
static bool SqlHasInsertWithoutColumnList(string SQL) {
SQLVisitor visitor = new SQLVisitor();
// visitor.TolerateTempTables = true;
TSql130Parser parser = new TSql130Parser(true);
IListerrors;
var fragment = parser.Parse(new System.IO.StringReader(SQL), out errors);
fragment.Accept(visitor);
return visitor.HasInsertWithoutColumnSpecification;
}

internal class SQLVisitor : TSqlFragmentVisitor {
public bool HasInsertWithoutColumnSpecification { get; set; }
public bool TolerateTempTables { get; set; }
 
public override void ExplicitVisit(InsertStatement node) {
if (node.InsertSpecification.Columns.Any())
return;
 
var source = node.InsertSpecification.InsertSource as ValuesInsertSource;
if (source != null && source.IsDefaultValues)
return;
 
if (TolerateTempTables) {
var target = node.InsertSpecification.Target as NamedTableReference;
if (target != null && !target.SchemaObject.BaseIdentifier.Value.StartsWith("#")) {
HasInsertWithoutColumnSpecification = true;
}
} else {
HasInsertWithoutColumnSpecification = true;
}
}
}

 

In my environment, I found twelve examples which I’ll be fixing soon.

About the Author

Michael J Swart

Michael is a Senior Database Developer from Waterloo, Ontario, Canada. Michael has worked in the I.T. industry for over ten years and has worked extensively with some Oracle background. He's focused on SQL Server for the past six years.

Start the discussion at forums.toadworld.com