1
votes

Comment puis-je mettre une colonne dans SQL qui affiche un 1 si la valeur d'une autre colonne est unique et 0 si elle est dupliquée?

Je voudrais créer une colonne qui met la valeur 1 si c'est la première occurrence d'une valeur dans une ligne et 0 si ce n'est pas la première occurrence.

 entrez la description de l'image ici


9 commentaires

Voulez-vous vérifier les valeurs dans différentes colonnes ou différentes lignes?. Dire une chose sur l'explication et une autre sur l'échantillon.


J'ai ajouté une image juste pour montrer ce que j'essaie d'expliquer!


Désolé, je ne comprends pas votre logique. Vous avez à la fois des valeurs d'indicateur 1 et 0 pour la valeur a et 1 valeur d'indicateur pour la valeur b (qui n'est pas répétée sur les autres lignes). Pouvez-vous l'expliquer?.


Votre image n'est pas claire. La valeur «a» n'est pas unique. Pourquoi est-il affiché à la fois 1 et 0?


@dimerazor l'image montre quelque chose de complètement différent de ce que vous avez demandé. Que voulez-vous réellement ? Publiez un exemple sous forme de texte , pas sous forme d'image, montrez ce que vous voulez s'il y a plus de deux éléments. Pourquoi l'une des lignes devrait-elle avoir 1 au lieu de toutes par exemple? Tous peuvent être effectués en vérifiant un count (*) . L'un d'eux peut être fait avec par exemple LEAD ou LAG


Stockez-vous cette valeur calculée dans le tableau? Ou demandez-vous comment écrire une instruction SQL qui inclut la colonne calculée?


Je voudrais avoir cette colonne 1/0 dans le tableau.


@dimerazor vous ne pouvez pas en avoir une comme valeur par défaut. Ces chiffres sont le résultat de requêtes. Cependant, vous n'avez toujours pas expliqué ce que vous vouliez. Pourquoi une ligne devrait-elle avoir 1 et une autre, avec les mêmes valeurs sinon, 0 ? Quelle est la logique? Il n'y a pas d'ordre dans une table à moins qu'il ne soit spécifié explicitement avec un ORDER BY


Si vous souhaitez stocker le 1/0 dans la table, alors (à moins que je ne comprenne mal la question), vous devrez recalculer la valeur pour chaque enregistrement, chaque fois qu'un enregistrement dans la table est ajouté / mis à jour / supprimé. Et recalculez également la valeur de chaque enregistrement chaque fois que vous souhaitez modifier la logique du calcul. Pour cette raison, il est recommandé d'éviter de stocker des valeurs calculées dans une base de données. Il y a des scénarios où cela a du sens, mais cela ne semble pas être l'un d'entre eux. Au lieu de cela, je regarderais exposer la valeur calculée via une vue ou une procédure stockée.


3 Réponses :


4
votes

Vous pouvez utiliser une fonction de fenêtre et CTE pour attribuer un numéro de ligne à chaque partition de "données", puis définir l'indicateur sur 1 lorsque le numéro de ligne est 1 sinon 0.

Démo Rextester

Cela suppose:

  • le champ à évaluer s'appelle "Données"
  • la 1ère entrée n'est pas considérée comme un doublon là où toutes les autres le sont. Le premier est délicat ici car nous n'avons pas défini d'ordre, donc la première entrée rencontrée par le système sera traitée comme non dupliquée; sauf si nous définissons davantage l'ordre par dans la fonction de fenêtre; cette non-duplication peut changer d'une exécution à l'autre.

.

    Data    Flg
1   A   1
2   A   0
3   B   1
4   B   0
5   B   0
6   C   1
7   C   0

Renvoie quelque chose comme ceci étant donné mon exemple de données utilisé:

With CTE AS (SELECT Data, Row_Number() over (partition by Data order by Data) RN 
             FROM TableName T)
SELECT Data, case when RN = 1 then 1 else 0 end as Flg
FROM CTE


4 commentaires

Je ne sais pas pourquoi cela obtiendrait des votes positifs. La clause order by n'est pas stable et la réponse ne résout pas le problème fondamental de la question - à savoir que l'exemple de table n'a pas de colonne qui spécifie l'ordre.


Cela suppose que la commande est pertinente. c'est peut-être juste une table avec des valeurs répétitives et ils ne se soucient pas de celle qu'ils gardent. J'ai essayé de répondre à la question telle qu'elle était posée. Cela n'a peut-être pas beaucoup de sens. et j'ai déclaré que la ligne sélectionnée pouvait changer d'une course à l'autre


. La question est: "si c'est la première occurrence d'une valeur dans une ligne et 0 si ce n'est pas la première occurrence" (je souligne). Je pense qu'il est vraiment clair que la commande est importante. Comme je le dis dans mon commentaire, les votes positifs me déroutent. Je comprends votre réponse, mais pas la raison pour laquelle elle serait majorée.


Je comprends ton point de vue; seul l'auteur sait ce qu'ils recherchent à ce stade.



0
votes

Tout d'abord, il n'est pas possible de définir et de mettre à jour automatiquement cette valeur dans le tableau. Ils devraient être recalculés après chaque modification de la table et les colonnes calculées ne peuvent faire référence à d'autres lignes ou exécuter des requêtes complètes.

Vous pouvez utiliser une fonction de fenêtre comme LAG pour vérifier s'il existe une valeur précédente dans un ensemble selon l'ordre de recherche que vous fournissez existe ou non, par exemple:

declare @t table (data varchar(10),value bit)
insert into @t(data)
values ('A'),
    ('B'),
    ('A'),
    ('B'),
    ('B'),
    ('C'),
    ('C');


with x as ( SELECT 
    Data,value, 
    iif( lag(1) over (partition by Data order by Data) is null,1,0) as Val
FROM @t)
update x
set value=val
from @t;

select * 
from @t
order by data

Cela renverra:

Data    Value
A       1
A       0
B       1
B       0
B       0
C       1
C       0

lag (1) over (partitionnement par ordre des données par données) partitionne les lignes par les valeurs de la colonne de données et les trie par la même valeur, essentiellement produire un ordre aléatoire. Il renvoie ensuite la valeur "précédente" de cette partition. Pour la première ligne, il n'y en a pas et LAG renvoie null .

iif (... is null, 1,0) as Value vérifie le résultat et renvoie 1 s'il est nul, 0 sinon.

Si vous souhaitez stocker les modifications de la table, vous pouvez utiliser un CTE modifiable:

declare @t table (data varchar(10))
insert into @t
values ('A'),
    ('B'),
    ('A'),
    ('B'),
    ('B'),
    ('C'),
    ('C')


SELECT 
    Data, 
    iif( lag(1) over (partition by Data order by Data) is null,1,0) as Value
FROM @t

Vous pouvez utiliser un déclencheur sur INSERT, UPDATE, DELETE pour exécuter cette requête à chaque modification et mettre à jour le tableau. Il serait cependant préférable de faire toutes les modifications et d'exécuter UPDATE uniquement à la fin


0 commentaires

0
votes

Les tables SQL représentent des ensembles non ordonnés . Votre table ne contient pas suffisamment d'informations pour répondre à cette question, une fois la table créée.

Si vous avez une telle table, vous pouvez utiliser une requête comme celle-ci pour attribuer la valeur:

select value,
       (case when row_number() over (partition by value order by ?) = 1
             then 1 else 0
        end) as flag
from t;

Le ? est un espace réservé pour une colonne telle que createdAt ou id , qui spécifie l'ordre des valeurs dans la table.

Si vous n'avez pas de colonne qui spécifie l'ordre, vous pouvez le faire avec un déclencheur qui vérifie si la valeur existe déjà. Cependant, plutôt que d'écrire un déclencheur, je suggérerais de créer la table avec une colonne identity () ou createdAt (ou les deux) pour capturer l'ordre d'insertion.


0 commentaires