Insertar SQL Server si no existe la mejor práctica [cerrado]

Resuelto Didier Levy asked hace 13 años • 8 respuestas

Tengo una Competitionstabla de resultados que contiene los nombres de los miembros del equipo y su clasificación en una mano.

Por otro lado necesito mantener una tabla de nombres únicos de competidores :

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

Ahora tengo unos 200.000 resultados en la primera tabla y cuando la tabla de competidores está vacía puedo realizar esto:

INSERT INTO Competitors SELECT DISTINCT Name FROM CompResults

Y la consulta sólo tarda unos 5 segundos en insertar unos 11.000 nombres.

Hasta ahora, esta no es una aplicación crítica, por lo que puedo considerar truncar la tabla de Competidores una vez al mes, cuando reciba los nuevos resultados de la competencia con unas 10.000 filas.

Pero, ¿cuál es la mejor práctica cuando se agregan nuevos resultados, con competidores nuevos Y existentes? No quiero truncar la tabla de competidores existentes

Necesito realizar una declaración INSERT solo para nuevos competidores y no hacer nada si existen.

Didier Levy avatar Mar 13 '11 15:03 Didier Levy
Aceptado

Semánticamente estás preguntando "insertar competidores donde aún no existen":

INSERT Competitors (cName)
SELECT DISTINCT Name
FROM CompResults cr
WHERE
   NOT EXISTS (SELECT * FROM Competitors c
              WHERE cr.Name = c.cName)
gbn avatar Mar 13 '2011 09:03 gbn

Otra opción es unir a la izquierda su tabla de Resultados con la tabla de competidores existentes y encontrar nuevos competidores filtrando los distintos registros que no coinciden en la combinación:

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

La nueva sintaxis MERGE también ofrece una forma compacta, elegante y eficiente de hacerlo:

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);
pcofre avatar Mar 13 '2011 12:03 pcofre

No sé por qué nadie más ha dicho esto todavía;

NORMALIZAR.

¿Tienes una mesa que modela competiciones? ¿Las competiciones están compuestas por Competidores? Necesita una lista distinta de Competidores en una o más Competiciones...

Deberías tener las siguientes tablas.....

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]
        )
    )

Con restricciones en CompetitionCompetitors.CompetitionID y CompetitorID apuntando a las otras tablas.

Con este tipo de estructura de tabla (todas sus claves son INTS simples), no parece haber una buena CLAVE NATURAL que se ajuste al modelo, así que creo que una CLAVE SURROGADA es una buena opción aquí.

Entonces, si tuviera esto, para obtener la lista distinta de competidores en una competencia en particular, puede realizar una consulta como esta:

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
        )

Y si quisieras conocer la puntuación de cada competición en la que participa un competidor:

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]

Y cuando tienes una nueva competencia con nuevos competidores, simplemente verifica cuáles ya existen en la tabla de Competidores. Si ya existen, no los inserte en Competidor para esos competidores y sí los inserte para los nuevos.

Luego insertas la nueva Competición en Competición y finalmente simplemente haces todos los enlaces en CompeticiónCompetitors.

Transact Charlie avatar Mar 13 '2011 10:03 Transact Charlie