Je m'excuse, mais c'est en quelque sorte une question en deux parties.
Je connais très bien SQL et je suis en train de développer une application de chronométrage pour le petit bureau dans lequel je travaille. Je m'amuse actuellement avec le backend SQL et pose une question sur les instructions composées.
Là où je suis bloqué, c'est que si un utilisateur essaie de faire une pause, mais jamais au début du quart de travail, SQL doit créer une nouvelle ligne plutôt que de mettre à jour un existant.
Voici ce que j'ai essayé:
IF NOT EXISTS(SELECT * FROM Clock WHERE clockDate = '08/10/2012') AND userName = 'test')
BEGIN
INSERT INTO Clock(clockDate, userName, breakOut)
VALUES({ fn NOW() }, 'test', { fn NOW() })
END
ELSE
BEGIN
UPDATE Clock
SET breakOut = { fn NOW() }
WHERE (clockDate = '08/10/2012') AND (userName = 'test')
END
J'utilise Visual Studio 2010 pour ce faire connecté à SQL Server Express 2008 sur mon ordinateur local. Je reçois une erreur indiquant: "La construction ou l'instruction SQL de l'instruction Compound n'est pas prise en charge". Cependant, cela est suivi d'un message indiquant qu'une ligne a été affectée et que, lorsque je consulte ma table Clock, elle ressemble à ce à quoi je m'attends. Quel est le meilleur moyen d'y parvenir?
Et ma deuxième partie de cette question se trouve dans mes déclarations WHERE. Existe-t-il une fonction permettant d’obtenir la date du jour dans la colonne clockDate plutôt que de devoir renseigner la date du jour? J'essaie juste de penser à l'avenir pour construire l'application front-end.
IF NOT EXISTS(SELECT * FROM Clock WHERE clockDate = { fn CURRENT_DATE() }) AND userName = 'test')
Encore une fois, cela me donne les résultats souhaités, mais pas après avoir obtenu une erreur "Erreur dans la clause WHERE près de 'CURRENT_DATE'. Impossible d'analyser le texte de la requête."
J'espère que j'ai bien expliqué cela, et merci pour votre aide !!
MODIFIER:
@RThomas @ w00te
OK, alors avec clockDate comme champ de date et breakOut comme champ de temps (0), cela devrait-il fonctionner? Cause: je reçois toujours un message "La construction ou l'instruction SQL de l'instruction Compound n'est pas prise en charge". Erreur de syntaxe, même si cela semble fonctionner.
IF NOT EXISTS (SELECT * FROM Clock WHERE (clockDate = GETDATE()) AND (userName = 'test'))
BEGIN
INSERT INTO Clock(clockDate, userName, breakOut)
Values(GETDATE(), 'test', GETDATE())
END
ELSE
BEGIN
UPDATE Clock
SET breakOut = GETDATE()
WHERE (clockDate = GETDATE()) AND (userName = 'test')
END
Mes résultats de table sont:
clockDate userName clockIn breakOut breakIn clockOut
08/10/2012 test NULL 11:24:38 NULL NULL
C'est le résultat que je veux mais cette erreur me confond. Est-ce une erreur de Visual Studio ou une erreur de SQL? Et je vais lire sur les déclarations de fusion, merci à vous deux pour les liens.
À première vue, votre tentative initiale semble assez proche. Je suppose que clockDate est un champ DateTime, alors essayez ceci:
IF (NOT EXISTS(SELECT * FROM Clock WHERE cast(clockDate as date) = '08/10/2012')
AND userName = 'test')
BEGIN
INSERT INTO Clock(clockDate, userName, breakOut)
VALUES(GetDate(), 'test', GetDate())
END
ELSE
BEGIN
UPDATE Clock
SET breakOut = GetDate()
WHERE Cast(clockDate AS Date) = '08/10/2012' AND userName = 'test'
END
Notez que getdate vous donne la date actuelle. Si vous essayez de comparer une date (sans l'heure), vous devez lancer un casting ou l'élément time fera échouer la comparaison.
Si clockDate n'est pas un champ datetime (juste une date), le moteur SQL le fera pour vous - inutile de transtyper une instruction set/insert.
IF (NOT EXISTS(SELECT * FROM Clock WHERE clockDate = '08/10/2012')
AND userName = 'test')
BEGIN
INSERT INTO Clock(clockDate, userName, breakOut)
VALUES(GetDate(), 'test', GetDate())
END
ELSE
BEGIN
UPDATE Clock
SET breakOut = GetDate()
WHERE clockDate = '08/10/2012' AND userName = 'test'
END
Comme d'autres l'ont souligné, la déclaration de fusion est un autre moyen de s'attaquer à cette même logique. Toutefois, dans certains cas, en particulier avec des ensembles de données volumineux, l’instruction de fusion peut être extrêmement lente, ce qui entraîne beaucoup d’activités de journalisation. Donc, savoir comment procéder comme indiqué ci-dessus reste une technique valable.
Comme d'autres personnes vous ont suggéré de consulter l'instruction MERGE mais personne n'a fourni de solution à l'aide de cette dernière, j'ajoute ma propre réponse avec cette construction TSQL particulière. Je parie que ça vous plaira.
Votre code comporte une faute de frappe dans votre instruction if
dans la partie not exists(select...)
. L'instruction select
interne ne comporte qu'une seule condition where
alors que la condition UserName est exclue du not exists
en raison de la fin de l'accolade non valide. Dans tous les cas, vous cédez trop d'accolades fermantes.
Je suppose que ceci est basé sur le fait que vous utilisez deux conditions where
dans l'instruction update
plus loin dans votre code.
Continuons à ma réponse ...
instruction MERGE est un superbe joyau TSQL très bien adapté aux situations "insérer ou mettre à jour" . Dans votre cas, cela ressemblerait au code suivant. Prenez en compte le fait que je déclare des variables qui sont probablement des paramètres de procédure stockée (je suppose).
declare @clockDate date = '08/10/2012';
declare @userName = 'test';
merge Clock as target
using (select @clockDate, @userName) as source (ClockDate, UserName)
on (target.ClockDate = source.ClockDate and target.UserName = source.UserName)
when matched then
update
set BreakOut = getdate()
when not matched then
insert (ClockDate, UserName, BreakOut)
values (getdate(), source.UserName, getdate());
IF NOT EXISTS(SELECT * FROM Clock
WHERE clockDate = '08/10/2012') AND userName = 'test')
A une parenthèse supplémentaire. Je pense que c'est bien si vous l'enlevez:
IF NOT EXISTS(SELECT * FROM Clock WHERE
clockDate = '08/10/2012' AND userName = 'test')
De plus, GETDATE () mettra la date du jour dans la colonne, mais si vous ne voulez pas avoir le temps, vous devrez jouer un peu. Je pense que CONVERT (varchar (8), GETDATE (), 112) ne vous donnerait que la partie date (et non l'heure).
IF NOT EXISTS(SELECT * FROM Clock WHERE
clockDate = CONVERT(varchar(8), GETDATE(), 112)
AND userName = 'test')
devrait probablement le faire.
PS: utilisez un fusion instruction :)
Vous devez le remplacer par WHERE clockDate = { fn CURRENT_DATE() } AND userName = 'test'
. Supprimez s'il vous plaît extra ")"
de { fn CURRENT_DATE() })