159 votes

SQL Server insère s'il n'existe pas de meilleure pratique

J'ai un Competitions tableau des résultats de la qui détient membre de l'équipe de noms et de leur classement sur une seule main.

D'autre part j'ai besoin de maintenir un tableau de unique concurrents noms:

CREATE TABLE Competitors (cName nvarchar(64) primary key)

Maintenant, j'ai quelque 200 000 résultats dans la 1ère table et quand les concurrents de la table est vide , je peux le faire:

INSERT INTO Competitors SELECT DISTINCT Name FROM CompResults

Et la requête ne prend que 5 secondes pour insérer environ 11 000 noms.

Jusqu'à présent, ce n'est pas une critique de l'application afin que je puisse envisager de tronquer les Concurrents de la table une fois par mois, lorsque je reçois les nouveaux résultats de la compétition avec quelques 10 000 lignes.

Mais quelle est la meilleure pratique lorsque de nouveaux résultats sont ajoutés, avec de nouveaux concurrents existants? Je ne veux pas tronquer les concurrents de table

J'ai besoin pour effectuer l'instruction INSERT pour de nouveaux concurrents et de ne rien faire si elles existent.

231voto

gbn Points 197263

Sémantiquement, vous demandez "insérer des concurrents là où il n’existe pas déjà":

 INSERT Competitors (cName)
SELECT DISTINCT Name
FROM CompResults cr
WHERE
   NOT EXISTS (SELECT * FROM Competitors c
              WHERE cr.Name = c.cName)
 

58voto

pcofre Points 2235

Une autre option est de laisser rejoindre votre table de résultats avec votre table de concurrents existants et de rechercher les nouveaux concurrents en filtrant les enregistrements distincts qui ne correspondent pas à la jointure:

 INSERT Competitors (cName)
SELECT  DISTINCT cr.Name
FROM    CompResults cr left join
        Competitors c on cr.Name = c.cName
where   c.cName is null
 

Nouvelle syntaxe, MERGE offre également un moyen compact, élégant et efficace de le faire:

 MERGE INTO Competitors AS Target
USING (SELECT DISTINCT Name FROM CompResults) AS Source ON Target.Name = Source.Name
WHEN NOT MATCHED THEN
    INSERT (Name) VALUES (Source.Name);
 

32voto

Transact Charlie Points 1070

Ne sais pas pourquoi personne d'autre n'a pas dit cela encore;

NORMALISER.

Vous avez une table que les modèles de compétitions? Les compétitions sont constitués de Concurrents? Vous avez besoin d'une liste distincte de Concurrents dans une ou plusieurs Compétitions......

Vous devriez avoir les tableaux suivants.....

CREATE TABLE Competitor (
    [CompetitorID] INT IDENTITY(1,1) PRIMARY KEY
    , [CompetitorName] NVARCHAR(255)
    )

CREATE TABLE Competition (
    [CompetitionID] INT IDENTITY(1,1) PRIMARY KEY
    , [CompetitionName] NVARCHAR(255)
    )

CREATE TABLE CompetitionCompetitors (
    [CompetitionID] INT
    , [CompetitorID] INT
    , [Score] INT

    , PRIMARY KEY (
        [CompetitionID]
        , [CompetitorID]
        )
    )

Avec des Contraintes sur CompetitionCompetitors.CompetitionID et CompetitorID pointant vers d'autres tables.

Avec ce type de structure de table, vos clés sont tous de simples ENTIERS -- il ne semble pas être une bonne CLÉ qui permettrait d'adapter le modèle donc je pense qu'une CLÉ de SUBSTITUTION est une bonne place ici.

Donc, si vous avez eu ce alors pour obtenir la liste distincte des concurrents dans un concours particulier, vous pouvez émettre une requête comme ceci:

DECLARE @CompetitionName VARCHAR(50) SET @CompetitionName = 'London Marathon'

    SELECT
        p.[CompetitorName] AS [CompetitorName]
    FROM
        Competitor AS p
    WHERE
        EXISTS (
            SELECT 1
            FROM
                CompetitionCompetitor AS cc
                JOIN Competition AS c ON c.[ID] = cc.[CompetitionID]
            WHERE
                cc.[CompetitorID] = p.[CompetitorID]
                AND cc.[CompetitionName] = @CompetitionNAme
        )

Et si vous vouliez le score pour chaque concours, un concurrent est en:

SELECT
    p.[CompetitorName]
    , c.[CompetitionName]
    , cc.[Score]
FROM
    Competitor AS p
    JOIN CompetitionCompetitor AS cc ON cc.[CompetitorID] = p.[CompetitorID]
    JOIN Competition AS c ON c.[ID] = cc.[CompetitionID]

Et lorsque vous avez un nouveau la concurrence avec de nouveaux concurrents, alors il vous suffit de cocher celles qui existent déjà dans les Concurrents de la table. S'ils existent déjà, alors vous ne l'insérez pas en Concurrent pour les Concurrents et faire des insert pour les nouveaux.

Ensuite, vous insérez la nouvelle Concurrence de la Concurrence et, enfin, vous venez de faire tous les liens dans CompetitionCompetitors.

12voto

richard Points 3579

Vous devrez joindre les tables et obtenir une liste des concurrents qui n'existent pas déjà, en Competitors.

Cela permettra d'insérer des enregistrements uniques.

INSERT Competitors (cName) 
SELECT DISTINCT Name
FROM CompResults cr LEFT JOIN Competitors c ON cr.Name = c.cName
WHERE c.Name IS NULL

Il peut arriver un moment où cette notice doit être fait rapidement, sans être en mesure d'attendre pour la sélection des noms uniques. Dans ce cas, vous pouvez insérer les noms uniques dans une table temporaire, et ensuite utiliser cette table temporaire à insérer dans votre vraie table. Cela fonctionne bien parce que tout le traitement se passe au moment de l'insertion dans une table temporaire, de sorte qu'il n'affecte pas votre vraie table. Puis, quand vous aurez tout le traitement terminé, vous faire une rapide insertion dans la table réelle. Je pourrait même terminer la dernière partie, où vous insérez dans la vraie table, à l'intérieur d'une transaction.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X