2011-07-12 2 views
3

J'ai une procédure stockée qui peut avoir 1 à 4 variables passées et il doit retourner les lignes où la plupart des colonnes correspondent ou s'il n'y a pas d'enregistrements correspondants, il retourne ceux par défaut (qui sont nuls). La séquence doit être distincte.SQL Server sélectionner où la plupart des colonnes correspondent

Exemple de tableau avec des données:

Client_Id Project_ID Phase Task Employee Sequence 
--------- ---------- ----- ---- -------- -------- 
NULL  NULL  NULL NULL Chris 1 
NULL  NULL  NULL NULL Bob  100 
500  NULL  NULL NULL Joe  1 
500  2   NULL NULL Max  1 

Ainsi, les résultats pour le client 100, tout projet, phase ou tâche serait tout simplement les enregistrements NULL par défaut de Chris et Bob. Pour le client 500, les résultats seraient Joe et Bob. Pour le client 500, projet 2, le résultat serait Max et Bob. En ce moment je fais cette requête en vérifiant d'abord la tâche puis en la joignant avec une requête par phase et en vérifiant qu'aucune ligne ne se chevauche et fait la même chose pour le projet que pour le client. Cela semble incroyablement inefficace et il doit y avoir un moyen plus intelligent à ce sujet. Des pensées?

EDIT - Quelques exemples de requête, je vérifie d'abord pour le cas où tout correspond

insert into #TempTracking 
    select p.employee, p.sequence 
     from  invoices i, projects p 
     where i.client_id = p.client_id 
     and  i.project_no = p.project_no 
     and  i.phase = p.phase 
     and  i.task = p.task 

Ensuite, je fais les requêtes de moins en moins spécifiques et vérifiez que la séquence n'existe pas déjà.

insert into #TempTracking 
select p.employee, p.sequence 
    from  invoices i, projects p 
    where (i.client_id = p.client_id or i.client_id is null) 
    and  (i.project_no = p.project_no or i.project_no is null) 
    and  (i.phase = p.phase or i.phase is null) 
    and  (i.task = p.task or i.task is null) 
    and  NOT EXISTS (SELECT * FROM #TempTracking t WHERE t.sequence = p.sequence) 
+0

Quelle version de SQL Server? – Matthew

+0

'Pour le Client 500, Projet 2, le résultat serait Max et Bob. Cela ne devrait-il pas renvoyer Max à celui-ci? –

+0

Abe soulève un bon point, comment Bob est-il un résultat valide pour Client 500, Projet 2 mais Chris ne l'est pas? – Seph

Répondre

3

« La plupart des colonnes correspondent » est très vague, mais je suppose que vous voulez dire que s'ils recherchent nulle, ou si la valeur de la table est nulle alors assumer ce disque pourrait être inclus.

Si vous voulez la ligne correspondant le plus ou toutes les lignes qui ne correspondent pas, alors vous aurez besoin de faire quelque chose comme ça (il commence à faire très long)

DECLARE @Client_Id VARCHAR(MAX) = '500' 
DECLARE @Project_ID VARCHAR(MAX) = '2' 
DECLARE @Phase VARCHAR(MAX) = NULL 
DECLARE @Task VARCHAR(MAX) = NULL 

SELECT Employee, Sequence 
FROM 
    (SELECT Employee, Sequence, 
    (
    CASE WHEN (Client_Id = @Client_Id OR Client_Id IS NULL OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Project_ID = @Project_ID OR Project_ID IS NULL OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Phase = @Phase OR Phase IS NULL OR @Phase IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Task = @Task OR Task IS NULL OR @Task IS NULL) THEN 1 ELSE 0 END 
) AS MatchCount 
WHERE MatchCount = 
    (
    SELECT MAX(
     CASE WHEN (Client_Id = @Client_Id OR Client_Id IS NULL OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
     CASE WHEN (Project_ID = @Project_ID OR Project_ID IS NULL OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
     CASE WHEN (Phase = @Phase OR Phase IS NULL OR @Phase IS NULL) THEN 1 ELSE 0 END + 
     CASE WHEN (Task = @Task OR Task IS NULL OR @Task IS NULL) THEN 1 ELSE 0 END 
    ) 
    FROM myTable 
) 
    -- Now prevent for duplicate sequence numbers 
    AND NOT EXISTS (
    SELECT Employee, Sequence 
    FROM 
     (SELECT Employee, Sequence, 
     (
     CASE WHEN (Client_Id = @Client_Id OR Client_Id IS NULL OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
     CASE WHEN (Project_ID = @Project_ID OR Project_ID IS NULL OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
     CASE WHEN (Phase = @Phase OR Phase IS NULL OR @Phase IS NULL) THEN 1 ELSE 0 END + 
     CASE WHEN (Task = @Task OR Task IS NULL OR @Task IS NULL) THEN 1 ELSE 0 END 
    ) AS MatchCount 
     FROM myTable) mt2 
    WHERE mt2.MatchCount = 
     (
     SELECT MAX(
      CASE WHEN (Client_Id = @Client_Id OR Client_Id IS NULL OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
      CASE WHEN (Project_ID = @Project_ID OR Project_ID IS NULL OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
      CASE WHEN (Phase = @Phase OR Phase IS NULL OR @Phase IS NULL) THEN 1 ELSE 0 END + 
      CASE WHEN (Task = @Task OR Task IS NULL OR @Task IS NULL) THEN 1 ELSE 0 END 
     ) 
     FROM myTable 
    ) 
     AND mt2.Sequence = myTable.Sequence AND mt2.MatchCount > myTable.MatchCount 
) 

Note: Ceci renvoie tous les enregistrements la table lorsque le nombre de champs correspondants est zéro.

Je suis sûr qu'ils peuvent être nettoyés pour ne pas être trop verbeux en insérant toutes les lignes correspondantes dans une table temporaire et en incluant le nombre de colonnes qui correspondent (MatchCount), en réduisant considérablement la requête .

Maintenant, puisque vous voulez des séquences uniques et les plus rangée correspondant/lignes à renvoyer le résultat que vous êtes à la recherche est plus comme ceci:

DECLARE @Client_Id VARCHAR(MAX) = '500' 
DECLARE @Project_ID VARCHAR(MAX) = '3' 
DECLARE @Phase VARCHAR(MAX) = NULL 
DECLARE @Task VARCHAR(MAX) = NULL 

INSERT INTO #myTempTable SELECT Employee, Sequence, 
    (
    CASE WHEN (Client_Id = @Client_Id OR Client_Id IS NULL OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Project_ID = @Project_ID OR Project_ID IS NULL OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Phase = @Phase OR Phase IS NULL OR @Phase IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Task = @Task OR Task IS NULL OR @Task IS NULL) THEN 1 ELSE 0 END 
) AS MatchCount, 
    (
    CASE WHEN (Client_Id IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Project_ID IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Phase IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Task IS NULL) THEN 1 ELSE 0 END 
) AS NullCount 
-- ,(
-- CASE WHEN (Client_Id = @Client_Id OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
-- CASE WHEN (Project_ID = @Project_ID OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
-- CASE WHEN (Phase = @Phase OR @Phase IS NULL) THEN 1 ELSE 0 END + 
-- CASE WHEN (Task = @Task OR @Task IS NULL) THEN 1 ELSE 0 END 
-- ) AS MatchCountWithoutNulls 

SELECT Employee, Sequence 
FROM #myTempTable mtt 
WHERE MatchCount = (
    SELECT MAX(MatchCount) 
    FROM #myTempTable mtt2 
    WHERE mtt2.Sequence = mtt.Sequence 
) 
    AND NullCount = (
    SELECT MIN(NullCount) 
    FROM #myTempTable mtt2 
    WHERE mtt2.Sequence = mtt.Sequence 
) 

Ou quelque chose de très proche de celui, je ne » J'ai une table de test composée d'atm donc je ne peux pas le faire tourner et voir.

+0

C'est vague et je m'excuse. Je sais à quoi la solution devrait ressembler mais j'ai du mal à articuler le problème spécifique. – ChrisOPeterson

+0

C'est bon, je pense que je comprends ce que vous essayez d'articuler ... voir ma dernière édition et cela devrait être ce que vous cherchez – Seph

Questions connexes