it-swarm.com.de

Überprüfen Sie, ob eine Zeile vorhanden ist, andernfalls fügen Sie ein

Ich muss eine gespeicherte T-SQL-Prozedur schreiben, die eine Zeile in einer Tabelle aktualisiert. Wenn die Zeile nicht vorhanden ist, fügen Sie sie ein. Alle diese Schritte werden von einer Transaktion umschlossen.

Dies ist für ein Buchungssystem, also muss es atomar und zuverlässig sein. Es muss true zurückgegeben werden, wenn die Transaktion abgeschlossen und der Flug gebucht wurde.

Ich bin neu in T-SQL und nicht sicher, wie man @@rowcount Benutzt. Das habe ich bis jetzt geschrieben. Bin ich auf der richtigen straße Ich bin sicher, es ist ein leichtes Problem für Sie.

-- BEGIN TRANSACTION (HOW TO DO?)

UPDATE Bookings
 SET TicketsBooked = TicketsBooked + @TicketsToBook
 WHERE FlightId = @Id AND TicketsMax < (TicketsBooked + @TicketsToBook)

-- Here I need to insert only if the row doesn't exists.
-- If the row exists but the condition TicketsMax is violated, I must not insert 
-- the row and return FALSE

IF @@ROWCOUNT = 0 
BEGIN

 INSERT INTO Bookings ... (omitted)

END

-- END TRANSACTION (HOW TO DO?)

-- Return TRUE (How to do?)
222
Robert

Schauen Sie sich den Befehl [~ # ~] merge [~ # ~] an. Sie können UPDATE, INSERT & DELETE in einer Anweisung ausführen.

Hier ist eine funktionierende Implementierung zur Verwendung von MERGE
- Überprüft, ob der Flug voll ist, bevor ein Update durchgeführt wird, andernfalls wird ein Insert durchgeführt.

if exists(select 1 from INFORMATION_SCHEMA.TABLES T 
              where T.TABLE_NAME = 'Bookings') 
begin
    drop table Bookings
end
GO

create table Bookings(
  FlightID    int identity(1, 1) primary key,
  TicketsMax    int not null,
  TicketsBooked int not null
)
GO

insert  Bookings(TicketsMax, TicketsBooked) select 1, 0
insert  Bookings(TicketsMax, TicketsBooked) select 2, 2
insert  Bookings(TicketsMax, TicketsBooked) select 3, 1
GO

select * from Bookings

Und dann ...

declare @FlightID int = 1
declare @TicketsToBook int = 2

--; This should add a new record
merge Bookings as T
using (select @FlightID as FlightID, @TicketsToBook as TicketsToBook) as S
    on  T.FlightID = S.FlightID
      and T.TicketsMax > (T.TicketsBooked + S.TicketsToBook)
  when matched then
    update set T.TicketsBooked = T.TicketsBooked + S.TicketsToBook
  when not matched then
    insert (TicketsMax, TicketsBooked) 
    values(S.TicketsToBook, S.TicketsToBook);

select * from Bookings
153
Sung M. Kim

Ich gehe von einer einzelnen Zeile für jeden Flug aus? Wenn ja:

IF EXISTS (SELECT * FROM Bookings WHERE FLightID = @Id)
BEGIN
    --UPDATE HERE
END
ELSE
BEGIN
   -- INSERT HERE
END

Ich gehe davon aus, dass Ihre Vorgehensweise einen Flug überbuchen kann, da eine neue Zeile eingefügt wird, wenn maximal 10 Tickets vorhanden sind und Sie 20 buchen.

147

Übergeben Sie Updlock-, Rowlock- und Holdlock-Hinweise, wenn Sie prüfen, ob die Zeile vorhanden ist.

begin tran /* default read committed isolation level is fine */

if not exists (select * from Table with (updlock, rowlock, holdlock) where ...)
    /* insert */
else
    /* update */

commit /* locks are released here */

Der Updlock-Hinweis erzwingt, dass die Abfrage eine Aktualisierungssperre für die Zeile übernimmt, sofern diese bereits vorhanden ist, und verhindert, dass andere Transaktionen sie ändern, bis Sie einen Commit oder ein Rollback ausführen.

Der Holdlock-Hinweis erzwingt, dass die Abfrage eine Bereichssperre erhält, und verhindert, dass andere Transaktionen eine Zeile hinzufügen, die Ihren Filterkriterien entspricht, bis Sie einen Commit oder ein Rollback ausführen.

Der Rowlock-Hinweis erzwingt eine Sperrung der Granularität auf Zeilenebene anstelle der Standardseitenebene, sodass Ihre Transaktion keine anderen Transaktionen blockiert, die versuchen, nicht verknüpfte Zeilen auf derselben Seite zu aktualisieren (wobei jedoch der Kompromiss zwischen reduzierten Konflikten und der Erhöhung von berücksichtigt wird) Overhead sperren - Sie sollten vermeiden, eine große Anzahl von Sperren auf Zeilenebene in einer einzigen Transaktion vorzunehmen.

Weitere Informationen finden Sie unter http://msdn.Microsoft.com/en-us/library/ms187373.aspx .

Beachten Sie, dass Sperren verwendet werden, wenn die Anweisungen ausgeführt werden, die sie benötigen. Durch das Aufrufen von begin tran erhalten Sie keine Immunität gegen eine andere Transaktion, bei der Sperren auf etwas angewendet werden, bevor Sie darauf zugreifen. Sie sollten versuchen, Ihre SQL so zu faktorisieren, dass Sperren so schnell wie möglich gehalten werden, indem Sie die Transaktion so schnell wie möglich ausführen (spät erwerben, früh freigeben).

Beachten Sie, dass Sperren auf Zeilenebene möglicherweise weniger effektiv sind, wenn Ihre PK ein Bigint ist, da das interne Hashing in SQL Server für 64-Bit-Werte degeneriert ist (verschiedene Schlüsselwerte können mit derselben Sperr-ID hashen).

64
Cassius Porcus

ich schreibe meine Lösung. Meine Methode steht nicht für 'if' oder 'merge'. Meine Methode ist einfach.

INSERT INTO TableName (col1,col2)
SELECT @par1, @par2
   WHERE NOT EXISTS (SELECT col1,col2 FROM TableName
                     WHERE [email protected] AND [email protected])

Zum Beispiel:

INSERT INTO Members (username)
SELECT 'Cem'
   WHERE NOT EXISTS (SELECT username FROM Members
                     WHERE username='Cem')

Erklärung:

(1) SELECT col1, col2 FROM Tabellenname WHERE col1 = @ par1 AND col2 = @ par2 Wählt aus den TableName-Suchwerten aus

(2) SELECT @ par1, @ par2 WHERE NOT EXISTS Es dauert, wenn nicht vorhanden aus (1) Unterabfrage

(3) Fügt in TableName (2) Schrittwerte ein

37
Cem

Dies ist etwas, was ich erst kürzlich tun musste:

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[cjso_UpdateCustomerLogin]
    (
      @CustomerID AS INT,
      @UserName AS VARCHAR(25),
      @Password AS BINARY(16)
    )
AS 
    BEGIN
        IF ISNULL((SELECT CustomerID FROM tblOnline_CustomerAccount WHERE CustomerID = @CustomerID), 0) = 0
        BEGIN
            INSERT INTO [tblOnline_CustomerAccount] (
                [CustomerID],
                [UserName],
                [Password],
                [LastLogin]
            ) VALUES ( 
                /* CustomerID - int */ @CustomerID,
                /* UserName - varchar(25) */ @UserName,
                /* Password - binary(16) */ @Password,
                /* LastLogin - datetime */ NULL ) 
        END
        ELSE
        BEGIN
            UPDATE  [tblOnline_CustomerAccount]
            SET     UserName = @UserName,
                    Password = @Password
            WHERE   CustomerID = @CustomerID    
        END

    END
2
TheTXI

Ich konnte endlich eine Zeile einfügen, unter der Bedingung, dass sie noch nicht existiert, und zwar unter Verwendung des folgenden Modells:

INSERT INTO table ( column1, column2, column3 )
(
    SELECT $column1, $column2, $column3
      WHERE NOT EXISTS (
        SELECT 1
          FROM table 
          WHERE column1 = $column1
          AND column2 = $column2
          AND column3 = $column3 
    )
)

was ich gefunden habe bei:

http://www.postgresql.org/message-id/[email protected]

2
Paul G

Sie können die Merge -Funktionalität verwenden, um zu erreichen. Ansonsten können Sie Folgendes tun:

declare @rowCount int

select @[email protected]@RowCount

if @rowCount=0
begin
--insert....
1
JoshBerke
INSERT INTO [DatabaseName1].dbo.[TableName1] SELECT * FROM [DatabaseName2].dbo.[TableName2]
 WHERE [YourPK] not in (select [YourPK] from [DatabaseName1].dbo.[TableName1])
0
Almamun

Die beste Lösung für dieses Problem besteht darin, zuerst die Datenbankspalte UNIQUE zu machen

ALTER TABLE table_name ADD UNIQUE KEY

THEN INSERT IGNORE INTO table_name, der Wert wird nicht eingefügt, wenn er zu einem doppelten Schlüssel führt/bereits in der Tabelle vorhanden ist.

0
Maurice Elagu

Die vollständige Lösung finden Sie weiter unten (einschließlich Cursorstruktur). Vielen Dank an Cassius Porcus für das begin trans ... commit Code aus dem obigen Beitrag.

declare @mystat6 bigint
declare @mystat6p varchar(50)
declare @mystat6b bigint

DECLARE mycur1 CURSOR for

 select result1,picture,bittot from  all_Tempnogos2results11

 OPEN mycur1

 FETCH NEXT FROM mycur1 INTO @mystat6, @mystat6p , @mystat6b

 WHILE @@Fetch_Status = 0
 BEGIN

 begin tran /* default read committed isolation level is fine */

 if not exists (select * from all_Tempnogos2results11_uniq with (updlock, rowlock, holdlock)
                     where all_Tempnogos2results11_uniq.result1 = @mystat6 
                        and all_Tempnogos2results11_uniq.bittot = @mystat6b )
     insert all_Tempnogos2results11_uniq values (@mystat6 , @mystat6p , @mystat6b)

 --else
 --  /* update */

 commit /* locks are released here */

 FETCH NEXT FROM mycur1 INTO @mystat6 , @mystat6p , @mystat6b

 END

 CLOSE mycur1

 DEALLOCATE mycur1
 go
0
user2836818