1
votes

SQL: parcourir la colonne avec les valeurs d'une autre colonne

J'ai une table:

SELECT DISTINCT
    [Day],
    CASE 
       WHEN Client_ID = '1804' 
          THEN 1 
          ELSE 0 
    END AS Occur
FROM 
    table

Maintenant, ce que je veux faire, c'est prendre des valeurs distinctes de chaque colonne et (probablement avec une instruction while) vérifier toutes les valeurs de colonne de date et en avoir une plus de colonne avec une déclaration vrai ou faux si cet identifiant était à cette date. Le résultat devrait donc ressembler à ceci:

Day       Client_ID Occur
-------------------------
2018.10.22  1804    TRUE
2018.10.23  1804    TRUE
2018.10.24  1804    TRUE
2018.10.25  1804    TRUE
2018.10.26  1804    TRUE
2018.10.29  1804    TRUE
2018.10.30  1804    TRUE
2018.10.31  1804    TRUE
2018.11.02  1804    TRUE
2018.11.23  1804    FALSE
2018.10.22  1317    Does not exist
2018.10.23  1317    Does not exist
2018.10.24  1317    TRUE
2018.10.25  1317    FALSE
2018.10.26  1317    FALSE
2018.10.29  1317    FALSE
2018.10.30  1317    FALSE
2018.10.31  1317    FALSE
2018.11.02  1317    FALSE
2018.11.23  1317    TRUE

Pour 1 ID, je peux obtenir le résultat avec cette requête:

Client_ID   Day
------------------
1804    2018-10-22
1804    2018-10-23
1804    2018-10-24
1804    2018-10-25
1804    2018-10-26
1804    2018-10-29
1804    2018-10-30
1804    2018-10-31
1804    2018-11-02
1317    2018-10-24
1317    2018-11-23

Mais j'en ai besoin pour parcourir toutes les valeurs distinctes de la colonne Day . Et si la date la plus basse de certains ID est supérieure à la date la plus basse dans la colonne Jour, cela doit avoir un résultat différent. Disons que "n'existe pas" (mais cela peut être n'importe quoi). C'est là que j'ai besoin d'aide.


2 commentaires

Quelle version de SQL Server utilisez-vous?


Comme vous le verrez dans la discussion dans les réponses (ci-dessous), vous ne voulez pas utiliser une structure WHILE si vous pouvez l'éviter. Les systèmes SGBDR comme SQL Server sont BEAUCOUP plus heureux si vous leur confiez des tâches basées sur des ensembles.


3 Réponses :


1
votes

Ceci peut être réalisé avec un CROSS JOIN qui génère toutes les combinaisons possibles de date et d'identifiant, combiné avec un LEFT JOIN sur la table d'origine, comme:

SELECT
    d.date,
    i.id,
    CASE WHEN t.id IS NULL THEN 'FALSE'  ELSE 'TRUE' END
FROM
    (SELECT DISTINCT day FROM table) d
    CROSS JOIN (SELECT DISTINCT id FROM table) i 
    LEFT JOIN table t
        ON t.date = d.date 
        AND t.id = i.id


2 commentaires

@Larnu: oui, merci de l'avoir signalé! J'étais en train de modifier en même temps que vous, je viens de mettre à jour ma réponse pour corriger cette faute de frappe


Cela a l'air vraiment sympa. Je vais l'essayer. J'ai juste oublié une chose en écrivant la demande originale et je n'ai pas remarqué qu'il y avait des réponses aussi rapidement lors de l'édition de mon message. Désolé pour ça.



0
votes

Il existe un moyen de créer des boucles while sur SQL Server, vous pouvez essayer ceci:

DECLARE @intFlag INT
SET @intFlag = 1
WHILE (@intFlag <= #Number of loops here)
BEGIN
    #Your statements here
SET @intFlag = @intFlag + 1
END


2 commentaires

Ce n'est pas une mauvaise réponse, mais ce serait certainement l'une des pires performances. Juste une note aux lecteurs.


Convenu. Bien que l'OP ait supposé qu'il aurait probablement besoin d'une boucle WHILE , en réalité en utiliser une serait un mauvais choix. SQL Server et d'autres SGBDR excellent dans les opérations basées sur des ensembles, pas dans les tâches itératives; et une boucle WHILE est très certainement la dernière. Dans SQL World, de telles opérations sont appelées opérations RBAR (Row By Agonizing Row) et sont généralement mieux évitées.



0
votes

Vous pouvez générer les lignes avec une jointure croisée et utiliser jointure gauche pour importer les valeurs. Vous avez besoin d'une contrainte supplémentaire sur la date la plus proche. Je pense que je ferais:

select d.date, c.client_id,
       (case when d.date < c.min_date then 'Does not exist'
             when t.id is not null then 'TRUE'
             else 'FALSE'
        end) as occur
from (select distinct day from t) d cross join
     (select client_id, min(date) as min_date
      from <table> t
      group by client_id
     ) c left join
     <table> t
     on t.day = d.day and t.client_id = c.client_id;


1 commentaires

Merci Gordon Linoff, c'est exactement ce dont j'avais besoin. Il y a juste une petite erreur, sur la seconde à partir de la ligne du bas avant "t" ou après la jointure gauche, il doit y avoir "table". Juste pour que les autres le sachent :)