1
votes

Envoi de SQL un booléen et mise à jour d'une table comme 1 ou -1 et comment «mettre à jour» une ligne vide pour les valeurs initiales

J'ai un tableau Songs avec une colonne likes qui contient le nombre de likes envoyés par les utilisateurs. Chaque utilisateur envoie un booléen (1 ou 0) via une application C # qui s'ajoute à la colonne likes .

À propos de ma procédure:

  1. Je veux savoir s'il existe un moyen plus efficace et plus court d'écrire la partie 1 de la fonction?
    J'ai dû insérer manuellement «0» au lieu de NULL pour la première fois pour que la fonction fonctionne. Cela ne fonctionnait pas car la valeur initiale de la colonne Likes est NULL . Existe-t-il un moyen d'affecter la ligne pour la première fois lorsqu'elle contient NULL?

  2. Pour la partie 2 de la fonction avec la table [Users_Likes_Songs] , je souhaite mettre à jour si l'utilisateur envoie un like (true = 1) ou l'a supprimé (false = 0).

    Comment puis-je mettre à jour ce tableau pour la première fois lorsque les utilisateurs «j'aime» doivent avoir la valeur «1», lorsque ses lignes sont complètement vides?

Je vous remercie beaucoup si vous pouvez m'aider.

La procédure:

CREATE PROCEDURE Songs_Likes
    @User_ID INT,
    @SongID INT,
    @Song_like BIT
AS
BEGIN
    --- part 1 of the function
    IF (@Song_like = 1)
    BEGIN
        UPDATE [Songs] 
        SET [Likes] = [Likes] + @Song_like
        WHERE [Song_ID] = @SongID
    END

    IF (@Song_like = 0)
    BEGIN
        UPDATE [Songs] 
        SET [Likes] = [Likes] - 1
        WHERE [Song_ID] = @SongID
    END

    --- part 2 of the function with the second table
    UPDATE [Users_Likes_Songs]
    SET [LikeSong] = @Song_like 
    WHERE ([UserID] = @User_ID) AND ([SongID] = @SongID)
END


4 commentaires

Pourquoi avez-vous besoin de stocker le nombre de J'aime dans le tableau Chansons ? Vous pouvez toujours le calculer simplement à partir de la table Users_Likes_Songs .


En ce qui concerne votre commentaire B, pourquoi ne pas définir la valeur DEFAULT de Likes sur 0, au lieu de NULL ? Idéalement, cependant, je calculerais en fait le nombre de likes comme une valeur calculée. Le stockage dans une table peut facilement se terminer par une valeur incorrecte; surtout avec des choses comme les conditions de course.


@HoneyBadger, c'est une bonne idée, mais pour le projet de démonstration, je dois insérer de «faux» likes sans utilisateur réel.


@ sup.DR Je dirais que vous ne pouvez pas avoir de likes sans utilisateurs, même pour une démo. Si vous avez besoin de faire une démonstration, créez de faux utilisateurs et faites-leur aimer et ne pas aimer les chansons.


3 Réponses :


1
votes

Vous pouvez essayer cette requête dans votre procédure

UPDATE [songs] 
SET    [likes] = Isnull ([likes], 0) + ( CASE WHEN @Song_like THEN 1 ELSE -1 END) 
WHERE  [song_id] = @SongID 


1 commentaires

Il y a un erratum dans votre code: "ESLE" -> "ELSE". De plus, COALESCE est plus recommandé que ISNULL, tout comme la norme ANSII



1
votes

Pour 1) c'est un peu plus clair, plus court et un peu plus efficace.

IF NOT EXISTS (SELECT 1 
    FROM [Users_Likes_Songs] 
    WHERE [UserID] = @User_ID 
    AND [SongID] = @SongID) 

  INSERT INTO [Users_Likes_Songs] (User_ID, SongID, [LikeSong]) 
    VALUES (@User_ID, @SongID, @Song_like)
ELSE
  UPDATE [Users_Likes_Songs]
    SET [LikeSong] = @Song_like WHERE ([UserID] = @User_ID) AND ([SongID] = @SongID)

Pour la deuxième partie, vous pouvez faire quelque chose comme ceci:

UPDATE [Songs] 
    SET [Likes] = COALESCE([Likes], 0) + CASE WHEN @Song_like = 1 THEN 1
                                WHEN @Song_like = 0 THEN -1
                                ELSE 0 END
    WHERE [Song_ID] = @SongID;


3 commentaires

J'ai mis à jour ma deuxième partie de la question, pouvez-vous la regarder? Je veux savoir si vous avez bien compris votre réponse.


Merci, il suffit de modifier votre réponse avec moins ')' '(' as - (SELECT 1 FROM [Users_Likes_Songs] WHERE [UserID] = @User_ID AND [SongID] = @SongID)


Ah, oui ... il y avait quelques déroutants () et un manquant). Corrigé dans ma réponse pour référence future. Merci d'avoir partagé !!!



3
votes

Je pense que la meilleure méthode serait de changer votre design pour calculer les likes et avoir une table qui stocke les likes pour chaque utilisateur. En termes simples, quelque chose comme:

USE Sandbox;
GO

CREATE SCHEMA music;
GO

CREATE TABLE music.song (SongID int IDENTITY(1,1),
                         Artist nvarchar(50) NOT NULL,
                         Title nvarchar(50) NOT NULL,
                         ReleaseDate date);

CREATE TABLE music.[User] (UserID int IDENTITY(1,1),
                           [Login] nvarchar(128));

CREATE TABLE music.SongLike (LikeID bigint IDENTITY(1,1),
                             SongID int,
                             UserID int,
                             Liked bit);

CREATE UNIQUE NONCLUSTERED INDEX UserLike ON music.SongLike(SongID, UserID); --Stops multiple likes
GO

--To add a LIKE you can then have a SP like:

CREATE PROC music.AddLike @SongID int, @UserID int, @Liked bit AS
BEGIN

    IF EXISTS (SELECT 1 FROM music.SongLike WHERE UserID = @UserID AND SongID = @SongID) BEGIN
        UPDATE music.SongLike
        SET Liked = @Liked
        WHERE UserID = @UserID
          AND SongID = @SongID
    END ELSE BEGIN
        INSERT INTO music.SongLike (SongID,
                                    UserID,
                                    Liked)
        VALUES (@SongID, @UserID, @Liked);
    END
END
GO

--And, if you want the number of likes:

CREATE VIEW music.SongLikes AS

    SELECT S.Artist,
           S.Title,
           S.ReleaseDate,
           COUNT(CASE SL.Liked WHEN 1 THEN 1 END) AS Likes
    FROM music.Song S
         JOIN music.SongLike SL ON S.SongID = SL.SongID
    GROUP BY S.Artist,
             S.Title,
             S.ReleaseDate;
GO


2 commentaires

J'ajouterais une contrainte (FK) pour la référence de table SongsLikes le songID.


Il y a plusieurs index et contraintes dont il a besoin, @Sami. Ce n'était que l'essentiel. Je ne fais pas tout le travail pour l'OP :)