sql - tablas - SI EXISTE, LUEGO SELECCIONE MÁS INSERTAR Y LUEGO SELECCIONAR
porque se dañan las tablas en mysql (7)
¿Cómo se dice lo siguiente en Microsoft SQL Server 2005:
IF EXISTS (SELECT * FROM Table WHERE FieldValue='''') THEN
SELECT TableID FROM Table WHERE FieldValue=''''
ELSE
INSERT INTO TABLE(FieldValue) VALUES('''')
SELECT TableID FROM Table WHERE TableID=SCOPE_IDENTITY()
END IF
Lo que estoy tratando de hacer es ver si ya hay un valor de campo en blanco, y si lo hay, devolver ese TableID; de lo contrario, inserte un valor de campo en blanco y devuelva la clave primaria correspondiente.
Estabas cerca:
IF EXISTS (SELECT * FROM Table WHERE FieldValue='''')
SELECT TableID FROM Table WHERE FieldValue=''''
ELSE
BEGIN
INSERT INTO TABLE (FieldValue) VALUES ('''')
SELECT TableID FROM Table WHERE TableID=SCOPE_IDENTITY()
END
Solo tienes que cambiar la estructura del if...else..endif
algo así:
if exists(select * from Table where FieldValue='''') then begin
select TableID from Table where FieldValue=''''
end else begin
insert into Table (FieldValue) values ('''')
select TableID from Table where TableID = scope_identity()
end
También podrías hacer:
if not exists(select * from Table where FieldValue='''') then begin
insert into Table (FieldValue) values ('''')
end
select TableID from Table where FieldValue=''''
O:
if exists(select * from Table where FieldValue='''') then begin
select TableID from Table where FieldValue=''''
end else begin
insert into Table (FieldValue) values ('''')
select scope_identity() as TableID
end
DECLARE @t1 TABLE (
TableID int IDENTITY,
FieldValue varchar(20)
)
--<< No empty string
IF EXISTS (
SELECT *
FROM @t1
WHERE FieldValue = ''''
) BEGIN
SELECT TableID
FROM @t1
WHERE FieldValue=''''
END
ELSE BEGIN
INSERT INTO @t1 (FieldValue) VALUES ('''')
SELECT SCOPE_IDENTITY() AS TableID
END
--<< A record with an empty string already exists
IF EXISTS (
SELECT *
FROM @t1
WHERE FieldValue = ''''
) BEGIN
SELECT TableID
FROM @t1
WHERE FieldValue=''''
END
ELSE BEGIN
INSERT INTO @t1 (FieldValue) VALUES ('''')
SELECT SCOPE_IDENTITY() AS TableID
END
IF EXISTS (SELECT 1 FROM Table WHERE FieldValue='''')
BEGIN
SELECT TableID FROM Table WHERE FieldValue=''''
END
ELSE
BEGIN
INSERT INTO TABLE(FieldValue) VALUES('''')
SELECT SCOPE_IDENTITY() AS TableID
END
Consulte aquí para obtener más información sobre IF ELSE
Nota: escrito sin una instalación de SQL Server a mano para verificar esto pero creo que es correcto
Además, he cambiado el bit EXISTS para hacer SELECCIONAR 1 en lugar de SELECCIONAR * ya que no me importa lo que se devuelve dentro de un EXISTO, siempre y cuando algo haya cambiado también el bit SCOPE_IDENTITY () para devolver solo la identidad asumiendo que TableID es la columna de identidad
Parece que tu mesa no tiene llave. Debería poder simplemente probar INSERT
: si es un duplicado, la restricción de clave morderá y INSERT
. No se preocupe: solo necesita asegurarse de que la aplicación no vea / ignore el error. Cuando dices ''clave primaria'' presumiblemente quieres decir valor de IDENTITY
. Eso está muy bien, pero también necesita una restricción clave (por ejemplo, UNIQUE
) en su clave natural.
Además, me pregunto si su procedimiento está haciendo demasiado. Considere tener procedimientos separados para las acciones ''crear'' y ''leer'', respectivamente.
Debe hacer esto en la transacción para asegurarse de que dos clientes simultáneos no inserten el mismo fieldValue dos veces:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
DECLARE @id AS INT
SELECT @id = tableId FROM table WHERE fieldValue=@newValue
IF @id IS NULL
BEGIN
INSERT INTO table (fieldValue) VALUES (@newValue)
SELECT @id = SCOPE_IDENTITY()
END
SELECT @id
COMMIT TRANSACTION
también puede usar el bloqueo comprobado doble para reducir la sobrecarga de bloqueo
DECLARE @id AS INT
SELECT @id = tableID FROM table (NOLOCK) WHERE fieldValue=@newValue
IF @id IS NULL
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
SELECT @id = tableID FROM table WHERE fieldValue=@newValue
IF @id IS NULL
BEGIN
INSERT INTO table (fieldValue) VALUES (@newValue)
SELECT @id = SCOPE_IDENTITY()
END
COMMIT TRANSACTION
END
SELECT @id
En cuanto a por qué ISOLATION LEVEL SERIALIZABLE es necesario, cuando se encuentra dentro de una transacción serializable, el primer SELECT que golpea la tabla crea un bloqueo de rango que cubre el lugar donde debe estar el registro, para que nadie más pueda insertar el mismo registro hasta que finalice la transacción.
Sin AISLAMIENTO NIVEL SERIALIZABLE, el nivel de aislamiento predeterminado (LECTURA COMPROMETIDA) no bloquearía la tabla en el momento de la lectura, por lo que entre SELECCIONAR y ACTUALIZAR, alguien aún podría insertar. Las transacciones con nivel de aislamiento LECTURA COMPROMETIDA no provocan que SELECCIONAR se bloquee. Las transacciones con READATABLE READS bloquean el registro (si se encuentra) pero no el espacio.
create schema tableName authorization dbo
go
IF OBJECT_ID (''tableName.put_fieldValue'', ''P'' ) IS NOT NULL
drop proc tableName.put_fieldValue
go
create proc tableName.put_fieldValue(@fieldValue int) as
declare @tableid int = 0
select @tableid = tableid from table where fieldValue=''''
if @tableid = 0 begin
insert into table(fieldValue) values('''')
select @tableid = scope_identity()
end
return @tableid
go
declare @tablid int = 0
exec @tableid = tableName.put_fieldValue('''')