A Very Cool Benefit in SSMS 21

I saw a post from Erin that Preview 2 is available. I’d gotten a message when I started SSMS v21 this morning, but got distracted.

I made a short video showing me getting the update, which is way, way easier and more convenient than it used to be.

Posted in Blog | Tagged , , | Comments Off on A Very Cool Benefit in SSMS 21

AI Helping with an API

Can an AI help me with some database API work? Let’s see.

This is part of a series of experiments with AI systems.

The Scenario

One of the things that helped me support a number of development teams with their database work was having code generate code. I had a piece of code that could read the system tables in SQL Server and produce insert, update, and delete procedures.

I wondered if an AI could do this easily.

Using Copilot

I decided to try this first in the Edge Copilot window. I wrote this prompt:Create the T-sQL code for insert, update, and delete procedures for these tables:

I then pasted in the code for 5 tables from Northwind, such as this one:

CREATE TABLE "Employees" ( "EmployeeID" "int" IDENTITY (1, 1) NOT NULL , "LastName" nvarchar (20) NOT NULL , "FirstName" nvarchar (10) NOT NULL , "Title" nvarchar (30) NULL , "TitleOfCourtesy" nvarchar (25) NULL , "BirthDate" "datetime" NULL , "HireDate" "datetime" NULL , "Address" nvarchar (60) NULL , "City" nvarchar (15) NULL , "Region" nvarchar (15) NULL , "PostalCode" nvarchar (10) NULL , "Country" nvarchar (15) NULL , "HomePhone" nvarchar (24) NULL , "Extension" nvarchar (4) NULL , "Photo" "image" NULL , "Notes" "ntext" NULL , "ReportsTo" "int" NULL , "PhotoPath" nvarchar (255) NULL , CONSTRAINT "PK_Employees" PRIMARY KEY CLUSTERED ( "EmployeeID" ), CONSTRAINT "FK_Employees_Employees" FOREIGN KEY ( "ReportsTo" ) REFERENCES "dbo"."Employees" ( "EmployeeID" ), CONSTRAINT "CK_Birthdate" CHECK (BirthDate < getdate()) ) GO CREATE INDEX "LastName" ON "dbo"."Employees"("LastName") GO CREATE INDEX "PostalCode" ON "dbo"."Employees"("PostalCode") GO

I got this result:

-- Insert Procedure
CREATE PROCEDURE InsertEmployee
     @LastName nvarchar(20),
     @FirstName nvarchar(10),
     @Title nvarchar(30),
     @TitleOfCourtesy nvarchar(25),
     @BirthDate datetime,
     @HireDate datetime,
     @Address nvarchar(60),
     @City nvarchar(15),
     @Region nvarchar(15),
     @PostalCode nvarchar(10),
     @Country nvarchar(15),
     @HomePhone nvarchar(24),
     @Extension nvarchar(4),
     @Photo image,
     @Notes ntext,
     @ReportsTo int,
     @PhotoPath nvarchar(255)
AS
BEGIN
     INSERT INTO Employees (LastName, FirstName, Title, TitleOfCourtesy, BirthDate, HireDate, Address, City, Region, PostalCode, Country, HomePhone, Extension, Photo, Notes, ReportsTo, PhotoPath)
     VALUES (@LastName, @FirstName, @Title, @TitleOfCourtesy, @BirthDate, @HireDate, @Address, @City, @Region, @PostalCode, @Country, @HomePhone, @Extension, @Photo, @Notes, @ReportsTo, @PhotoPath)
END
GO
-- Update Procedure
CREATE PROCEDURE UpdateEmployee
     @EmployeeID int,
     @LastName nvarchar(20),
     @FirstName nvarchar(10),
     @Title nvarchar(30),
     @TitleOfCourtesy nvarchar(25),
     @BirthDate datetime,
     @HireDate datetime,
     @Address nvarchar(60),
     @City nvarchar(15),
     @Region nvarchar(15),
     @PostalCode nvarchar(10),
     @Country nvarchar(15),
     @HomePhone nvarchar(24),
     @Extension nvarchar(4),
     @Photo image,
     @Notes ntext,
     @ReportsTo int,
     @PhotoPath nvarchar(255)
AS
BEGIN
     UPDATE Employees
     SET LastName = @LastName, FirstName = @FirstName, Title = @Title, TitleOfCourtesy = @TitleOfCourtesy, BirthDate = @BirthDate, HireDate = @HireDate, Address = @Address, City = @City, Region = @Region, PostalCode = @PostalCode, Country = @Country, HomePhone = @HomePhone, Extension = @Extension, Photo = @Photo, Notes = @Notes, ReportsTo = @ReportsTo, PhotoPath = @PhotoPath
     WHERE EmployeeID = @EmployeeID
END
GO




-- Delete Procedure
CREATE PROCEDURE DeleteEmployee
     @EmployeeID int
AS
BEGIN
     DELETE FROM Employees WHERE EmployeeID = @EmployeeID
END
GO

Here’s an image of what I saw:

2024-11_0126

You might ask if this is better than what I’d write. I wondered myself, so I asked it to change the update procedure slightly. Here’s the prompt and result:

2024-11_0127

-- Update Procedure
CREATE PROCEDURE UpdateEmployee
     @EmployeeID int,
     @LastName nvarchar(20) = NULL,
     @FirstName nvarchar(10) = NULL,
     @Title nvarchar(30) = NULL,
     @TitleOfCourtesy nvarchar(25) = NULL,
     @BirthDate datetime = NULL,
     @HireDate datetime = NULL,
     @Address nvarchar(60) = NULL,
     @City nvarchar(15) = NULL,
     @Region nvarchar(15) = NULL,
     @PostalCode nvarchar(10) = NULL,
     @Country nvarchar(15) = NULL,
     @HomePhone nvarchar(24) = NULL,
     @Extension nvarchar(4) = NULL,
     @Photo image = NULL,
     @Notes ntext = NULL,
     @ReportsTo int = NULL,
     @PhotoPath nvarchar(255) = NULL
AS
BEGIN
     UPDATE Employees
     SET LastName = COALESCE(@LastName, LastName),
         FirstName = COALESCE(@FirstName, FirstName),
         Title = COALESCE(@Title, Title),
         TitleOfCourtesy = COALESCE(@TitleOfCourtesy, TitleOfCourtesy),
         BirthDate = COALESCE(@BirthDate, BirthDate),
         HireDate = COALESCE(@HireDate, HireDate),
         Address = COALESCE(@Address, Address),
         City = COALESCE(@City, City),
         Region = COALESCE(@Region, Region),
         PostalCode = COALESCE(@PostalCode, PostalCode),
         Country = COALESCE(@Country, Country),
         HomePhone = COALESCE(@HomePhone, HomePhone),
         Extension = COALESCE(@Extension, Extension),
         Photo = COALESCE(@Photo, Photo),
         Notes = COALESCE(@Notes, Notes),
         ReportsTo = COALESCE(@ReportsTo, ReportsTo),
         PhotoPath = COALESCE(@PhotoPath, PhotoPath)
     WHERE EmployeeID = @EmployeeID
END
GO

That’s interesting. If I pass in nulls for everything, I get an update in place. Not quite what I’d do, as I’d check if the param was null and not include it in an update, which could reduce logging, but this is likely just as efficient.

Easy code to write for sure, and I could likely put together a bit of code to do this for me, but it’s nice that I can quickly ask an AI to do this. I think this is the type of thing that might be easier for developers to do, and maybe more likely. They get to play with AI and feel more productive. They can even alter a table and “re-ask” for new procedures where they can interact with the table.

What’s more, the INSERT procedures have the explicit column lists, so this means I could rev the underlying table without breaking this code. It’s a good coding practice, but far too many people would just embed a this in their code:

insert Employee values ‘Jones’, ‘Steve’, ‘Editor’, …

A quick thing, but Copilot seemed to work well here.

Posted in Blog | Tagged , | Comments Off on AI Helping with an API

Creating a “Real” Copy of a View: #SQLNewBlogger

I saw a post where a developer was trying to read the Information Schema views to create a copy of a view as a “real” table, a user table. This posts shows an easy way to do this.

Another post for me that is simple and hopefully serves as an example for people trying to get blogging as #SQLNewBloggers.

The Scenario

Imagine you have a view, for example, I have this one:

CREATE   VIEW [dbo].[City] 
AS
SELECT TOP 10
  cn.CityNameID, cn.CityName
  FROM dbo.CityName AS cn
  WITH CHECK OPTION
GO

The structure of the underlying table is:

2024-11_0122

I have data being returned from this view as well, as you can see here:

2024-11_0118

If I want a copy of this view, I can certainly look in the information_schema views and see some data. Below, I have the column information for this view, which can be used to structure a create table statement.

2024-11_0119

However, there’s a better way.

Quickly Copying a View

The INTO clause is very valuable and helpful here. Many of us use this to copy a table or part of a table, but it work with views. Here is how I create an empty copy of my view.

SELECT * 
  INTO dbo.MyCities
  FROM dbo.city
  WHERE 1 = 0;

This will actually create a new table, as you can see in my Table list when I refresh after running the command.

2024-11_0120

The table looks like the structure of the view above. The PK isn’t set, but there isn’t necessarily a PK in a view as it can combine data from multiple tables. If I wanted data, I can run the same statement above without the WHERE clause. I’ve done that below and then selected data from the new table so show this.

2024-11_0123

If I needed to add some constraints or other items, I could easily add those with ALTER TABLE statements.

SQL New Blogger

This post required about 20 minutes for me to setup a demo, test, and then write with some screenshots. It wasn’t a hard post to write, but it shows a quick technique for doing something I’ve commonly seen from others.

This is the type of post you can write that might get an interviewer interested in you and perhaps ask you a question. You could add some context as to why you did this, or why you like (or don’t like) this technique.

Posted in Blog | Tagged , , | Comments Off on Creating a “Real” Copy of a View: #SQLNewBlogger

Continuous Learning

It seems there’s quite a dichotomy in the technology workforce. On one hand I hear about the Great Resignation where many employees are leaving their jobs because of RTO (return to office) mandates or some other dissatisfaction with their job. On the other, I’ve seen quite a few people who were laid off and are struggling to find new positions. On the third hand, there is no shortage of companies who report they are struggling to find and hire talented people for some positions.

I don’t quite know what to think, but I do know that employment seems to be harder to come by. If you are looking for a job, I believe you need your own sustainable learning plan. If your organization can’t find qualified talented staff, then the organization definitely needs a continuous learning plan.

I saw a piece on creating a continuous learning culture, which seems more suited for managers than technology workers, but there are a few good pieces of advice. First, set some goals. I write about this often, and I’ve seen others recommend this as well. Think about where you could improve your skills, and where you see demand for skills, and then start working backward on a plan to gain those skills. Think about where you want to be in 6 months or a year and build a plan to get there.

Another good piece of advice is to learn within your flow of work, which often means spending a little more time deepening or broadening your skills in an area where you are already working. If you’re writing a query, analyze the plan and reads and see if you could tune it to run more efficiently. Read about those skills and practice them, which deepens your skills. If you don’t know much about query tuning, then broaden your experience and learn about a new operator, new index, new hint, and experiment. Then you have a wider view of what possibilities there are in query tuning.

More importantly, build the habit of curiosity and experimentation, which is what will help you drive continuous learning throughout your day. It’s good to look at new things, but don’t forget to sharpen your existing skills, practice being better at the work you already do, and find a balance that ensures you are growing while still meeting your other commitments, both at work and away from work.

There’s an old joke that if you train people they might leave, but if you don’t train them, they’ll stay. For organizations struggling with talent, embrace some investment in current employees, at least those who have potential. Grow them and you might find that the person you’ve been struggling to hire is already working for you. They just needed a little boost.

Steve Jones

Listen to the podcast at Libsyn, Spotify, or iTunes.

Note, podcasts are only available for a limited time online.

Posted in Editorial | Tagged | Comments Off on Continuous Learning