web-dev-qa-db-fra.com

Procédure stockée SQL IF EXISTS UPDATE ELSE INSERT

D'ACCORD. J'ai eu beaucoup d'aide ici plus tôt avec un serveur SQL à un simple ... mais pas pour moi :( ... solution d'horloge pour le petit bureau dans lequel je travaille, je suis donc de retour pour plus !

Mon tableau sur lequel je travaille actuellement se compose de 6 colonnes:

  1. date du clockDate non PK nulle
  2. nom d'utilisateur varchar (50) non nul PK
  3. horloge en heure (0)
  4. temps de pause (0)
  5. temps de pause (0)
  6. heure de sortie (0)

Je pensais avoir compris ma déclaration IF NOT EXISTS INSERT ELSE UPDATE à partir de ma dernière question, mais maintenant, j'essaie de l'utiliser dans une procédure stockée, plutôt que dans une fenêtre de requête simple, sans succès.

Fondamentalement, un utilisateur synchronisant est une évidence. Cependant, si l'utilisateur ne se connecte pas, mais qu'il le fait pour le déjeuner, la déclaration doit créer la ligne au lieu de mettre à jour une ligne existante. Ok alors voici ma procédure stockée:

ALTER PROCEDURE dbo.BreakOut
(
    @userName varchar(50)
)
AS

IF EXISTS (SELECT * FROM Clock WHERE clockDate = GETDATE() AND userName = @userName)
    BEGIN
        UPDATE Clock SET breakOut = GETDATE() 
            WHERE clockDate = GETDATE() AND userName = @userName
    END
ELSE
    BEGIN
        INSERT INTO Clock (clockDate, userName, breakOut) 
            VALUES (GETDATE(), @userName, GETDATE())
    END

Voici mon problème ... Si l'utilisateur DID passe le jour où j'obtiens une violation de clé primaire car la procédure stockée tente toujours d'exécuter la partie INSERT de l'instruction et n'exécute jamais la ligne UPDATE. Je l'ai essayé retourné avec un IF NOT EXISTS avec le même résultat. Quelle est l'astuce pour que IF-ELSE fonctionne dans une procédure stockée? Est-ce que cela peut être fait comme je le pense ou dois-je étudier la déclaration Merge? Mon plan consiste à exécuter les procédures stockées à partir d'un simple programme Visual Basic sur chaque poste de travail. Peut-être que je suis au-dessus de ma tête :( Dommage que mon patron soit trop bon marché pour acheter une solution horodateur!

MODIFIER:

Merci à tous pour votre aide!! Je tombe en amour avec ce site, les questions obtiennent des réponses SO FAST !!! Voici ma procédure stockée de travail:

ALTER PROCEDURE dbo.BreakOut
(
    @userName varchar(50)
)
AS

IF EXISTS (SELECT * FROM Clock WHERE DateDiff(dd, GetDate(),clockDate) = 0 AND userName = @userName)
    BEGIN
        UPDATE Clock SET breakOut = GETDATE() 
            WHERE DateDiff(dd, GetDate(),clockDate) = 0 AND userName = @userName
    END
ELSE
    BEGIN
        INSERT INTO Clock (clockDate, userName, breakOut) 
            VALUES (GETDATE(), @userName, GETDATE())
    END

Est-ce approprié ou pourrait-il être amélioré davantage? Encore merci à tous SO BEAUCOUP !!!

17
tmhalbert

C'est probablement le problème ici: WHERE clockDate = GETDATE ()

GetDate renvoie la date actuelle ET l'heure actuelle, qui ne correspondent pas à clockDate. Vous pouvez comparer les dates avec DateDiff à la place:

WHERE DateDiff(dd, GetDate(),clockDate) = 0
11
Jim

Votre problème semble être le suivant:

Imaginons que l'utilisateur soit enregistré à 09:00

Un enregistrement du type suivant pourrait exister:

 ClockDate userName clockIn breakOut breakIn clockOut 
 12/08/2012 joe 09:00 NULL NULL NULL 

Maintenant, votre déclaration IF fait ceci:

SELECT * FROM Clock WHERE clockDate = "20120812 17:24:13" AND userName = @userName

c'est-à-dire que cet enregistrement n'existera pas.

Au lieu de cela, essayez ceci:

IF EXISTS (SELECT * FROM Clock  WHERE clockDate = DATEADD(D, 0, DATEDIFF(D, 0, GETDATE())) AND userName = @userName)

Vous devez également vous assurer que vous stockez clockDate uniquement comme partie de date de GETDATE (). Sinon, vous devrez ajuster votre requête de la manière suivante:

IF EXISTS (SELECT * FROM Clock WHERE DATEADD(D, 0, DATEDIFF(D, 0, clockDate)) = DATEADD(D, 0, DATEDIFF(D, 0, GETDATE())) AND userName = @userName)
3
dash

Votre mise à jour ne fonctionnera jamais car GETDATE renvoie une date et une heure.

http://msdn.Microsoft.com/en-us/library/ms188383.aspx

1
Dave R.
CREATE PROCEDURE `SP_GENRE_SELECT`(
    IN _Id INTEGER,
      IN _Name VARCHAR(50),
      IN _account VARCHAR (50),
      IN _Password VARCHAR (50),
      IN _LastConnexionDate DATETIME,
      IN _CreatedDate DATETIME,
      IN _UpdatedDate DATETIME,
      IN _CreatedUserId INTEGER,
      IN _UpdatedUserId INTEGER,
      IN _Status TINYINT
    )
BEGIN
      SELECT *
      FROM user
      WHERE Id LIKE IF(_Id IS NULL,'%',CAST(_Id AS VARCHAR(50)))
      AND
      Name LIKE IF(_Name IS NULL,'%',CONCAT('%',_Name,'%'))
      AND
      Account LIKE IF(_Account IS NULL,'%',CONCAT('%',_Account,'%'))
      AND
      LastConnexionDate LIKE IF(_LastConnexionDate IS NULL,'%',CONCAT('%',CAST(LastConnexionDate AS VARCHAR(50),'%')))
      AND
      CreatedDate LIKE IF(_CreatedDate IS NULL,'%',CONCAT('%',CAST(_CreatedDate AS VARCHAR(50),'%')))
      AND
      UpdatedDate LIKE IF(_UpdatedDate IS NULL,'%',CONCAT('%',CAST(_UpdatedDate AS VARCHAR(50),'%')))
      AND
      CreatedUserID LIKE IF(_CreatedUserID IS NULL,'%',CONCAT('%',CAST(_CreatedUserID AS VARCHAR(50),'%')))
      AND
      UpdatedUserID LIKE IF(_UpdatedUserID IS NULL,'%',CONCAT('%',CAST(_UpdatedUserID AS VARCHAR(50),'%')))
      AND
      Status LIKE IF(_Status IS NULL,'%',CAST(_Status AS VARCHAR(50),'%'))

END
0
Steves Kamdem