2017-09-18 4 views
1

Est-ce que des gourous C#/T-SQL peuvent m'aider? J'ai du mal à convertir ce code C# en T-SQL.C# to T-SQL - Trouver le plus proche de la semaine

Voici le code C#:

 public (int distance, int absoluteDistance) MinimumDayOfWeekDistance(DayOfWeek dayOfWeekOne, 
     DayOfWeek dayOfWeekTwo) 
    { 
     int forwardDaysDifference(int iteratorDayOfWeekOne, int iteratorDayOfWeekTwo) => iteratorDayOfWeekTwo - 
                         iteratorDayOfWeekOne + 
                         ((iteratorDayOfWeekOne > 
                          iteratorDayOfWeekTwo) 
                          ? 7 
                          : 0); 

     int forwardOneTwo = forwardDaysDifference((int) dayOfWeekOne, (int) dayOfWeekTwo); 
     int forwardTwoOne = forwardDaysDifference((int) dayOfWeekTwo, (int) dayOfWeekOne); 
     if (forwardOneTwo < forwardTwoOne) 
     { 
      return (forwardOneTwo, forwardOneTwo); 
     } 
     return (-forwardTwoOne, forwardTwoOne); 
    } 

    public int DaysToClosestDayOfWeek(DayOfWeek dayOfWeekOne, List<DayOfWeek> dayOfWeekList) 
    { 
     return dayOfWeekList.Select(dayOfWeek => MinimumDayOfWeekDistance(dayOfWeekOne, dayOfWeek)) 
      .Aggregate((x, y) => (x.absoluteDistance < y.absoluteDistance) 
       ? x 
       : ((x.absoluteDistance == y.absoluteDistance) ? ((x.distance > 0) ? x : y) : y)).distance; 
    } 

Et voici la mise en œuvre:

int dayOfWeekDistance = this.DaysToClosestDayOfWeek(passedInDateParameter.DayOfWeek, myDayOfWeekList); 
passedInDateParameter = passedInDateParameter.AddDays(dayOfWeekDistance); 

L'idée est que vous avez une liste (un DayOfWeekList du côté C#), et que la liste peut être rempli avec n'importe quel jour de la semaine. Peut être lundi et mardi, peut être mardi, mercredi, vendredi et samedi, etc.

Un paramètre DateTime transmis est comparé à cette liste et est mis à jour en fonction du jour de la semaine où il est le plus proche. la liste. Par exemple, si le paramètre DateTime transmis est un dimanche et que ma liste DayOfWeek contient un mercredi et un samedi, le paramètre doit être ramené au samedi car il est le plus proche dans la liste. De même, si ma liste contient les dimanches, lundis et samedis, et que le paramètre passé est jeudi, alors le paramètre devra être déplacé vers samedi. Enfin, si le paramètre est équidistant de deux jours de semaine dans la liste (mercredi est passé et lundi et vendredi sont dans la liste ... ou dimanche est passé et mardi et vendredi sont dans la liste), puis le paramètre doit être avancé au prochain jour de la semaine le plus proche (qui, dans le premier cas, serait vendredi, et mardi dans le second cas). Jusqu'à présent, du côté SQL, j'ai une variable VARCHAR représentant une liste de nombres basée sur chaque jour de la semaine. Par exemple, la variable serait quelque chose comme "126" si dimanche, lundi et vendredi étaient censés être contenus dans la variable.

En outre, du côté SQL, il serait optimal de renvoyer la distance minimale du paramètre d'entrée du jour de la semaine le plus proche dans la liste. Par exemple, si je passe un jeudi (ou un 5 pour la façon dont il est actuellement implémenté), et dimanche, lundi et mardi, sont dans la liste (ou 1,2 et 3), un -2. devrait être retourné (puisque mardi est le plus proche de jeudi dans la liste), de cette façon je peux soustraire 2 jours de ma variable datetime cible (la variable datetime sort du cadre de cette question, juste ici à titre de référence). En d'autres termes, les distances du paramètre d'entrée par rapport au jour de la semaine le plus proche doivent être renvoyées, et elles peuvent être positives ou négatives afin de représenter efficacement le nombre de jours à ajouter ou à soustraire. Jusqu'à présent, l'implémentation fonctionne très bien en C#, j'ai juste du mal à le convertir en SQL parce que ce n'est pas ma meilleure langue.

Toute aide à ce sujet serait grandement appréciée.

+0

Comment est dimanche plus proche de jeudi que le samedi est? –

+0

@DanBracuk Je suis confus quant à ce que vous voulez dire. Parlez-vous du deuxième exemple que j'ai donné en parlant de la liste DayOfWeek? – wibby35

Répondre

0

J'ai une réponse pour vous.Tout d'abord, SQL Fiddle

Voici le SQL:

create table test_Table (Days int); 

declare @DaysList int 
declare @x int 
declare @Day int 

set @DaysList = 36 
/*This is the variable that you mention in your original question. 
For example, 36 means Tuesday and Friday*/ 

set @Day = 1 
/*This is the day that you're checking against*/ 

set @x = 1 
/*This is just our while loop variable*/ 

WHILE @x <= len(@DaysList) 
    BEGIN 
    INSERT INTO test_Table 
    SELECT substring(cast(@DaysList as nvarchar(7)),@x,1) 
    SET @X = @X + 1 
    END 
/*The while loop is taking each digit in your @DaysList variable 
and putting it in its own row. 
This makes it so that we can compare our day to each day in the list 
more easily.*/ 

;with cte as (SELECT case when abs(@Day-days) < 7-abs(@Day-days) 
      then abs(@Day-days) 
      else 7-abs(@Day-days) end daysDiff 
/*This field finds the number of days between the @Day value and the day 
from @DaysList that we're comparing to. Basically, the smaller the number 
the better.*/ 
, days 
/*This value is going to be the result of our query*/ 
, case when [email protected] between 0 and 8 
    then [email protected] 
    when [email protected] between 0 and 8 
    then [email protected] 
    else -100 end a 
/*This is doing a bunch of stuff to meet the requirement of finding the "next day" 
if the day is in the next week (for example, if @DaysList is Friday and Sunday (6 and 1) 
and our @Day is Saturday (7), we want to show 1, not 6.*/ 
FROM #test_Table) 

SELECT TOP 1 days FROM cte ORDER BY DaysDiff Asc, a 
/*this just gives us our final result.*/ 

Si vous préférez avoir cela comme une fonction SQL, vous pouvez créer la fonction:

create function ClosestDayToDate(@Day int, @DaysList int) 
RETURNS int AS BEGIN 

declare @x int 
declare @result int 
declare @test_table table (days int) 
set @x = 1 

WHILE @x <= len(@DaysList) 
    BEGIN 
    INSERT INTO @test_Table 
    SELECT substring(cast(@DaysList as nvarchar(7)),@x,1) 
    SET @X = @X + 1 
    END 

;with cte as (SELECT case when abs(@Day-days) < 7-abs(@Day-days) 
      then abs(@Day-days) 
      else 7-abs(@Day-days) end daysDiff 
, days 
, case when [email protected] between 0 and 8 
    then [email protected] 
    when [email protected] between 0 and 8 
    then [email protected] 
    else -100 end a 
FROM @test_Table) 

Select @Result = (SELECT TOP 1 days FROM cte ORDER BY DaysDiff Asc, a) 

return @result 
END 

Ensuite, vous pouvez exécuter la fonction:

SELECT dbo.ClosestDayToDate(1,72) 

Qui retournerait 2 .

Si vous avez besoin de plus de précisions sur quelque chose, s'il vous plaît faites le moi savoir.

EDIT: Je suis toujours vraiment fasciné par cette fonction, donc je continue à l'éditer pour la raccourcir. Je pense que c'est le plus que je peux obtenir sans complètement re-travailler la façon dont il est écrit, si:

create function ClosestDayToDate(@Day int, @DaysList int) 
RETURNS int AS BEGIN 

declare @x int 
declare @result int 
declare @test_table table (days int) 
set @x = 1 

WHILE @x <= len(@DaysList) 
    BEGIN 
    INSERT INTO @test_Table 
    SELECT substring(cast(@DaysList as nvarchar(7)),@x,1) 
    SET @X = @X + 1 
    END 

;with cte as (SELECT days 
, case when [email protected] between 0 and 8 
     then [email protected] 
     when [email protected] between 0 and 8 
     then [email protected] 
     end a 

FROM @test_Table) 

Select @Result = (SELECT TOP 1 days FROM cte ORDER BY a) 

return @result 
END 

Voici le SQL Fiddle pour la fonction. Editer: Selon votre demande, j'ai mis à jour la fonction. Maintenant, il montrera le nombre de jours entre le "jour" mis en, et le jour le plus proche de la "liste du jour". Si le jour est antérieur, il affichera un nombre négatif.

FYI - Je n'ai pas testé cela aussi exhaustivement que les versions précédentes, mais dans les tests que j'ai faits, ça a bien fonctionné.

create function ClosestDayToDate(@Day int, @DaysList int) 
RETURNS int AS BEGIN 

declare @x int 
declare @result int 
declare @test_table table (days int) 
set @x = 1 

WHILE @x <= len(@DaysList) 
    BEGIN 
    INSERT INTO @test_Table 
    SELECT substring(cast(@DaysList as nvarchar(7)),@x,1) 
    SET @X = @X + 1 
    END 

;with cte as (SELECT days 
, case when abs([email protected]) < [email protected] then [email protected] else [email protected] end b 
, case when abs([email protected]) < [email protected] then abs([email protected]) else [email protected] end c   
FROM @test_Table) 

Select @Result = (SELECT TOP 1 b FROM cte ORDER BY c, b desc) 

return @result 
END 

Et le SQL Fiddle.

+0

Nice! Cela a bien fonctionné! J'ai juste une question. Est-il possible de retourner un jour négatif? Par exemple, si le paramètre de date passé était un mercredi et que mardi et samedi figuraient dans la liste, mardi est le jour le plus proche. Serait-il possible de renvoyer -1 comme valeur de retour dans la fonction? De cette façon, je peux correctement comptabiliser l'ajout de jours à une variable DateTime. Tels que: SET DateTimeVar = DATEADD (JOUR, -1, DATEADD (dd, SomeVar, SomeOtherVar)). De cette façon, la date peut effectivement traverser en avant et en arrière. Cela a-t-il du sens? Sinon c'est parfait !! – wibby35

+0

Je suis désolé, ceci est une erreur de ma part. Votre première solution fonctionnait logiquement, mais je ne savais pas clairement ce que je voulais sortir. Est-il possible de renvoyer la DISTANCE minimum à partir du jour d'entrée et des jours dans la liste? Par exemple, si je sais SELECT dbo.ClosestDayToDate (1,57), puisque Saturday (7) est le plus proche de Sunday (1), il serait optimal de retourner -1, de cette façon je peux soustraire 1 jour de ma variable datetime et ramène-le à la bonne date. De même, en gardant à l'esprit la règle de priorité équidistante, (1,36) devrait retourner 2 (dimanche est entre mardi et vendredi) ... (4,257) = 1, (4,12) = - 2 .. – wibby35

+0

Est-ce que cela a du sens? ? N'hésitez pas à me faire savoir si vous avez besoin d'éclaircissements. – wibby35