Verificați dacă un rând există, în caz contrar se introduce

Am nevoie pentru a scrie un T-SQL proceduri stocate care actualizează un rând într-un tabel. Dacă rand nu't există, introduceți-l. Toate aceste măsuri înfășurat de o tranzacție.

Acest lucru este pentru un sistem de rezervare, așa că trebuie să fie atomică și de încredere. Acesta trebuie să se întoarcă adevărat în cazul în care tranzacția a fost comisă și zborul rezervat.

Am'm nou pentru T-SQL, și nu sunt sigur despre cum să folosiți @@rowcount. Aceasta este ceea ce am'am scris până acum. Sunt pe drumul cel bun? Am'sunt sigur că este o problemă ușoară pentru tine.

-- 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?)
Comentarii la întrebare (2)

Uită-te la MERGE comandă. Poți să faci "UPDATE", "INSERT" & "DELETE", într-o declarație.

Aici este un lucru punere în aplicare privind utilizarea MERGE

  • Se verifică dacă zborul este complet înainte de a face o actualizare, altcineva nu o introduce.

dacă există(selectați 1 din INFORMATION_SCHEMA.TABELELE T în cazul în care T. TABLE_NAME = 'Rezervari') începe drop table Rezervările end DU-te

crea Rezervări de masă( FlightID int identitate(1, 1) cheie primară, TicketsMax int not null, TicketsBooked int not null ) DU-te

introduce Rezervari(TicketsMax, TicketsBooked) selectați 1, 0 introduce Rezervari(TicketsMax, TicketsBooked) selectați 2, 2 introduce Rezervari(TicketsMax, TicketsBooked) selectați 3, 1 DU-te

selectați * de la Rezervari

Și apoi ...

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
Comentarii (3)

Presupun că un singur rand pentru fiecare zbor? Dacă așa:

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

Presupun că ceea ce am spus, ca mod de a face lucrurile pot cere mai mult un zbor, ca se va introduce un rând nou, atunci când sunt 10 bilete max și vă rezervarea 20.

Comentarii (7)

Trece updlock, rowlock, holdlock indicii atunci când testarea pentru existența rând.

begin tran /* implicit citiți angajamentul de nivelul de izolare este bine */

dacă nu există (select from Tabel cu (updlock, rowlock, holdlock) unde ...) / inserare / altceva / actualizare */

comite / încuietori sunt puse aici /

La updlock indiciu forțele de interogare pentru a lua o actualizare de blocare pe rând dacă acesta există deja, prevenind alte tranzacții la modificarea până nu se angajeze sau să se rostogolească înapoi.

La holdlock indiciu forțele de interogare pentru a lua o serie de blocare, prevenind alte tranzacții la adăugarea unui rând de potrivire dumneavoastră de criterii de filtrare până nu se angajeze sau să se rostogolească înapoi.

La rowlock indiciu forțele de blocare granularitate la rândul nivel în loc de default la nivel de pagină, astfel încât tranzacția a câștigat't bloca alte tranzacții încercarea de a actualiza legătură rânduri în aceeași pagină (dar să fie conștienți de trade-off între redusă dispută și creșterea blocare deasupra capului - ar trebui să evite a lua un număr mare de nivel de rând blochează într-o singură tranzacție).

Vezi http://msdn.microsoft.com/en-us/library/ms187373.aspx pentru mai multe informații.

Rețineți că încuietorile sunt luate ca declarațiile pe care le ia sunt executate - invocarea begin tran nu't oferi imunitate împotriva o altă tranzacție ciupit blochează pe ceva înainte de a ajunge la ea. Ar trebui să încercați și factor SQL pentru a ține încuietori pentru cel mai scurt timp posibil de a comite tranzacția cât mai curând posibil (de a dobândi târziu, eliberați mai devreme).

Rețineți că la nivel de rând încuietori pot fi mai puțin eficiente dacă PK este un bigint, ca intern hashing pe SQL Server este degenerat pentru 64-bit valori (diferite valori-cheie poate hash la acelasi id blocare).

Comentarii (4)

am'm scris soluția mea. metoda mea nu't sta 'daca' sau 'merge'. metoda mea este ușor.

INSERT INTO TableName (col1,col2)
SELECT @par1, @par2
   WHERE NOT EXISTS (SELECT col1,col2 FROM TableName
                     WHERE col1=@par1 AND col2=@par2)

De Exemplu:

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

Explicație:

(1) SELECT col1,col2 FROM nume tabelă UNDE col1=@par1 ȘI col2=@par2 Se selectează din tabela nume căutat valori

(2) SELECTAȚI @par1, @par2 în cazul în CARE NU EXISTĂ E nevoie, dacă nu există la (1) subinterogare

(3) Introduce în TableName (2) pasul valori

Comentarii (2)

În cele din urmă am fost capabil de a introduce un rând, cu condiția că aceasta nu't există deja, folosind următorul model:

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

ceea ce am găsit la:

http://www.postgresql.org/message-id/87hdow4ld1.fsf@stark.xeocode.com

Comentarii (1)

Acest lucru este ceva recent am avut de-a face:

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
Comentarii (1)

Ai putea folosi Merge Funcționalitate pentru a atinge. În caz contrar, puteți face:

declare @rowCount int

select @rowCount=@@RowCount

if @rowCount=0
begin
--insert....
Comentarii (2)

Soluție completă este mai jos (inclusiv cursorul structura). Multe mulțumiri pentru Cassius Porcus pentru a începe trans ... comite` cod de la postarea de mai sus.

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
Comentarii (0)
INSERT INTO [DatabaseName1].dbo.[TableName1] SELECT * FROM [DatabaseName2].dbo.[TableName2]
 WHERE [YourPK] not in (select [YourPK] from [DatabaseName1].dbo.[TableName1])
Comentarii (0)

Cea mai bună abordare a acestei probleme este de a face prima coloana de date UNICE

ALTER TABLE nume_tabel ADD CHEIE UNICĂ

APOI INTRODUCEȚI IGNORA ÎN nume_tabel ,o valoare't fi introdus în cazul în care rezultă într-o cheie duplicat/există deja în tabel.

Comentarii (1)
INSERT INTO table ( column1, column2, column3 )
SELECT $column1, $column2, $column3
EXCEPT SELECT column1, column2, column3
FROM table
Comentarii (2)