Cześć, napisałem funkcję, ale podejrzewam, że można ją napisać lepiej.
Jest to zwykła funkcja skalarna, ma zadanie dopasować zmianę do pracownika.

Tzn.

Jest sobie pracownik. On o którejś godzinie rozpoczął pracę(wcale nie musiał zakończyć).

I jest tabela ze zmianami. Zmiana może się rozpocząć np. od godziny 08:00 do godziny 08:05 i zakończyć np. od godziny 16:00 do 16:05.

Mam nadzieję, że wszystko zrozumiałe póki co. No i teraz chodzi o to, żeby dopasować zmianę pracownikowi.

W tym momencie robię to tak, że:
Najpierw sprawdzam idealny przypadek, czyli taki, że pracownik wszedł i wyszedł idealnie w godzinach zmiany. Czyli wg powyższego przykładu wszedł powiedzmy o 08:01, a wyszedł o 16:00.

Jeśli jednak nie dopasowano żadnej zmiany, kolejnym krokiem jest próba dopasowania na podstawie samej godziny wejścia(co też nie jest do końca dobre).

Czyli biorę sobie dwie zmiany. 1. Pracownik wszedł przed rozpoczęciem zmiany, 2. pracownik wszedł po rozpoczęciu zmiany. Następnie mniejsza różnica(między wejściem pracownika i rozpoczęciem zmiany) oznacza, że to właśnie ta zmiana ma być dopasowana.

Ja w mojej funkcji mam:
1 zwykły SELECT
2 zagnieżdżone SELECTY w kolejnym SELECTcie.

Wygląda ona mniej więcej tak:
(mniej więcej, bo pomijam kilka nieistotnych dla zagadnienia warunków)

ALTER FUNCTION [dbo].[MatchShift]
(
	@employeeID bigint, -- id pracownika
	@firstIn DATETIME, -- pierwsze wejście pracownika
	@lastOut DATETIME = null -- ostatnie wyjście pracownika	
)
RETURNS bigint
AS
BEGIN
    if @firstIn is null return null

    DECLARE @result BIGINT
    DECLARE @id BIGINT --pomocnicza
	
    SET @firstIn = [dbo].get_time(@firstIn) -- pozbywam się części daty, zostaje sama godzina

    -- najpierw zakładam najlepszy przypadek
    if @lastOut is not null
    BEGIN
        SET @lastOut = [dbo].get_time(@lastOut) -- pozbywam się części daty, zostaje sama godzina
  
        SELECT @result = ID 
        FROM [dbo].shifts
        WHERE [dbo].get_time(beginFrom)>=@firstIn 
	AND [dbo].get_time(beginTo)<=@firstIn
	AND [dbo].get_time(endFrom)>=@lastOut
	AND [dbo].get_time(endTo)<=@lastOut
    END

    -- jeśli result jest nullem, znaczy, że koleś nie wpasował się idealnie
    IF @result is null
    begin
        -- dopasowuję zmianę wg wejścia
        SELECT top 1 @result = res.ID 
        FROM
        (
            SELECT top 1 ID, abs(datediff(second, [dbo].get_time(beginFrom), @firstIn)) as diff 
            FROM [dbo].shifts
            WHERE [dbo].get_time(beginFrom)>=@firstIn 

            UNION ALL

            SELECT top 1 ID, abs(datediff(second, [dbo].get_time(beginFrom), @firstIn)) as diff 
            FROM [dbo].shifts
            WHERE [dbo].get_time(beginFrom)<=@firstIn 
        ) as res			
        ORDER by res.diff asc
		
    end	

    RETURN @result
END

No, to jakby ktoś miał jakiś pomysł na optymalizację tego(czy w ogóle sie da) i ewentualnie uwzględnienie też godziny wyjścia, to byłoby zajebiście.