Je compte les jours ouvrables entre deux dates. Certains de mes résultats devraient légitimement être NULL, mais certains sont retournés comme NULL qui devraient plutôt être 0. Voici la requête que j'utilise:

SELECT
  ROW_NUMBER() OVER (ORDER BY Date_key asc) BusinessDaysID,
  BSDAYS * CASE WHEN B.ClosingDate > B.ApprovalDate THEN -1 ELSE 1 END FinaldDateCount
FROM
  DIM_DATE B
  CROSS APPLY (
    SELECT NULLIF(COUNT(*),0) BSDAYS
    FROM CALENDAR
    WHERE
      BSDAYS >= CASE WHEN B.ClosingDate > B.ApprovalDate THEN B.ApprovalDate ELSE B.ClosingDate END
      AND BSDAYS < CASE WHEN B.ClosingDate > B.ApprovalDate THEN B.ClosingDate ELSE B.ApprovalDate END
  ) R1

Exemple de source DIM_DATE B:

Date_Key ClosingDate ApprovalDate 38544 2018-01-18 2018-02-05 38545 NULL NULL 38546 NULL NULL 38547 NULL NULL 38548 2018-05-01 2018-05-01 38549 NULL NULL 38550 NULL NULL 38551 NULL NULL 38552 2018-03-08 2018-03-15 38553 NULL NULL 38554 NULL 2018-04-25 38555 NULL NULL

Exemple de calendrier source:

BSDAYS 2018-04-27 2018-04-30 2018-05-01 2018-05-02 2018-05-03 2018-05-04 2018-05-07 2018-05-08 2018-05-09 2018-05-10 2018-05-11 2018-05-14 2018-05-15 2018-05-16 2018-05-17 2018-05-18 2018-05-21 2018-05-22 2018-05-23

Voici ce que je reçois maintenant:

BusinessDaysID FinalDateCount 38544 12 38545 NULL 38546 NULL 38547 NULL 38548 NULL 38549 NULL 38550 NULL 38551 NULL 38552 5 38553 NULL 38554 NULL 38555 NULL

Et j'aimerais:

BusinessDaysID FinalDateCount 38544 12 38545 NULL 38546 NULL 38547 NULL 38548 0 38549 NULL 38550 NULL 38551 NULL 38552 5 38553 NULL 38554 NULL 38555 NULL

Si vous remarquez que le Date_Key 38548 arrive comme NULL et devrait être 0.

Quel est le problème avec ma requête et comment puis-je y remédier?

1
JC_BI 23 mai 2018 à 18:49

3 réponses

Meilleure réponse

Déplacement du NullIF et ajout d'un peu de logique dans la requête supérieure.

SELECT
  ROW_NUMBER() OVER (ORDER BY Date_key asc) BusinessDaysID,
 CASE
    WHEN B.ApprovalDate=B.ClosingDate THEN 0
    ELSE NULLIF(BSDAYS,0)
 END * CASE WHEN B.ClosingDate > B.ApprovalDate THEN -1 ELSE 1 END FinaldDateCount
FROM
  DIM_DATE B
  CROSS APPLY (
    SELECT COUNT(*) BSDAYS
    FROM CALENDAR
    WHERE
      BSDAYS >= CASE WHEN B.ClosingDate > B.ApprovalDate THEN B.ApprovalDate ELSE B.ClosingDate END
      AND BSDAYS < CASE WHEN B.ClosingDate > B.ApprovalDate THEN B.ClosingDate ELSE B.ApprovalDate END
  ) R1
1
UnhandledExcepSean 23 mai 2018 à 16:26

Je suggérerais une approche quelque peu différente. Le CROSS APPLY est un MS-ism, et un peu difficile pour moi de raisonner. Il ne semble pas que cela vous gagne beaucoup par rapport aux sous-requêtes ordinaires. C'est beaucoup plus facile à lire pour moi, et ça devrait faire le travail:

SELECT
  Date_Key AS BusinessDaysID,
  CASE 
    WHEN B.ApprovalDate <= B.ClosingDate THEN
      (SELECT COUNT(*) FROM Calendar C
       WHERE C.BSDAYS BETWEEN B.ApprovalDate AND B.ClosingDate)
    WHEN B.ApprovalDate > B.ClosingDate THEN
      (SELECT -COUNT(*) FROM Calendar C
       WHERE C.BSDAYS BETWEEN B.ClosingDate AND B.ApprovalDate)
    ELSE
      NULL
  END AS FinalDateCount
FROM
  DIM_DATE B

Notez qu'il repose sur le fait que lorsqu'au moins l'un de B.ClosingDate et B.ApprovalDate est NULL, alors ni B.ApprovalDate <= B.ClosingDate ni B.ApprovalDate > B.ClosingDate ne sont évalués à vrai. Dans ces cas, le nombre de dates est sélectionné comme NULL directement, sans sous-requête. Sinon, la (sous) requête agrégée appropriée est exécutée sur la table CALENDAR.

1
John Bollinger 23 mai 2018 à 16:53
SELECT
  ROW_NUMBER() OVER (ORDER BY Date_key asc) BusinessDaysID,
  BSDAYS * CASE WHEN B.ClosingDate = B.ApprovalDate THEN 0
                WHEN B.ClosingDate > B.ApprovalDate THEN -1  
                ELSE 1 
            END FinaldDateCount
FROM
  DIM_DATE B
  CROSS APPLY (
    SELECT NULLIF(COUNT(*),0) BSDAYS
    FROM CALENDAR
    WHERE
      BSDAYS >= CASE WHEN B.ClosingDate > B.ApprovalDate THEN B.ApprovalDate ELSE B.ClosingDate END
      AND BSDAYS < CASE WHEN B.ClosingDate > B.ApprovalDate THEN B.ClosingDate ELSE B.ApprovalDate END
  ) 
0
Dheerendra 23 mai 2018 à 16:16