简体   繁体   中英

SQL Server dynamic pivot table needed with dates as columns

I have searched this forum and others and still can't find a working solution. I have an Employees table and an EmpCalendar table in MS SQL. The table data looks like the following, simplified of course for this forum;

Employees Table

user_id Employee
1 Crystal Dee
4 Darryl Haster

EmpCalendar Table

CalId User_id Date_Assigned Position StartTime-EndTime
1 1 2202-11-29 LPN 7:00am - 2:30pm
2 4 2202-11-29 RN
3 1 2202-11-30 LPN
4 4 2202-11-30 RN 7:00am - 3:30pm

As you can see there're multiple people working each day, so each day has numerous entries and the basic output I do in SQL (for a given date range) would look like the EmpCalendar table above with the Employee name included from the Employees table (inner join and the sql is involved as I also don't want to show anyone that's off for that day, etc.). Our scheduler needs an overview of a week at a time or so to see what open spots there are, so the dates should be done as columns, not output as rows as in the EmpCalendar table. The desired output would be as follows:

Position Employee 2202-11-29 2202-11-30
LPN Crystal Dee 7:00am - 2:30pm 7:00am - 2:30pm
RN Darryl Haster 7:00am - 3:30pm
LPN Crystal Dee 7:00am - 2:30pm
RN Darryl Haster 7:00am - 3:30pm 7:00am - 3:30pm

I've tried pivot queries in my SQL statement but got errors and have tried numerous attempts to find similar questions like mine and then altering the answers to my specific tables but mine involves dates and not just nvarchar entries which are what most of the examples involve, but they are DATE entries in SQL. I've never done a pivot before in sql and have only recently learned they exist in researching why I can't get the output of dates as columns as I need, and usually manipulate the data in my Coldfusion code. Here's a sample of my current SQL query to get a list of calendar entries for a certain date range selected and coming from a CF form to this page:

SELECT  EmpCalendar.position, EmpCalendar.Days_date
, EmpCalendar.Shift, EmpCalendar.UnitWorking, EmpCalendar.StartTime
, EmpCalendar.EndTime, EmpCalendar.HoursWorked, pCalendar.CountOfHours
, EmpCalendar.user_id, EmpCalendar.Comments, Employees.fullname
, Employees.FirstName, Employees.LastInit

FROM EmpCalendar INNER JOIN Employees ON EmpCalendar.user_id = Employees.user_id

  where (LEN(EmpCalendar.Off_type) < 1 or EmpCalendar.Off_type IS NULL)           

  and EmpCalendar.Days_date >= #Startdate#  
  and EmpCalendar.Days_date <= #Enddate# and EmpCalendar.Shift = '1' 

  order by Days_date 

I think the spirit of what you are asking for is slightly different than your desired output, so my apologies if this solution doesn't work for your situation. Also interesting, it appears that your tagging is for MySQL, but your question is MS SQL. I'll assume it is meant for MS SQL.

-- Using Common Table Expressions just to allow me to reproduce data set locally
;WITH CTE_Employees AS (
    SELECT *
    FROM (
            VALUES (1,'Crystal Dee'),
                (4,'Darryl Haster')
        ) AS a([user_id],Employee)
),
CTE_EmpCalendar AS (
    SELECT *
    FROM (
        VALUES (1,1,'2022-11-29','LPN','07:00-14:30'),
        (2,4,'2022-11-29','RN',NULL),
        (3,1,'2022-11-30','LPN',NULL),
        (4,4,'2022-11-30','RN','07:00-15:30')
    ) AS a(CalId,[User_id],Date_Assigned,Position,ShiftTimes)
)

SELECT Position,
    Employee,
    Pivoted.*
FROM (
    SELECT b.Position,
        a.Employee,
        b.ShiftTimes,
        b.Date_Assigned
    FROM CTE_Employees AS a

        INNER JOIN CTE_EmpCalendar AS b
        ON a.[user_id] = b.[User_id]
) AS SourceData
PIVOT (
        MAX(ShiftTimes)
        FOR Date_Assigned IN (
            [2022-11-29],
            [2022-11-30],
            [2022-12-01] -- This is for a pretend scenario in which CF has generated the range of dates throughout the week
    )
) AS Pivoted

I see you mentioned cold fusion as well. I'm making the assumption that you have the start date and end dates for your report in mind and can dynamically loop in a cfquery tag to generate the expected columns that will appear in the FOR Date_Assigned IN (... CF Loop Here...) code.

Just a few other small notes. I would anticipate that the start time and end time should be in separate time data type'd columns. The dates in your outputs for the year 2202, and likely meant to be 2022, just worth noting in case that causes you issues when you get further in on the project.

Relavent documentation: https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-ver16

Hope this helps. Good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM