Using M365 Copilot With SQL

Share this:

I recently used M365 Copilot with SQL and I continue to be amazed with how helpful it is. I used it to help me write SQL statements. It’s ability to figure out context and provide me with what I need with less prompting is astonishing. I wanted to share what I did as just one example of how you can leverage AI with your own development. There are of course, many many great ways to use AI in development. Some directly using Visual Studio, and others like this that are indirect. Often times people have indirect problems they want to solve, and still want to use AI. Therefore, I wanted to show this one using M365 Copilot. The purpose is not for you to build this same application. Instead, understand how to use AI to help your own development process.

Background

Before, I can share how I used M365 Copilot with SQL, I need to explain the application I have and the data structure.

In my work, clients will send us problems that my team works to solve. We have people who are assigned to monitor the incoming requests and make sure they are assigned out properly to the rest of the team.

There are multiple shifts throughout each day, where a person is assigned this ‘triage’ role. This way, one person does not have to do it for the entire day.

We have other ‘shifts’ where we need people to be assigned a role on a certain date and time. Such as a code reviewer. Or a person to promote code, ect.

We have an Excel document to manage the assignments of these shifts.

Web Application

Instead of continuing to use an Excel document, I created a Web App to manage this schedule. This would allow use team member to enter in the dates they are not available to take a shift. It also allows the system to generate the schedule based on people’s availability, and send them email invites automatically.

I used AI to create the web app from a prompt of what I needed it to do. But that is not the part I want to focus on. The part I want to share is how I loaded data after I created the application.

The Data

The web application reads and writes to several different tables.

First, I have a table that stores all of the ‘team members’, named SchedTriageMembers.

Second, a table stores all of the available ‘shifts’ each day, named SchedShifts.

Third, a table stores which ‘team members’ are eligible to be assigned each ‘shift’. For example, I have some team members who live on the east coast. Therefore, I only want the system to assign them shifts that are in the morning. Similarly, I have people who live on the west coast. I only want them assigned shifts that are in the afternoon. Lastly, I have team members who live in India. These team members can be assigned the US ‘night shift’. This table is called SchedScheduleAssignments.

Fourth, I have table that stores all of the holiday’s for each country. US, and Canada, and India each have a different holiday calendar. This table is named SchedHolidays. I also have a table named SchedCountries that stores the countries.

Fifth, I have a table that stores when each team member is out of the office or otherwise unavailable to take a shift. This table is named ‘SchedMemberTimeOff‘.

Six, the team is large and therefore some team members work on one system, while others work on another. So each team member is actually part of a group that I call a ‘team’. The table that stores the list of teams is named SchedTeams.

Ultimately, the tables don’t matter that much. The purpose of this article is to show you how M365 Copilot with SQL can work on your tables as well.

The Scheduler

To help you visualize my specific example, below is an example scheduler in Excel with made up names.

In the first column, the spreadsheet lists each day that needs to be scheduled. Next, each column lists each ‘shift’. Additionally, at the top of each column, lists which team members are eligible for each shift.

Ultimately, the goal is to populate the Excel table with names so that each date and shift is assigned a team member who is eligible and available to work that shift.

Tell M365 About Your Table Structure

Now comes the neat stuff on using M365 Copilot with SQL.

First, I copied into M365 Copilot a sql script that explains my table structure to AI. This could be any a select statement, or any other kind of statement that allows Copilot to see the table names and fields:

I have these tables and data in a database: " 
INSERT [dbo].[SchedCountries] ([CountryId], [Name], [CreatedAt]) VALUES (1, N'US', CAST(N'2026-08-24T19:56:03.5350868' AS DateTime2))

INSERT [dbo].[SchedHolidays] ([HolidayId], [CountryId], [HolidayDate], [Name]) VALUES (1, 1, CAST(N'2026-09-07' AS Date), N'Labor Day')

INSERT [dbo].[SchedTeams] ([TeamId], [Name], [CreatedAt]) VALUES (1, N'F&SC', CAST(N'2026-08-24T19:56:03.7514177' AS DateTime2))

INSERT [dbo].[SchedTriageMembers] ([MemberId], [FirstName], [LastName], [TeamId], [CountryId], [CreatedAt], [Email]) VALUES (1, N'Ava', N'Smith', 1, 1, CAST(N'2026-08-24T20:37:10.4069066' AS DateTime2), N'')

INSERT [dbo].[SchedShifts] ([ShiftId], [TeamId], [Name], [SortOrder], [StartTime], [EndTime]) VALUES (1, 1, N'Morning Triage 8 AM-10:30 AM MST', 1, N'08:00', N'10:30')

INSERT [dbo].[SchedScheduleAssignments] ([Id], [TeamId], [ShiftId], [AssignedDate], [MemberId], [UpdatedAt], [GraphEventId]) VALUES (1, 1, 1, CAST(N'2026-08-24' AS Date), 1, CAST(N'2026-08-24T20:42:55.6624445' AS DateTime2), NULL)

INSERT [dbo].[SchedShiftMembers] ([ShiftId], [MemberId]) VALUES (1, 1)

INSERT [dbo].[SchedMemberTimeOff] ([Id], [MemberId], [OffDate]) VALUES (1, 7, CAST(N'2026-09-21' AS Date))"

In any other system, you have to provide your table structure and field names in a very well defined format. Maybe XML or JSON. But using AI, it is smart enough to understand my table schema using whatever format I have it is. This is amazing!

Insert Records Using Copilot

Now that I have told Copilot my table structure, I can it generate TSQL scripts to insert my data.

In this example, I have a list of names, and I need them inserted into my ‘team member’ table. The good news is I again can give this information to Copilot in whatever format works for me.

In this case, I can say to Copilot: “Now take this list of all of the team members (ignoring duplicates), and generate a TSQL script to insert all team members into the table SchedTriageMembers that are not already there. Use Work IQ knowledge, or read my email address book to look up the country and email address of each person. Set the createdAt column to right now”.

I can then copy and past a picture of the names from my excel file.

Copilot is smart enough to read the names, retrieve additional information from Work IQ, and generate TSQL code to insert the data into the table I specified. Notice, I didn’t even provide it with the column names. It figured it out from context.

Below is essentially the TSQL Copilot produced. I modified the script to use my made up names.

SET NOCOUNT ON;
SET XACT_ABORT ON;

BEGIN TRY
    BEGIN TRANSACTION;

    /*
        Team:
            F&SC

        Country names must match:
            US
            India

        Duplicate detection:
            1. Email, case-insensitive
            2. FirstName + LastName, case-insensitive
    */

    DECLARE @TeamId int;

    SELECT @TeamId = TeamId
    FROM dbo.SchedTeams
    WHERE Name = N'F&SC';

    IF @TeamId IS NULL
    BEGIN
        THROW 50001, 'The F&SC team was not found in dbo.SchedTeams.', 1;
    END;

    IF NOT EXISTS
    (
        SELECT 1
        FROM dbo.SchedCountries
        WHERE Name = N'US'
    )
    BEGIN
        THROW 50002, 'The US country was not found in dbo.SchedCountries.', 1;
    END;

    IF NOT EXISTS
    (
        SELECT 1
        FROM dbo.SchedCountries
        WHERE Name = N'India'
    )
    BEGIN
        THROW 50003, 'The India country was not found in dbo.SchedCountries.', 1;
    END;

    DECLARE @MembersToInsert table
    (
        FirstName   nvarchar(100) NOT NULL,
        LastName    nvarchar(100) NOT NULL,
        CountryName nvarchar(100) NOT NULL,
        Email       nvarchar(320) NOT NULL
    );

    INSERT INTO @MembersToInsert
    (
        FirstName,
        LastName,
        CountryName,
        Email
    )
    VALUES
        (N'Will',      N'Smith',    N'India', N'Will.Smith@gmail.com'),
        (N'Liam',   N'Dallas',         N'India', N'Joshi.dallas@gmail.com'),
        (N'Lucas',           N'Doe',       N'US',    N'Lucas.doe@gmail.com'),
        

    /*
        Preview the records that qualify for insertion.
        This can be retained for deployment validation.
    */
    SELECT
        SourceMember.FirstName,
        SourceMember.LastName,
        @TeamId AS TeamId,
        Country.CountryId,
        SourceMember.CountryName,
        SourceMember.Email
    FROM @MembersToInsert AS SourceMember
    INNER JOIN dbo.SchedCountries AS Country
        ON Country.Name = SourceMember.CountryName
    WHERE NOT EXISTS
    (
        SELECT 1
        FROM dbo.SchedTriageMembers AS ExistingMember
        WHERE
            LOWER(LTRIM(RTRIM(ExistingMember.Email))) =
                LOWER(LTRIM(RTRIM(SourceMember.Email)))
            OR
            (
                LOWER(LTRIM(RTRIM(ExistingMember.FirstName))) =
                    LOWER(LTRIM(RTRIM(SourceMember.FirstName)))
                AND
                LOWER(LTRIM(RTRIM(ExistingMember.LastName))) =
                    LOWER(LTRIM(RTRIM(SourceMember.LastName)))
            )
    )
    ORDER BY
        SourceMember.LastName,
        SourceMember.FirstName;

    INSERT INTO dbo.SchedTriageMembers
    (
        FirstName,
        LastName,
        TeamId,
        CountryId,
        CreatedAt,
        Email
    )
    SELECT
        SourceMember.FirstName,
        SourceMember.LastName,
        @TeamId,
        Country.CountryId,
        SYSUTCDATETIME(),
        SourceMember.Email
    FROM @MembersToInsert AS SourceMember
    INNER JOIN dbo.SchedCountries AS Country
        ON Country.Name = SourceMember.CountryName
    WHERE NOT EXISTS
    (
        SELECT 1
        FROM dbo.SchedTriageMembers AS ExistingMember
        WHERE
            LOWER(LTRIM(RTRIM(ExistingMember.Email))) =
                LOWER(LTRIM(RTRIM(SourceMember.Email)))
            OR
            (
                LOWER(LTRIM(RTRIM(ExistingMember.FirstName))) =
                    LOWER(LTRIM(RTRIM(SourceMember.FirstName)))
                AND
                LOWER(LTRIM(RTRIM(ExistingMember.LastName))) =
                    LOWER(LTRIM(RTRIM(SourceMember.LastName)))
            )
    );

    DECLARE @InsertedCount int = @@ROWCOUNT;

    COMMIT TRANSACTION;

    SELECT
        @InsertedCount AS InsertedMemberCount;

    /*
        Final validation result.
    */
    SELECT
        Member.MemberId,
        Member.FirstName,
        Member.LastName,
        Team.Name AS TeamName,
        Country.Name AS CountryName,
        Member.Email,
        Member.CreatedAt
    FROM dbo.SchedTriageMembers AS Member
    INNER JOIN dbo.SchedTeams AS Team
        ON Team.TeamId = Member.TeamId
    INNER JOIN dbo.SchedCountries AS Country
        ON Country.CountryId = Member.CountryId
    WHERE EXISTS
    (
        SELECT 1
        FROM @MembersToInsert AS SourceMember
        WHERE
            LOWER(LTRIM(RTRIM(SourceMember.Email))) =
                LOWER(LTRIM(RTRIM(Member.Email)))
    )
    ORDER BY
        Member.LastName,
        Member.FirstName;
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
    BEGIN
        ROLLBACK TRANSACTION;
    END;

    THROW;
END CATCH;
GO

Finally, provided this type of prompt to create team members and add them to each of the teams that are part of this scheduler.

Combing Data

Next, I wanted to combined two shifts into one. Instead of writing the code myself I used M365 Copilot with SQL to do the work for me. I told it the two shifts I wanted to combine, and let it provide the TSQL code for making the change.

This is the prompt I provided. Notice, my prompt is not all that specific. However, Copilot is still able to understand my intent and generate the correct script.

I want to combine these two shifts into one 
'Morning Triage 8 am - 1pm MST' shift. "INSERT [dbo].[SchedShifts] ([ShiftId], [TeamId], [Name], [SortOrder], [StartTime], [EndTime]) VALUES (1, 1, N'Morning Triage 8 AM-10:30 AM MST', 1, N'08:00', N'10:30')
INSERT [dbo].[SchedShifts] ([ShiftId], [TeamId], [Name], [SortOrder], [StartTime], [EndTime]) VALUES (2, 1, N'10:30-1:00 MST', 2, N'10:30', N'13:00')" 
Give me the tsql scripts to make that change.


Additionally, combine these two shifts: 
"INSERT [dbo].[SchedShifts] ([ShiftId], [TeamId], [Name], [SortOrder], [StartTime], [EndTime]) VALUES (3, 1, N'Afternoon Triage 1:00-3:30 MST', 3, N'13:00', N'15:30')
INSERT [dbo].[SchedShifts] ([ShiftId], [TeamId], [Name], [SortOrder], [StartTime], [EndTime]) VALUES (4, 1, N'Evening 3:30 PM-6PM MST', 4, N'15:30', N'18:00')" 
to one shift named 'Afternoon/Evening Triage 1pm - 6pm MST'

This is the script it produced. Because I told Copilot the unique identifier information in my request, it knew enough to make the changes.

SET XACT_ABORT ON;

BEGIN TRY
    BEGIN TRANSACTION;

    ------------------------------------------------------------
    -- 1. Combine Shift 1 and Shift 2 into Shift 1
    ------------------------------------------------------------

    UPDATE dbo.SchedShifts
    SET
        Name      = N'Morning Triage 8 AM - 1 PM MST',
        SortOrder = 1,
        StartTime = N'08:00',
        EndTime   = N'13:00'
    WHERE ShiftId = 1
      AND TeamId = 1;


    ------------------------------------------------------------
    -- 2. Move any assignments for Shift 2 to Shift 1
    ------------------------------------------------------------

    UPDATE dbo.SchedScheduleAssignments
    SET ShiftId = 1
    WHERE ShiftId = 2
      AND TeamId = 1;


    ------------------------------------------------------------
    -- 3. Delete old Shift 2
    ------------------------------------------------------------

    DELETE FROM dbo.SchedShifts
    WHERE ShiftId = 2
      AND TeamId = 1;


    ------------------------------------------------------------
    -- 4. Combine Shift 3 and Shift 4 into Shift 3
    ------------------------------------------------------------

    UPDATE dbo.SchedShifts
    SET
        Name      = N'Afternoon/Evening Triage 1 PM - 6 PM MST',
        SortOrder = 2,
        StartTime = N'13:00',
        EndTime   = N'18:00'
    WHERE ShiftId = 3
      AND TeamId = 1;


    ------------------------------------------------------------
    -- 5. Move any assignments for Shift 4 to Shift 3
    ------------------------------------------------------------

    UPDATE dbo.SchedScheduleAssignments
    SET ShiftId = 3
    WHERE ShiftId = 4
      AND TeamId = 1;


    ------------------------------------------------------------
    -- 6. Delete old Shift 4
    ------------------------------------------------------------

    DELETE FROM dbo.SchedShifts
    WHERE ShiftId = 4
      AND TeamId = 1;


    ------------------------------------------------------------
    -- 7. Re-sequence the remaining F&SC shifts
    ------------------------------------------------------------

    UPDATE dbo.SchedShifts
    SET SortOrder =
        CASE ShiftId
            WHEN 1 THEN 1
            WHEN 3 THEN 2
            WHEN 5 THEN 3
            WHEN 6 THEN 4
            WHEN 7 THEN 5
            WHEN 8 THEN 6
        END
    WHERE TeamId = 1
      AND ShiftId IN (1, 3, 5, 6, 7, 8);


    COMMIT TRANSACTION;


    ------------------------------------------------------------
    -- Validation
    ------------------------------------------------------------

    SELECT
        ShiftId,
        TeamId,
        Name,
        SortOrder,
        StartTime,
        EndTime
    FROM dbo.SchedShifts
    WHERE TeamId = 1
    ORDER BY SortOrder;

END TRY
BEGIN CATCH

    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;

    THROW;

END CATCH;
GO

Advanced Inserts

Next, in my example, I want to assign team members who are eligible to work each shift using the data I already have in Excel. Typically this would be a lot of manual work to write insert statements for many different records. I also would need to look up the proper identifiers for each team member and shift.

Instead, M365 Copilot with SQL makes this very easy. It understands what I am trying to do with very little context and generates what I need.

Give me the tsql script to assign these people (ignore duplicates) to the 'Morning triage' shift. "Will, Liam, Lucas, Olivia, Emma"

Impressively, Copilot generated the correct SQL code, even adding additional validation checks.

/*
    Assign Morning Triage members
    ShiftId 1 = Morning Triage 8 AM - 1 PM MST
*/

DECLARE @ShiftId int = 1;

-- Validate the shift exists
IF NOT EXISTS
(
    SELECT 1
    FROM dbo.SchedShifts
    WHERE ShiftId = @ShiftId
      AND TeamId = 1
)
BEGIN
    THROW 50001, 'Morning Triage ShiftId 1 was not found.', 1;
END;


DECLARE @Members table
(
    FirstName nvarchar(100),
    LastName  nvarchar(100)
);

INSERT INTO @Members
(
    FirstName,
    LastName
)
VALUES
    (N'Will',    N'Smith'),
    (N'Liam',    N'Dallas'),
    (N'Lucas', N'Doe'),
    (N'Olivia',  N'Danger'),
    (N'Emma',   N'Marlow');


-- Insert only members not already assigned to this shift
INSERT INTO dbo.SchedShiftMembers
(
    ShiftId,
    MemberId
)
SELECT
    @ShiftId,
    tm.MemberId
FROM @Members m
INNER JOIN dbo.SchedTriageMembers tm
    ON tm.FirstName = m.FirstName
   AND tm.LastName = m.LastName
   AND tm.TeamId = 1
WHERE NOT EXISTS
(
    SELECT 1
    FROM dbo.SchedShiftMembers sm
    WHERE sm.ShiftId = @ShiftId
      AND sm.MemberId = tm.MemberId
);


-- Validate the resulting assignments
SELECT
    s.ShiftId,
    s.Name AS ShiftName,
    tm.MemberId,
    tm.FirstName,
    tm.LastName,
    tm.Email
FROM dbo.SchedShiftMembers sm
INNER JOIN dbo.SchedShifts s
    ON s.ShiftId = sm.ShiftId
INNER JOIN dbo.SchedTriageMembers tm
    ON tm.MemberId = sm.MemberId
WHERE sm.ShiftId = @ShiftId
ORDER BY
    tm.LastName,
    tm.FirstName;
GO

After that, I repeated the prompts for each of the shifts. However, I probably could have just taken a screenshot of the list of names, along with the shift, and saved even more time.

Conclusion

Microsoft M365 Copilot with SQL can be very effective even with little context. This is a very random example, but the purpose is not to have you recreate this application. But to apply this same type of process to your own scenarios. Simply provide Copilot with context about the table schema you are working with. Then, provide it any context it needs to know about your data. Finally, ask it for what you need, providing it the data and instructions in whatever format you already have it in. Of course there are limitations, but I think you will be surprised by how good AI has become at understanding context, and discerning your intent. By practicing these skills you will safe time in many ways that were never possible before.

Peter Ramer
Peter Ramer is a part of the Managed Application Services team at RSM working on Microsoft Dynamics 365. He focuses on the Retail and Commerce industries. When he is not solving problems and finding ways to accelerate his clients' business, he enjoys time with his three kids and amazing wife.

Share this:

Leave a Reply

Your email address will not be published. Required fields are marked *

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑