Je sais que cela est possible mais je ne sais pas comment le configurer . En gros, je dois extraire des données pour chaque employé, mais uniquement si elles répondent à certains critères basés sur quelques dates différentes.
Par exemple, si l'employé a été affecté à une entreprise avant le 6/1, il est compté automatiquement.
Si l'employé a été affecté à une entreprise après le 6/1, il n'est comptabilisé que s'il a passé un examen avec cette entreprise après la date à laquelle il a été affecté (c'est-à-dire qu'il a été affecté le 6/25 et que l'examen a été effectué le 7/1. cela devrait être compté. Si, par exemple, ils étaient assignés le 6/25 et que la révision se produisait le 6/15, ils ne compteraient pas pour cet employé)
Si l'employé est renvoyé d'une entreprise avant le 4/1, il n'est pas comptabilisé. S'ils sont supprimés à partir du 4/1, cela compte.
Les colonnes de clé sont donc Date de création de la révision, Date de début et Date de fin dans la table employé-client.
Je crois que cela devrait être soit un type de sous-requête qui renvoie la date de début pour l'employé avec ce client, puis compare la date de révision sur la base d'une instruction de cas évaluant cette date par rapport à la date de révision, mais je ne sais pas exactement comment procéder. .
Toute aide serait appréciée.
EDIT: Structure de la table/Données ci-dessous:
Table Employé-Client
ID EmpID CustID StartDate EndDate
1 4 10 10/1/2017 2/21/2018
2 4 11 10/1/2017 7/31/2018
3 4 15 10/1/2017 4/8/2018
4 4 17 6/1/2018 NULL (means still active with this employee)
5 4 19 5/18/2018 NULL
Tableau de données client
ID CustID ActivityDate Task
1 10 1/13/2018 Review
3 15 4/2/2018 Review
4 17 6/25/2018 Review
5 17 6/13/2018 Client Engagement
6 17 6/29/2018 Client Engagement
7 19 5/25/2018 Client Engagement
8 19 6/28/2018 Review
Donc, pour cet exemple, je souhaite une requête qui renvoie les ID client suivants avec des données basées sur les critères:
Espérons que cette explication et cette panne ont du sens.
UPDATE: Voici les scripts de table et les résultats attendus:
CREATE TABLE Cust_Employee(
Cust_Emp_ID int IDENTITY(1,1) NOT NULL,
Cust_ID int NOT NULL,
Emp_ID int NULL,
Start_Date datetime NULL,
End_Date datetime NULL,
CONSTRAINT PK_Cust_Employee PRIMARY KEY CLUSTERED
(
Cust_Emp_ID ASC
)WITH (PAD INEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON PRIMARY
)ON PRIMARY
GO
CREATE TABLE Cust_Data(
Cust_Data_ID int IDENTITY(1,1) NOT NULL,
Cust_ID int NULL,
Activity_Date datetime NULL,
Task VARCHAR(50) NULL
)
CONSTRAINT PK_Client_Data PRIMARY KEY CLUSTERED
(
Cust_Data_ID ASC
)WITH (PAD INEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON PRIMARY
)ON PRIMARY
GO
INSERT INTO Cust_Employee VALUES(4, 10, '10/1/2017', '2/21/2018')
INSERT INTO Cust_Employee VALUES(4, 11, '10/1/2017', '7/31/2018')
INSERT INTO Cust_Employee VALUES(4, 15, '10/1/2017', '4/8/2018')
INSERT INTO Cust_Employee VALUES(4, 17, '6/1/2018', NULL)
INSERT INTO Cust_Employee VALUES(4, 19, '5/18/2018', NULL)
INSERT INTO Cust _Data VALUES(10, '1/13/2018', 'Review')
INSERT INTO Cust _Data VALUES(15, '4/2/2018', 'Review')
INSERT INTO Cust _Data VALUES(17, '6/25/2018', 'Review')
INSERT INTO Cust _Data VALUES(17, '6/13/2018', 'Client Engagement')
INSERT INTO Cust _Data VALUES(17, '6/29/2018', 'Client Engagement')
INSERT INTO Cust _Data VALUES(19, '5/25/2018', 'Client Engagement')
INSERT INTO Cust _Data VALUES(19, '6/28/2018', 'Review')
Résultats attendus:
Je ne suis pas sûr d'avoir compris toute votre demande. En fait, il me manque quelque chose car les résultats que j’obtiens ne sont pas exactement les mêmes que vous .. Le code que j’ai préparé:
SELECT E.Cust_ID AS Emp_ID, E.Emp_ID AS Cust_ID, E.Start_Date, E.End_Date,
MAX(D.Activity_Date) AS Activity_Date, D.Task
FROM Cust_Employee E
LEFT OUTER JOIN Cust_Data D
ON E.Emp_ID = D.Cust_ID
WHERE COALESCE(E.End_Date, GETDATE()) > '20180401'
GROUP BY
E.Cust_ID, E.Emp_ID, E.Start_Date, E.End_Date,
D.Task
ORDER BY E.Cust_ID;[![enter image description here][1]][1]
Donc, ma requête montre une ligne supplémentaire pour Emp 19, ne sachant pas quelle est la condition qui éliminera, si vous me clarifiez, je corrigerai la réponse.
Premièrement, je dois reconnaître que les exigences pour moi ne sont pas claires à 100% car elles sont basées sur des exemples de ce qui est habituel dans la vie réelle. Il est nécessaire d'identifier clairement les règles de gestion à appliquer et la séquence (ordre) à appliquer. Donc, basé sur mon hypothèse, j'ai construit la solution suivante. L'avantage de cette solution est qu'il est très facile de déboguer en tant que:
:
WITH CTE AS (
SELECT E.Cust_ID AS Emp_ID, E.Emp_ID AS Cust_ID,
E.Start_Date, E.End_Date,
MAX(D.Activity_Date) AS Activity_Date, D.Task,
CASE
-- RULE -1: Removed Prior to 4/1 cutoff date
WHEN E.End_Date < '20180401' THEN -1
-- RULE 1: If the employee has had the customer past the 5/31 cutoff date, even though there is no review for the customer
WHEN E.End_Date > '20180531' THEN 1
-- RULE 2: If the employee had the customer past the 4/1 cutoff date before it was removed from them
WHEN D.Activity_Date > '20180401' AND D.Activity_Date <= E.End_Date THEN 2
-- RULE -2: Client engagement from 6/13/2018 does NOT get returned because it happened BEFORE the review was done with this client
WHEN D.Task = 'Client Engagement'
AND NOT EXISTS (SELECT 1 FROM Cust_Data D2 WHERE D2.Cust_ID = E.Emp_ID AND D2.Task = 'Review' AND D2.Activity_Date <= D.Activity_Date)
THEN -2
-- RULE 12: If the employee was assigned to a company before 6/1 they get counted automatically.
WHEN E.Start_Date <= '20180601' THEN 12
-- RULE 14: If EndDate later than June-1-2018
WHEN COALESCE(E.End_Date, GETDATE()) > '20180601' THEN 14
-- RULE 0: Other cases
ELSE 0
END AS [Rule]
FROM Cust_Employee E
LEFT OUTER JOIN Cust_Data D
ON E.Emp_ID = D.Cust_ID
--AND D.Activity_Date > '20180401'
GROUP BY
E.Cust_ID, E.Emp_ID, E.Start_Date, E.End_Date,
D.Task, D.Activity_Date
)
SELECT Emp_ID, Cust_ID, Start_Date, End_Date, Activity_Date, Task, [Rule]
FROM CTE
WHERE [Rule] > 0
ORDER BY Cust_ID, Start_Date, Activity_Date;
Le meilleur de cette méthode est qu'il calcule et affiche la règle qui a été appliquée. Elle peut donc être déboguée très facilement car la requête indique quelle règle a été appliquée. Si l'ordre des règles ou une règle est incorrect, il peut être détecté très rapidement et corrigé. Il en va de même pour les modifications futures, car normalement, ces règles basées sur les dates changent très souvent et nous avons besoin d’un moyen simple de conserver le code ..__ Enfin, j’espère que cet exercice vous donnera quelques idées pour les développements futurs, car la traçabilité et la prise en charge sont optimales. très important lors de la création de code.
Pour des logiques aussi complexes, je conseillerais les instructions CTE afin de créer des sous-groupes de lignes susceptibles d'apparaître dans le jeu de résultats final, afin de disposer d'une requête plus claire pour créer/maintenir et créer des règles positives/négatives, comme suit:
;WITH AssignedBefore as
(
--if the employee was assigned to a company before 6/1 they get counted automatically.
SELECT Cust_ID, Emp_ID
FROM Cust_Employee
WHERE Start_Date <= '20180601'
),
AssignedReviewed as
(
--If the employee was assigned to a company after 6/1 they only get counted IF they have a review with that company after the date they were assigned
SELECT Cust_ID, Emp_ID
FROM Cust_Employee E
CROSS APPLY (
SELECT 1 as Exist
FROM Cust_Data D
WHERE D.Cust_ID = E.Cust_ID
AND D.Task = 'Review'
AND D.Activity_Date > E.Start_Date
) C
WHERE E.Start_Date > '20180601'
),
RemovedAfter as
(
--If the employee gets removed from a company before 4/1 they dont get counted. If they are removed on or after 4/1 it counts.
SELECT Cust_ID, Emp_ID
FROM Cust_Employee
WHERE End_Date >= '20180401'
),
RemovedBefore as
(
--If the employee gets removed from a company before 4/1 they dont get counted. If they are removed on or after 4/1 it counts.
SELECT Cust_ID, Emp_ID
FROM Cust_Employee
WHERE End_Date <= '20180401'
)
--Positive Rules
SELECT * FROM AssignedBefore
UNION
SELECT * FROM AssignedReviewed
UNION
SELECT * FROM RemovedBefore
--Negative Rules
EXCEPT
SELECT * FROM RemovedBefore
Une fois que vous obtenez ce résultat pour les n-uplets de Cust/Emp devant apparaître dans le résultat, vous pouvez ajouter les informations dont vous avez besoin.
La façon dont j'aborderais cette requête deviendrait très conviviale avec les expressions de table courantes et EXISTS/NOT EXISTS.
Je me suis rendu compte que pour un employé donné, s’il y avait des engagements avec le client avant que l’employé ait eu une révision avec ce client, ils devraient être ignorés dans le cadre de cet employé. Pour cela, j'ai implémenté une expression de table commune (cte_engagements_to_ignore
) afin de filtrer ceux-ci . Les résultats de cette expression de table commune finissent par être des enregistrements employee/cust_data qui doivent être ignorés . Cela fonctionne en filtrant d'abord vers le bas toutes les missions, puis filtrer pour ne retenir que celles pour lesquelles il n’existait pas d’examen précédent ayant eu lieu après l’affectation de l’employé et avant la mission à laquelle nous comparons.
Nous interrogerons ensuite les tables de données employé/client et inclurons automatiquement si le client a démarré avant le 6/1 OR s'il existe une vérification qui a eu lieu après leur affectation à l'employé. Nous excluons ensuite les personnes non affectées avant le 4/1 ou celles dont l’engagement a été identifié devraient être ignorées pour l’employé concerné.
Très intriguant, en effet!
WITH cte_engagements_to_ignore AS
( -- filter out client engagements that happened prior to reviews
SELECT
A.Emp_ID,
B.Cust_Data_ID
FROM Cust_Employee A
INNER JOIN Cust_Data B
ON A.Cust_ID = B.Cust_ID
WHERE B.Task = 'Client Engagement'
AND NOT EXISTS
( -- exclude this client engagement if there was not a review for this customer prior to it
SELECT
*
FROM Cust_Data X1
WHERE A.Cust_ID = X1.Cust_ID
AND X1.Task = 'Review'
AND A.Start_Date < X1.Activity_Date -- review happened after assignment
AND B.Activity_Date > X1.Activity_Date -- review happened prior to engagement
)
)
SELECT
A.Emp_ID,
A.Cust_ID,
A.Start_Date,
A.End_Date,
B.Activity_Date,
B.Task
FROM Cust_Employee A
LEFT JOIN Cust_Data B
ON A.Cust_ID = B.Cust_ID
WHERE (
-- included automatically if started before 6/1
A.Start_Date < '2018-06-01'
-- or include if there is a review after assignment
OR EXISTS
(
SELECT
*
FROM Cust_Data X1
WHERE A.Cust_ID = X1.Cust_ID
AND A.Start_Date < X1.Activity_Date
AND X1.Task = 'Review'
)
)
-- exclude if unassigned prior to 4/1
AND ISNULL(A.End_Date, '2050-01-01') >= '2018-04-01'
-- filter out engagements we identified should be ignored
AND NOT EXISTS
(
SELECT
*
FROM cte_engagements_to_ignore X1
WHERE A.Emp_ID = X1.Emp_ID
AND B.Cust_Data_ID = X1.Cust_Data_ID
)
Cela aidera peut-être.
SELECT employee
FROM employee emp
JOIN employee-customer ecust ON ecust.empID = ecust.empID
JOIN customer cust ON cust.custID = ecust.custID and cust.Task = 'Review'
WHERE
(emp.StartDate <= '01062019' and (emp.EndDate <= '01042019' or emp.EndDate = NULL) or
( emp.StartDate <= cust.ActivityDate )
Mon approche consiste à obtenir les différents critères de règle à l'aide de CTE, puis à appliquer la logique dans la requête finale:
WITH Reviews AS (
SELECT d1.Cust_ID, 'true' AS HasActiveReview
FROM Cust_Data d1
INNER JOIN Cust_Data d2 ON d1.Cust_ID = d2.Cust_id
WHERE d1.Task = 'Review'
AND d2.Task = 'Client Engagement'
AND d1.Activity_Date >= d2.Activity_Date
),
RuleData as (
SELECT e.Cust_Emp_ID,
(CASE WHEN e.Start_Date >= '20180601' THEN 'true' ELSE 'false' END) AS StartAfter0601,
(CASE WHEN e.End_Date <= '20180401' THEN 'true' ELSE 'false' END) as EndBefore0401,
COALESCE(r.HasActiveReview, 'false') as HasReview
FROM Cust_Employee e
LEFT OUTER JOIN reviews r on e.Cust_ID = r.Cust_ID)
SELECT e.Emp_id, e.Cust_id, e.Start_Date, e.end_date, MAX(d.Activity_Date) AS Activity_Date, d.Task
FROM RuleData r
INNER JOIN Cust_Employee e on r.Cust_Emp_ID = e.Cust_Emp_ID
LEFT OUTER JOIN Cust_Data d on e.Cust_ID = d.Cust_ID
WHERE r.EndBefore0401 = 'false'
AND ((r.StartAfter0601 = 'true' AND r.HasReview = 'true') OR r.StartAfter0601 = 'false')
GROUP BY e.Emp_id, e.Cust_id, e.Start_Date, e.end_date, d.Task, r.Cust_Emp_ID, r.StartAfter0601, r.EndBefore0401, r.HasReview
ORDER BY e.Emp_id, e.Cust_id;
Si vous avez besoin de déboguer, il est facile d'ajouter les données de la règle à la fin de la requête pour voir pourquoi une ligne est renvoyée:
WITH Reviews AS (
SELECT d1.Cust_ID, 'true' AS HasActiveReview
FROM Cust_Data d1
INNER JOIN Cust_Data d2 ON d1.Cust_ID = d2.Cust_id
WHERE d1.Task = 'Review'
AND d2.Task = 'Client Engagement'
AND d1.Activity_Date >= d2.Activity_Date
),
RuleData as (
SELECT e.Cust_Emp_ID,
(CASE WHEN e.Start_Date >= '20180601' THEN 'true' ELSE 'false' END) AS StartAfter0601,
(CASE WHEN e.End_Date <= '20180401' THEN 'true' ELSE 'false' END) as EndBefore0401,
COALESCE(r.HasActiveReview, 'false') as HasReview
FROM Cust_Employee e
LEFT OUTER JOIN reviews r on e.Cust_ID = r.Cust_ID)
SELECT e.Emp_id, e.Cust_id, e.Start_Date, e.end_date, MAX(d.Activity_Date) AS Activity_Date, d.Task, r.Cust_Emp_ID, r.StartAfter0601, r.EndBefore0401, r.HasReview
FROM RuleData r
INNER JOIN Cust_Employee e on r.Cust_Emp_ID = e.Cust_Emp_ID
LEFT OUTER JOIN Cust_Data d on e.Cust_ID = d.Cust_ID
WHERE r.EndBefore0401 = 'false'
AND ((r.StartAfter0601 = 'true' AND r.HasReview = 'true') OR r.StartAfter0601 = 'false')
GROUP BY e.Emp_id, e.Cust_id, e.Start_Date, e.end_date, d.Task, r.Cust_Emp_ID, r.StartAfter0601, r.EndBefore0401, r.HasReview
ORDER BY e.Emp_id, e.Cust_id;
J'ai utilisé 'true' et false 'pour représenter les valeurs booléennes, vous pouvez utiliser 1 et 0 bits si vous préférez.
L'exécution de la requête renvoie une ligne supplémentaire pour Cust_Id 19, en renvoyant à la fois l'enregistrement "Engagement client" et celui "Révision". Je ne suis pas sûr de savoir pourquoi cela ne devrait pas être fait lorsque vous voulez les deux lignes pour Cust_Id 17 et il semble que la même chose devrait s'appliquer à Cust_Id 19
Emp_Id,Cust_id,Start_Date,End_Date,Activity_Date,Task
4,11,2017-10-01 00:00:00.000,2018-07-31 00:00:00.000,NULL,NULL
4,15,2017-10-01 00:00:00.000,2018-04-08 00:00:00.000,2018-04-02 00:00:00.000,Review
4,17,2018-06-01 00:00:00.000,NULL,2018-06-29 00:00:00.000,Client Engagement
4,17,2018-06-01 00:00:00.000,NULL,2018-06-25 00:00:00.000,Review
4,19,2018-05-18 00:00:00.000,NULL,2018-05-25 00:00:00.000,Client Engagement
4,19,2018-05-18 00:00:00.000,NULL,2018-06-28 00:00:00.000,Review