Anda di halaman 1dari 74

How to generate auto increment field in select query

If it is MySql you can try SELECT @n := @n + 1 n, first_name, last_name FROM table1, (SELECT @n := 0) m ORDER BY first_name, last_name SQLFiddle And for SQLServer SELECT row_number() OVER (ORDER BY first_name, last_name) n, first_name, last_name FROM table1 here's for SQL server, Oracle, PostgreSQL which support window functions. SELECT ROW_NUMBER() OVER (ORDER BY first_name, last_name) Sequence_no, first_name, last_name FROM tableName SQLFiddle Demo

135 - Funciones escalares (crear y llamar)


Una funcin escalar retorna un nico valor. Como todas las funciones, se crean con la instruccin "create function". La sintaxis bsica es: create function NOMBRE (@PARAMETRO TIPO=VALORPORDEFECTO) returns TIPO begin INSTRUCCIONES return VALOR end; Luego del nombre se colocan (opcionalmente) los parmetros de entrada con su tipo. La clusula "returns" indica el tipo de dato retornado. El cuerpo de la funcin, se define en un bloque "begin...end" que contiene las instrucciones que retornan el valor. El tipo del valor retornado puede ser de cualquier tipo, excepto text, ntext, image, cursor o timestamp. Creamos una simple funcin denominada "f_promedio" que recibe 2 valores y retorna el promedio: create function f_promedio (@valor1 decimal(4,2), @valor2 decimal(4,2) ) returns decimal (6,2) as begin declare @resultado decimal(6,2) set @resultado=(@valor1+@valor2)/2 return @resultado end; Entonces, luego de "create function" y el nombre de la funcin, se deben especificar los parmetros de entrada con sus tipos de datos (entre parntesis), el tipo de dato que retorna luego de "returns", luego de "as" comienza el bloque "begin...end" dentro del cual se encuentran las instrucciones de procesamiento y el valor retornado luego de "return". En el ejemplo anterior se declara una variable local a la funcin (desaparece al salir de la funcin) que calcula el resultado que se retornar. Al hacer referencia a una funcin escalar, se debe especificar el propietario y el nombre de la funcin: select dbo.f_promedio(5.5,8.5); Cuando llamamos a funciones que tienen definidos parmetros de entrada DEBEMOS suministrar SIEMPRE un valor para l.

Si llamamos a la funcin anterior sin enviarle los valores para los parmetros: select dbo.f_promedio(); SQL Server muestra un mensaje de error indicando que necesita argumentos. Creamos una funcin a la cual le enviamos una fecha y nos retorna el nombre del mes en espaol: create function f_nombreMes (@fecha datetime='2007/01/01') returns varchar(10) as begin declare @nombre varchar(10) set @nombre= case datename(month,@fecha) when 'January' then 'Enero' when 'February' then 'Febrero' when 'March' then 'Marzo' when 'April' then 'Abril' when 'May' then 'Mayo' when 'June' then 'Junio' when 'July' then 'Julio' when 'August' then 'Agosto' when 'September' then 'Setiembre' when 'October' then 'Octubre' when 'November' then 'Noviembre' when 'December' then 'Diciembre' end--case return @nombre end; Analicemos: luego de "create function" y el nombre de la funcin, especificamos los parmetros de entrada con sus tipos de datos (entre parntesis). El parmetro de entrada tiene definido un valor por defecto. Luego de los parmetros de entrada se indica el tipo de dato que retorna luego de "returns"; luego de "as" comienza el bloque "begin...end" dentro del cual se encuentran las instrucciones de procesamiento y el valor retornado luego de "return". Las funciones que retornan un valor escalar pueden emplearse en cualquier consulta donde se coloca un campo. Recuerde que al invocar una funcin escalar, se debe especificar el propietario y el nombre de la funcin: select nombre, dbo.f_nombreMes(fechaingreso) as 'mes de ingreso' from empleados; No olvide que cuando invocamos funciones que tienen definidos parmetros de entrada DEBEMOS suministrar SIEMPRE un valor para l.

Podemos colocar un valor por defecto al parmetro, pero al invocar la funcin, para que tome el valor por defecto DEBEMOS especificar "default". Por ejemplo, si llamamos a la funcin anterior sin enviarle un valor: select dbo.f_nombreMes(); SQL Server muestra un mensaje de error indicando que necesita argumento. Para que tome el valor por defecto debemos enviar "default" como argumento: select dbo.f_nombreMes(default); La instruccin "create function" debe ser la primera sentencia de un lote.

Existen tres tipos de funciones en SQL Server una parece ser como el tipo de funciones de los leguajes de programacin donde se le enva un valor y retorna un resulta a esta se les llama funciones escalares, los otros dos tipos de funciones resultan un hibrido entre vista y procedimiento almacenado, permitiendo enviar parmetros a una consulta, en este video se revisa su funcionamiento.

Use northwind go 1.Creacion de Funciones Escalares CREATE FUNCTION Iva (@DATE money) RETURNS money AS BEGIN Declare @iva money Set @Iva=@date*.12 Return(@iva) END 3.Revisar la funcion debe de escribirse el nombre con dos partes Select unitprice, dbo.iva(unitprice) as ivafrom [ord er details] 4.borrar la funcion drop function iva 5.Otro ejemplo de funcion CREATE Function Comision(@valor money) ReturnS money

96 - Exists y No Exists
Los operadores "exists" y "not exists" se emplean para determinar si hay o no datos en una lista de valores. Estos operadores pueden emplearse con subconsultas correlacionadas para restringir el resultado de una consulta exterior a los registros que cumplen la subconsulta (consulta interior). Estos operadores retornan "true" (si las subconsultas retornan registros) o "false" (si las subconsultas no retornan registros). Cuando se coloca en una subconsulta el operador "exists", SQL Server analiza si hay datos que coinciden con la subconsulta, no se devuelve ningn registro, es como un test de existencia; SQL Server termina la recuperacin de registros cuando por lo menos un registro cumple la condicin "where" de la subconsulta. La sintaxis bsica es la siguiente: ... where exists (SUBCONSULTA); En este ejemplo se usa una subconsulta correlacionada con un operador "exists" en la clusula "where" para devolver una lista de clientes que compraron el artculo "lapiz": select cliente,numero from facturas as f where exists (select *from Detalles as d where f.numero=d.numerofactura and d.articulo='lapiz'); Puede obtener el mismo resultado empleando una combinacin. Podemos buscar los clientes que no han adquirido el artculo "lapiz" empleando "if not exists": select cliente,numero from facturas as f where not exists (select *from Detalles as d where f.numero=d.numerofactura and d.articulo='lapiz');

Recuperar valores de identidad o de autonumeracin


.NET Framework 4.5 Otras versiones

Este tema an no ha recibido ninguna valoracin - Valorar este tema Una clave principal de una base de datos relacional es una columna o combinacin de columnas que siempre contienen valores nicos. Conocer el valor de la clave principal permite localizar la fila que la contiene. Los motores de bases de datos relacionales, como SQL Server, Oracle y Microsoft Access/Jet admiten la creacin de columnas de incremento automtico que pueden designarse como claves principales. Estos valores los genera el servidor cuando se agregan filas a una tabla. En SQL Server se establece la propiedad de identidad de una columna, en Oracle se crea una secuencia y en Microsoft Access se crea una columna Autonumrica. DataColumn tambin se puede utilizar para generar de manera automtica valores incrementales estableciendo la propiedad AutoIncrement en true. No obstante, podra haber valores duplicados en instancias distintas de DataTable si varias aplicaciones cliente estn generando por separado valores incrementales de manera automtica. Si se tiene un servidor que genera de manera automtica valores incrementales se eliminan posibles conflictos, pues se permite a cada usuario recuperar el valor generado para cada fila insertada. Durante una llamada al mtodo Update de DataAdapter, la base de datos puede volver a enviar datos a la aplicacin ADO.NET como parmetros de salida o como el primer registro devuelto del conjunto de resultados de una instruccin SELECT ejecutada en el mismo lote que la instruccin INSERT. ADO.NET puede recuperar estos valores y actualizar las columnas correspondientes en el DataRow que se est actualizando. Algunos motores de base de datos, como los de Microsoft Access Jet, no admiten parmetros de salida y no pueden procesar varias instrucciones en un nico lote. Cuando trabaje con el motor de base de datos de Jet, puede recuperar el nuevo valor Autonumrico generado para una fila insertada ejecutando un comando SELECT distinto en un controlador de eventos para el evento RowUpdated de DataAdapter.

Nota

Una opcin alternativa al uso de un valor de incremento automtico es utilizar el mtodo NewGuid de un obj (identificador nico global) en el equipo cliente que se pueda copiar al servidor cuando se inserte una nueva f

binario de 16 bits que se crea mediante un algoritmo que permite que haya una alta probabilidad de que no se de SQL Server, el GUID se almacena en una columnauniqueidentifier que SQL Server puede generar autom SQL NEWID(). Utilizar un GUID como clave principal puede afectar de manera negativa al rendimiento. SQ funcin NEWSEQUENTIALID(), que genera un GUID secuencial que no est garantizado que sea nico gl forma ms eficaz.

Recuperar valores de columnas de identidad de SQL Server


Cuando trabaje con Microsoft SQL Server, puede crear procedimientos almacenados con un parmetro de salida para devolver el valor de identidad de una fila insertada.La siguiente tabla describe las tres funciones de Transact-SQL en SQL Server que se pueden utilizar para recuperar valores de columna de identidad.

Funcin SCOPE_IDENTITY

Descripcin Devuelve el ltimo valor de identidad en el mbito de ejecucin actual. SCOPE_IDENTITY se recomienda en la mayora de los casos. Contiene el ltimo valor de identidad generado en cualquier tabla de la sesin actual. @@IDENTITY puede verse afectado por los desencadenadores y no devolver el valor de identidad esperado. Devuelve el ltimo valor de identidad generado para una tabla concreta de cualquier sesin y en cualquier mbito.

@@IDENTITY

IDENT_CURRENT

El siguiente procedimiento almacenado muestra cmo insertar una fila en la tabla Categories y utilizar un parmetro de salida para devolver el nuevo valor de identidad generado por la funcin Transact-SQL SCOPE_IDENTITY(). CREATE PROCEDURE dbo.InsertCategory @CategoryName nvarchar(15), @Identity int OUT AS INSERT INTO Categories (CategoryName) VALUES(@CategoryName) SET @Identity = SCOPE_IDENTITY() El procedimiento almacenado se puede especificar como el origen de InsertCommand de un objeto SqlDataAdapter.La propiedad CommandType de InsertCommand debe establecerse en StoredProcedure.La salida de identidad se recupera creando un SqlParameter que tiene un ParameterDirection de Output.Cuando se procesaInsertCommand, el valor de identidad de incremento automtico se devuelve y se coloca en la columna CategoryID de la fila actual si se establece la propiedadUpdatedRowSource del comando de insercin en UpdateRowSource.OutputParameters o UpdateRowSource.Both. Si el comando de insercin ejecuta un lote que incluye tanto una instruccin INSERT como una instruccin SELECT que devuelven el nuevo valor de identidad, entonces puede recuperar el nuevo

valor estableciendo la propiedad UpdatedRowSource del comando de insercin en UpdateRowSource.FirstReturnedRecord. C# VB private static void RetrieveIdentity(string connectionString) { using (SqlConnection connection = new SqlConnection(connectionString)) { // Create a SqlDataAdapter based on a SELECT query. SqlDataAdapter adapter = new SqlDataAdapter( "SELECT CategoryID, CategoryName FROM dbo.Categories", connection); //Create the SqlCommand to execute the stored procedure. adapter.InsertCommand = new SqlCommand("dbo.InsertCategory", connection); adapter.InsertCommand.CommandType = CommandType.StoredProcedure; // Add the parameter for the CategoryName. Specifying the // ParameterDirection for an input parameter is not required. adapter.InsertCommand.Parameters.Add( new SqlParameter("@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")); // Add the SqlParameter to retrieve the new identity value. // Specify the ParameterDirection as Output. SqlParameter parameter = adapter.InsertCommand.Parameters.Add( "@Identity", SqlDbType.Int, 0, "CategoryID"); parameter.Direction = ParameterDirection.Output; // Create a DataTable and fill it. DataTable categories = new DataTable(); adapter.Fill(categories); // Add a new row. DataRow newRow = categories.NewRow(); newRow["CategoryName"] = "New Category"; categories.Rows.Add(newRow); adapter.Update(categories); Console.WriteLine("List All Rows:"); foreach (DataRow row in categories.Rows) {

{ Console.WriteLine("{0}: {1}", row[0], row[1]); } } } }

Combinar nuevos valores de identidad


Un caso frecuente es llamar al mtodo GetChanges de DataTable para crear una copia que contiene nicamente filas modificadas y utilizar la nueva copia al llamar al mtodo Update de DataAdapter. Esto es especialmente til cuando hay que calcular las referencias de las filas modificadas en un componente independiente que realiza la actualizacin. Despus de la actualizacin, la copia puede contener nuevos valores de identidad que se deben volver a combinar en el DataTable original. Probablemente los nuevos valores de identidad son diferentes a los valores originales de DataTable. Para conseguir la combinacin, se deben mantener los valores originales de las columnas AutoIncrement en la copia para poder localizar y actualizar filas existentes en el original DataTable, en lugar de anexar filas nuevas con los nuevos valores de identidad. No obstante, de manera predeterminada estos valores se pierden despus de una llamada al mtodo Update de DataAdapter, debido a que se llama implcitamente a AcceptChanges en cada DataRow actualizada. Hay dos maneras de mantener los valores originales de DataColumn en DataRow durante una actualizacin de DataAdapter: El primer mtodo para mantener los valores originales consiste en establecer la propiedad AcceptChangesDuringUpdate de DataAdapter en false. Esto afecta a cada DataRow de DataTable que se est actualizando. Para obtener ms informacin y un ejemplo de cdigo, vea AcceptChangesDuringUpdate. El segundo mtodo consiste en escribir cdigo en el controlador de eventos RowUpdated de DataAdapter para establecer Status en SkipCurrentRow. DataRow se actualiza pero se mantiene el valor original de cada DataColumn. Este mtodo permite mantener los valores originales en algunas filas y no en otras. Por ejemplo, el cdigo puede mantener los valores originales de filas agregadas y no los de filas editadas o eliminadas comprobando primero StatementType y, a continuacin, estableciendo Status en SkipCurrentRow nicamente para filas con un StatementType de Insert. Cuando se utiliza alguno de estos mtodos para mantener los valores originales de DataRow durante una actualizacin de DataAdapter, ADO.NET realiza una serie de acciones para establecer los valores actuales de DataRow a los nuevos valores devueltos por parmetros de salida o por la primera fila devuelta de un conjunto de resultados, al tiempo que se mantiene el valor original de cada DataColumn. Primero, se llama al mtodo AcceptChanges de DataRow para mantener los valores actuales como valores originales y, a continuacin, se asignan los nuevos valores. Despus de estas acciones, las DataRows que tienen la propiedad RowState establecida en Addedtendrn su propiedad RowState establecida en Modified, lo que puede ser inesperado. El modo en que se aplican los resultados del comando a cada DataRow que se actualiza lo determina la propiedad UpdatedRowSource de cada DbCommand. Esta propiedad se establece en un valor desde la enumeracin UpdateRowSource.

La siguiente tabla describe cmo afectan los valores de enumeracin UpdateRowSource a la propiedad RowState de las filas actualizadas.

Nombre del miembro Both

Descripcin

Se llama a AcceptChanges y tanto los parmetros de salida como los valores de resultados devuelto se colocan en la DataRow que se est actualizando. Si no hay aplicar, RowState ser Unchanged.

FirstReturnedRecord

Si se devuelve una fila, se llama a AcceptChanges y la fila se asigna a la fila mo estableciendo RowState en Modified. Si no se devuelve ninguna fila, entonces n a AcceptChanges y RowState permanece en Added.

None

Se pasan por alto todos los parmetros o filas devueltos. No hay llamada a Accep en Added.

OutputParameters

Se llama a AcceptChanges y todos los parmetros de salida se asignan a la fila m estableciendo RowState en Modified.Si no hay parmetros de salida, RowState

Ejemplo
Este ejemplo muestra la extraccin de filas modificadas desde DataTable y el uso de SqlDataAdapter para actualizar el origen de datos y recuperar un nuevo valor de columna de identidad. InsertCommand ejecuta dos instrucciones Transact-SQL; la primera es la instruccin INSERT y la segunda es la instruccin SELECT. INSERT INTO dbo.Shippers (CompanyName) VALUES (@CompanyName); SELECT ShipperID, CompanyName FROM dbo.Shippers WHERE ShipperID = SCOPE_IDENTITY(); La propiedad UpdatedRowSource del comando de insercin se establece en UpdateRowSource.FirstReturnedRow y la propiedad MissingSchemaAction de DataAdapterse establece en MissingSchemaAction.AddWithKey. DataTable se rellena y el cdigo agrega una nueva fila a DataTable.A continuacin, las filas modificadas se extraen en un nuevo DataTable, que se pasa a DataAdapter, el cual actualiza el servidor. C# VB private static void MergeIdentityColumns(string connectionString) { using (SqlConnection connection = new SqlConnection(connectionString)) { // Create the DataAdapter SqlDataAdapter adapter = new SqlDataAdapter( "SELECT ShipperID, CompanyName FROM dbo.Shippers", connection);

//Add the InsertCommand to retrieve new identity value. adapter.InsertCommand = new SqlCommand( "INSERT INTO dbo.Shippers (CompanyName) " + "VALUES (@CompanyName); " + "SELECT ShipperID, CompanyName FROM dbo.Shippers " + "WHERE ShipperID = SCOPE_IDENTITY();", connection); // Add the parameter for the inserted value. adapter.InsertCommand.Parameters.Add( new SqlParameter("@CompanyName", SqlDbType.NVarChar, 40, "CompanyName")); adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both; // MissingSchemaAction adds any missing schema to // the DataTable, including identity columns adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey; // Fill the DataTable. DataTable shipper = new DataTable(); adapter.Fill(shipper); // Add a new shipper. DataRow newRow = shipper.NewRow(); newRow["CompanyName"] = "New Shipper"; shipper.Rows.Add(newRow); // Add changed rows to a new DataTable. This // DataTable will be used by the DataAdapter. DataTable dataChanges = shipper.GetChanges(); // Add the event handler. adapter.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated); adapter.Update(dataChanges); connection.Close(); // Merge the updates. shipper.Merge(dataChanges); // Commit the changes. shipper.AcceptChanges(); Console.WriteLine("Rows after merge."); foreach (DataRow row in shipper.Rows) { { Console.WriteLine("{0}: {1}", row[0], row[1]);

} } } }

El controlador de eventos OnRowUpdated comprueba StatementType de SqlRowUpdatedEventArgs para determinar si la fila es una insercin.Si lo es, entonces la propiedad se establece Status en SkipCurrentRow.La fila est actualizada, pero los valores originales de la fila se mantienen.En el cuerpo principal del procedimiento, se llama al mtodo Merge para combinar el nuevo valor de identidad en el DataTable original y, finalmente, se llama a AcceptChanges. C# VB protected static void OnRowUpdated( object sender, SqlRowUpdatedEventArgs e) { // If this is an insert, then skip this row. if (e.StatementType == StatementType.Insert) { e.Status = UpdateStatus.SkipCurrentRow; } }

Recuperar valores de autonumeracin de Microsoft Access


Esta seccin incluye un ejemplo que muestra cmo recuperar valores de Autonumber desde una base de datos de Jet 4.0. El motor de la base de datos de Jet no admite la ejecucin de varias instrucciones en un lote o el uso de parmetros de salida, por lo que no es posible utilizar ninguna de estas tcnicas para devolver el nuevo valorAutonumber asignado a una fila insertada. No obstante, se puede agregar cdigo al controlador de eventos RowUpdated que ejecuta una instruccin SELECT @@IDENTITY independiente para recuperar el valor Autonumber nuevo.

Ejemplo
En lugar de agregar informacin de esquema utilizando MissingSchemaAction.AddWithKey, este ejemplo configura DataTable con el esquema adecuado antes de llamar a OleDbDataAdapter para rellenar DataTable. En este caso, la columna CategoryID se configura para disminuir el valor asignado a cada fila insertada empezando desde cero, estableciendo AutoIncrement en true, AutoIncrementSeed en 0 y AutoIncrementStep en 1. Entonces, el cdigo agrega dos filas nuevas y utiliza GetChanges para agregar las filas modificadas a un nuevo DataTable que se pasa al mtodo Update. C# VB

private static OleDbConnection connection = null; private static void MergeIdentityColumns(OleDbConnection connection) { using (connection) { // Create a DataAdapter based on a SELECT query. OleDbDataAdapter adapter = new OleDbDataAdapter( "SELECT CategoryID, CategoryName FROM Categories", connection); // Create the INSERT command for the new category. adapter.InsertCommand = new OleDbCommand( "INSERT INTO Categories (CategoryName) Values(?)", connection); adapter.InsertCommand.CommandType = CommandType.Text; // Add the parameter for the CategoryName. adapter.InsertCommand.Parameters.Add( "@CategoryName", OleDbType.VarWChar, 15, "CategoryName"); adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both; // Create a DataTable DataTable categories = new DataTable(); // Create the CategoryID column and set its auto // incrementing properties to decrement from zero. DataColumn column = new DataColumn(); column.DataType = System.Type.GetType("System.Int32"); column.ColumnName = "CategoryID"; column.AutoIncrement = true; column.AutoIncrementSeed = 0; column.AutoIncrementStep = -1; categories.Columns.Add(column); // Create the CategoryName column. column = new DataColumn(); column.DataType = System.Type.GetType("System.String"); column.ColumnName = "CategoryName"; categories.Columns.Add(column); // Set the primary key on CategoryID. DataColumn[] pKey = new DataColumn[1]; pKey[0] = categories.Columns["CategoryID"]; categories.PrimaryKey = pKey; // Fetch the data and fill the DataTable adapter.Fill(categories);

// Add a new row. DataRow newRow = categories.NewRow(); newRow["CategoryName"] = "New Category"; categories.Rows.Add(newRow); // Add another new row. DataRow newRow2 = categories.NewRow(); newRow2["CategoryName"] = "Another New Category"; categories.Rows.Add(newRow2); // Add changed rows to a new DataTable that will be // used to post the inserts to the database. DataTable dataChanges = categories.GetChanges(); // Include an event to fill in the Autonumber value. adapter.RowUpdated += new OleDbRowUpdatedEventHandler(OnRowUpdated); // Update the database, inserting the new rows. adapter.Update(dataChanges); Console.WriteLine("Rows before merge:"); foreach (DataRow row in categories.Rows) { { Console.WriteLine(" {0}: {1}", row[0], row[1]); } } // Merge the two DataTables. categories.Merge(dataChanges); // Commit the changes. categories.AcceptChanges(); Console.WriteLine("Rows after merge:"); foreach (DataRow row in categories.Rows) { { Console.WriteLine(" {0}: {1}", row[0], row[1]); } } } }

El controlador de eventos RowUpdated utiliza el mismo OleDbConnection abierto que la instruccin Update de OleDbDataAdapter. Comprueba el StatementType deOleDbRowUpdatedEventArgs de las filas insertadas. Se crea un

nuevo OleDbCommand en cada nueva fila insertada para ejecutar la instruccin SELECT @@IDENTITY en la conexin, devolviendo el nuevo valor Autonumber, que est situado en la columna CategoryID de DataRow. La propiedad Status se establece luego enUpdateStatus.SkipCurrentRow para suprimir la llamada oculta a AcceptChanges. En el cuerpo principal del procedimiento, se llama al mtodo Merge para combinar los dos objetos DataTable y, finalmente, se llama a AcceptChanges. C# VB private static void OnRowUpdated( object sender, OleDbRowUpdatedEventArgs e) { // Conditionally execute this code block on inserts only. if (e.StatementType == StatementType.Insert) { OleDbCommand cmdNewID = new OleDbCommand("SELECT @@IDENTITY", connection); // Retrieve the Autonumber and store it in the CategoryID column. e.Row["CategoryID"] = (int)cmdNewID.ExecuteScalar(); e.Status = UpdateStatus.SkipCurrentRow; } }

Vea tambin
Conceptos
Estados de fila y versiones de fila AcceptChanges y RejectChanges Combinar contenido de DataSet Actualizar orgenes de datos con DataAdapters

Otros recursos
Recuperacin y modificacin de datos en ADO.NET DataAdapters y DataReaders Proveedores administrados de ADO.NET y centro de desarrolladores de DataSet

DENT_CURRENT (Transact-SQL)
SQL Server 2012 Otras versiones

Personas que lo han encontrado til: 2 de 2 - Valorar este tema Devuelve el ltimo valor de identidad generado para una tabla o vista especificadas. El ltimo valor de identidad generado puede ser para cualquier sesin y cualquier mbito. Convenciones de sintaxis de Transact-SQL

Sintaxis
IDENT_CURRENT( 'table_name' )

Argumentos
table_name Es el nombre de la tabla cuyo valor de identidad se devuelve. table_name es de tipo varchar y no tiene valor predeterminado.

Tipos de valor devueltos


numeric(38,0)

Excepciones
Devuelve NULL si se produce un error o si el autor de la llamada no tiene permiso para ver el objeto. En SQL Server, un usuario solo puede ver los metadatos de elementos protegibles que posea o para los que se le haya concedido permiso. Esto significa que las funciones integradas de emisin de metadatos, como IDENT_CURRENT, pueden devolver NULL si el usuario no tiene ningn permiso para el objeto. Para obtener ms informacin, vea Configuracin de visibilidad de los metadatos.

Comentarios
IDENT_CURRENT es similar a las funciones de identidad SCOPE_IDENTITY e @@IDENTITY de SQL Server 2000. Las tres funciones devuelven los ltimos valores de identidad generados. Pero la definicin de los ltimos valores de identidad difiere en el mbito y la sesin para cada una de estas funciones. IDENT_CURRENT devuelve el ltimo valor de identidad generado para una tabla especfica en cualquier sesin y cualquier mbito. @@IDENTITY devuelve el ltimo valor de identidad generado para cualquier tabla en la sesin actual, en todos los mbitos.

SCOPE_IDENTITY devuelve el ltimo valor de identidad generado para cualquier tabla en la sesin y el mbito actuales. Cuando el valor de IDENT_CURRENT es NULL (porque la tabla nunca ha contenido filas ni ha sido truncada), la funcin IDENT_CURRENT devuelve el valor de inicializacin. Las instrucciones y transacciones con errores pueden cambiar la identidad actual de una tabla y crear espacios en los valores de la columna de identidad. El valor de identidad jams se revierte, aun cuando no se haya confirmado la transaccin que intent insertar el valor en la tabla. Por ejemplo, si se produce un error en una instruccin INSERT debido a una infraccin de IGNORE_DUP_KEY, el valor de identidad actual de la tabla se sigue incrementando. Tenga cuidado al usar IDENT_CURRENT para predecir el siguiente valor de identidad generado. El valor generado real puede ser diferente de IDENT_CURRENT ms IDENT_INCR a causa de las inserciones realizadas por otras sesiones.

Ejemplos
A.Devolver el ltimo valor de identidad generado para una tabla especificada
En el ejemplo siguiente se devuelve el ltimo valor de identidad generado para la tabla Person.Address en la base de datos AdventureWorks2012. USE AdventureWorks2012; GO SELECT IDENT_CURRENT ('Person.Address') AS Current_Identity; GO

B.Comparar valores de identidad devueltos por IDENT_CURRENT, @@IDENTITY y SCOPE_IDENTITY


En el ejemplo siguiente se muestran los distintos valores de identidad devueltos por IDENT_CURRENT, @@IDENTITY y SCOPE_IDENTITY. USE AdventureWorks2012; GO IF OBJECT_ID(N't6', N'U') IS NOT NULL DROP TABLE t6; GO IF OBJECT_ID(N't7', N'U') IS NOT NULL DROP TABLE t7; GO CREATE TABLE t6(id int IDENTITY); CREATE TABLE t7(id int IDENTITY(100,1)); GO CREATE TRIGGER t6ins ON t6 FOR INSERT AS BEGIN INSERT t7 DEFAULT VALUES END; GO --End of trigger definition SELECT id FROM t6; --IDs empty.

SELECT id FROM t7; --ID is empty. --Do the following in Session 1 INSERT t6 DEFAULT VALUES; SELECT @@IDENTITY; /*Returns the value 100. This was inserted by the trigger.*/ SELECT SCOPE_IDENTITY(); /* Returns the value 1. This was inserted by the INSERT statement two statements before this query.*/ SELECT IDENT_CURRENT('t7'); /* Returns value inserted into t7, that is in the trigger.*/ SELECT IDENT_CURRENT('t6'); /* Returns value inserted into t6. This was the INSERT statement four statements before this query.*/ -- Do the following in Session 2. SELECT @@IDENTITY; /* Returns NULL because there has been no INSERT action up to this point in this session.*/ SELECT SCOPE_IDENTITY(); /* Returns NULL because there has been no INSERT action up to this point in this scope in this session.*/ SELECT IDENT_CURRENT('t7'); /* Returns the last value inserted into t7.*/

Vea tambin
Referencia
@@IDENTITY (Transact-SQL) SCOPE_IDENTITY (Transact-SQL) IDENT_INCR (Transact-SQL) IDENT_SEED (Transact-SQL) Expresiones (Transact-SQL) Funciones del sistema (Transact-SQL)

BASE DE DATOS, MYSQL, SQL SERVER

OBTENER EL ULTIMO ID DEL ULTIMO REGISTRO INSERTADO


ABRIL 1, 2013 MASTER 5 COMENTARIOS

En diversas ocasiones muchos de nuestros alumnos nos han preguntado, como obtener el id del ultimo registro insertado y si tu eres programador sabrs lo til que resulta obtener el ultimo valor del id para despus utilizarlo en alguna otra operacin y/o consulta. En esta ocasin nos enfocaremos a bases de datos MySQL y SQL Server. Para que las siguientes operaciones funcionen adecuadamente es necesario que el campo id sea indice (MySQL) o clave principal (SQL Server) y que sea auto-increment (autonumerico). Empezemos

@@identity Este es un metodo muy conocido, consiste en utilizar la sintaxis SELECT @@identity AS id y devuelve el id del ultimo ingreso, por ello se debe utilizar inmediatamente despus de usar la sentencia INSERT.
Ejemplo con PHP y MySQL

$query= mysql_query("SELECT @@identity AS id"); if ($row = mysql_fetch_row($query)) { $id = trim($row[0]); }

Ejemplo con Visual Basic y SQL Server

command.CommandText = "SELECT @@identity AS id" dt.TableName="nombre_de_la_tabla" dt.Load(command.ExecuteReader) id = dt.Rows(0).Item(0).ToString()

MAX(id) Otra forma es mediante la sentencia SELECT MAX(id) AS id FROM tabla. La ventaja de este mtodo con respecto al anterior es que no es necesario utilizarlo inmediatamente despues de utilizar la sentencia INSERT; ya que este mtodo busca el id de mayor valor dentro de la tabla y como es auto incrementable el mayor siempre sera el ultimo.
Ejemplo con PHP y MySQL

$query= mysql_query("SELECT MAX(id_tabla) AS id FROM tabla"); if ($row = mysql_fetch_row($query)) { $id = trim($row[0]); }

Ejemplo con Visual Basic y SQL Server

command.CommandText = "SELECT MAX(id_tabla) FROM tabla" dt.TableName="nombre_de_la_tabla"

dt.Load(command.ExecuteReader) id = dt.Rows(0).Item(0).ToString()

mysql_insert_id Este metodo funciona solo con PHP y MySQL: mysql_insert_id(). Al igual que la propiedad @@identity, solo retorna el id del ultimo registro ingresado independientemente de la tabla en la que se haya realizado la operacion.
$id=mysql_insert_id();
OBTENER EL ULTIMO IDOBTENER ULTIMO ID INSERTADOULTIMO IDULTIMO ID DE BASE MYSQLULTIMO ID DE BASE SQL SERVER

SCOPE_IDENTITY (Transact-SQL)
SQL Server 2012 Otras versiones

Personas que lo han encontrado til: 6 de 7 - Valorar este tema Devuelve el ltimo valor de identidad insertado en una columna de identidad en el mismo mbito. Un mbito es un mdulo: un procedimiento almacenado, desencadenador, funcin o lote. Por tanto, dos instrucciones estn en el mismo mbito si se encuentran en el mismo procedimiento almacenado, funcin o lote. Convenciones de sintaxis de Transact-SQL

Sintaxis
SCOPE_IDENTITY()

Tipos de valor devueltos


numeric(38,0)

Comentarios
SCOPE_IDENTITY, IDENT_CURRENT y @@IDENTITY son funciones parecidas ya que devuelven valores insertados en columnas de identidad. IDENT_CURRENT no est limitado por el mbito y la sesin; se limita a una tabla especificada. IDENT_CURRENT devuelve el valor generado para una tabla especfica en cualquier sesin y cualquier mbito. Para obtener ms informacin, vea IDENT_CURRENT (Transact-SQL). SCOPE_IDENTITY y @@IDENTITY devuelven los ltimos valores de identidad generados en una tabla en la sesin actual. No obstante, SCOPE_IDENTITY solo devuelve los valores insertados en el mbito actual; @@IDENTITY no se limita a un mbito especfico. Por ejemplo, suponga que hay dos tablas, T1 y T2, y un desencadenador INSERT definido en T1. Cuando se inserta una fila en T1, el desencadenador se activa e inserta una fila en T2. Este escenario muestra dos mbitos: la insercin en T1 y la insercin en T2 como resultado del desencadenador. Suponiendo que T1 y T2 tienen columnas de identidad, @@IDENTITY y SCOPE_IDENTITY devolvern distintos valores al finalizar una instruccin INSERT en T1. @@IDENTITY devolver el ltimo valor de la columna de identidad insertado en cualquier mbito en la sesin actual. En este caso, se trata del valor insertado en T2. SCOPE_IDENTITY() devolver el valor IDENTITY insertado en T1. Es la ltima insercin que se ha producido en el mismo mbito. La funcin SCOPE_IDENTITY() devolver el valor NULL si se llama a la funcin antes de que se ejecuten las instrucciones INSERT en una columna de identidad en el mbito. Las instrucciones y transacciones con errores pueden cambiar la identidad actual de una tabla y crear huecos en los valores de columna de identidad. El valor de identidad jams se revierte, aun cuando no se haya confirmado la transaccin que intent insertar el valor en la tabla. Por ejemplo, si

se produce un error en una instruccin INSERT debido a una infraccin de tipo IGNORE_DUP_KEY, el valor de identidad actual de la tabla se sigue incrementando.

Ejemplos
A.Usar @@IDENTITY y SCOPE_IDENTITY con desencadenadores
Este ejemplo crea dos tablas, TZ y TY, y un desencadenador INSERT en TZ. Cuando se inserta una fila en TZ, el desencadenador Ztrig se activa e inserta una fila en TY. USE tempdb GO CREATE TABLE TZ ( Z_id int IDENTITY(1,1)PRIMARY KEY, Z_name varchar(20) NOT NULL) INSERT TZ VALUES ('Lisa') INSERT TZ VALUES ('Mike') INSERT TZ VALUES ('Carla') SELECT * FROM TZ --Result set: This is how table TZ looks. Z_id Z_name ------------1 Lisa 2 Mike 3 Carla CREATE TABLE TY ( Y_id int IDENTITY(100,5)PRIMARY KEY, Y_name varchar(20) NULL) INSERT TY VALUES INSERT TY VALUES INSERT TY VALUES (Y_name) ('boathouse') (Y_name) ('rocks') (Y_name) ('elevator')

SELECT * FROM TY --Result set: This is how TY looks: Y_id Y_name --------------100 boathouse 105 rocks 110 elevator /*Create the trigger that inserts a row in table TY when a row is inserted in table TZ.*/

CREATE TRIGGER Ztrig ON TZ FOR INSERT AS BEGIN INSERT TY VALUES ('') END /*FIRE the trigger and determine what identity values you obtain with the @@IDENTITY and SCOPE_IDENTITY functions.*/ INSERT TZ VALUES ('Rosalie') SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY] GO SELECT @@IDENTITY AS [@@IDENTITY] GO El conjunto de resultados es el siguiente. SCOPE_IDENTITY 4 /*SCOPE_IDENTITY returned the last identity value in the same scope. This was the insert on table TZ.*/ @@IDENTITY 115 /*@@IDENTITY returned the last identity value inserted to TY by the trigger. This fired because of an earlier insert on TZ.*/

B.Usar @@IDENTITY y SCOPE_IDENTITY() con una replicacin

Los ejemplos siguientes muestran cmo se usan @@IDENTITY y SCOPE_IDENTITY() para las inserciones en una base de datos publicada para la replicacin de mezcla. Las dos tablas de los ejemplos se encuentran en la base de datos de ejemplo AdventureWorks2012 : Person.ContactType no est publicado y Sales.Customer s. La replicacin de mezcla agrega desencadenadores a las tablas publicadas. Por lo tanto, @@IDENTITY puede devolver el valor de la insercin en una tabla de sistema de replicacin en lugar de la insercin en una tabla de usuario. La tabla Person.ContactType tiene un valor de identidad mximo de 20. Si inserta una fila en la tabla, @@IDENTITY y SCOPE_IDENTITY() devolvern el mismo valor. USE AdventureWorks2012; GO INSERT INTO Person.ContactType ([Name]) VALUES ('Assistant to the Manager'); GO SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY]; GO SELECT @@IDENTITY AS [@@IDENTITY]; GO El conjunto de resultados es el siguiente. SCOPE_IDENTITY 21 @@IDENTITY 21

La tabla Sales.Customer tiene un valor de identidad mximo de 29483. Si inserta una fila en la tabla, @@IDENTITY y SCOPE_IDENTITY() devolvern valores diferentes.SCOPE_IDENTITY() devuelve el valor de la insercin en la tabla de usuario, mientras que @@IDENTITY devuelve el valor de la insercin en la tabla del sistema de replicacin.Use SCOPE_IDENTITY() para las aplicaciones que necesitan obtener acceso al valor de identidad insertado. INSERT INTO Sales.Customer ([TerritoryID],[PersonID]) VALUES (8,NULL); GO SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY]; GO SELECT @@IDENTITY AS [@@IDENTITY]; GO El conjunto de resultados es el siguiente. SCOPE_IDENTITY 29484 @@IDENTITY 89

Vea tambin
Referencia

@@IDENTITY (Transact-SQL)

Grimpi IT Blog
abril 3, 2008
Soluciones Para Actualizar Un Registro Si Existe, Sino Insertar En SQL Server.
Archivado en: SQL Server, T-SQL grimpi @ 2:06 am

3 Votes

Muchas veces cuando trabajamos con ABMs o algn proceso de escritura en la base de datos, al actualizar los registros, debemos establecer si vamos a efectuar un INSERT o un UPDATE. O sea, tenemos que determinar si el registro existe o no, para saber que operacin se va a efectuar en la base de datos. Generalmente se suele encapsular toda esta lgica dentro de un SP, algo que considero una muy buena practica, ya que nos desentendemos del lado de la aplicacin, si se va a efectuar una operacin de insercin o de modificacin. Primera solucin: Ahora bien, dentro del Store Procedure, lo solemos hacer para determinar la operacin, es el famoso IF EXISTS. Ejemplo: IF EXISTS(SELECT ID FROM TABLA WHERE ID = @ID) INSERT INTO TABLA (Campo1,ID) VALUES (@Valor,@ID) ELSE UPDATE TABLA SET Campo1 = @Valor WHERE ID = @ID No es un mal enfoque, es muy claro. Sin embargo esta solucin tiene dos inconvenientes: 1) Estamos pagando el costo de ejecutar un Query. Por mas que la consulta este indexada, tiene un costo. 2) No es 100% segura. En entornos muy demandantes, con alta concurrencia, puede darse el caso de que justo luego de ejecutar el IF EXISTS, otro proceso inserte en la tabla un registro con la misma PK y no tendramos forma de darnos cuenta, generando un error de duplicate key. Por lo tanto, esta opcin que es la ms comn, tiene serios inconvenientes.

Segunda solucin: Una segunda opcin podra ser esta: UPDATE TABLA SET Campo1 = @Valor WHERE ID = @ID IF @@ROWCOUNT = 0 INSERT INTO TABLA (Campo1,ID) VALUES (@Valor,@ID) En caso, se eliminara el tener que ejecutar una query con el EXISTS. Aunque en caso de que no exista el registro, se ejecuta el UPDATE innecesariamente. Si la mayora de las operaciones van a ser del tipo INSERT, en realidad no se ganara performance, pero por el contrario, si la mayora de las operaciones seria del tipo UPDATE, podra llegar a ser mas performante. De todas maneras esta solucin sigue teniendo el problema de que otro proceso podra insertar un registro con la misma PK en la tabla y no tendramos forma de darnos cuenta. Tercera solucin: En el segundo caso ganamos un poco de performance (no siempre), pero seguimos con el mismo problema de concurrencia. Pero ahora veamos este ejemplo de cdigo: BEGIN TRY INSERT INTO TABLA (Campo1,ID) VALUES (@Valor,@ID) END TRY BEGIN CATCH UPDATE TABLA SET Campo1 = @Valor WHERE ID = @ID END CATCH A nivel perfomance, es similar a las otras soluciones, pero si tenemos muchas ms operaciones de insercin que de actualizacin, vamos a ganar velocidad. Sin embargo, en este caso no tendramos el inconveniente de concurrencia que sucede en los 2 casos anteriores!!. Lo cual lo hace ideal para situaciones de alta demanda. Cuarta solucin (Solo en SQL Server 2008): SQL Server 2008, incorpora el comando MERGE (que ya tenamos en Oracle y otros motores), que sirve para resolver de una manera muy eficiente, exactamente este problema. MERGE TABLA USING (SELECT @ID AS ID) AS SRC ON SRC.ID = TABLA.ID WHEN MATCHED THEN UPDATE SET Campo1 = @Valor

WHEN NOT MATCHED THEN INSERT (Campo1,ID) VALUES (@Valor,@ID) Con este mtodo, tambin solucionamos el problema de concurrencia, y adems evitar tener que ejecutar consultas innecesarias. Por lo cual, podramos decir que es la optima solucin resolver este problema, aunque lamentablemente debemos esperar hasta mitad de ao, cuando Microsoft libere SQL Server 2008. Conclusin: Vimos como un problema en apariencia tonto y trivial, puede causar serios problemas de performance y peor aun, crear errores de concurrencia y comportamientos no deseados. Por las pruebas que hicimos en un entorno de TEST, la diferencia de performance que hicimos no son demasiadas. Pero en situaciones de alta concurrencia, las 2 primeras soluciones son definitivamente incorrectas. Recomiendo ver estos links, que explican como funcionan los lockeos, en cada una de las distintas soluciones: http://weblogs.sqlteam.com/mladenp/archive/2007/07/30/60273.aspx http://weblogs.sqlteam.com/mladenp/archive/2007/08/03/60277.aspx Y estas soluciones alternativas al mismo problema, tal vez sean un poco ms complejas, pero en algunos escenarios pueden ser tiles: http://www.samsaffron.com/blog/archive/2007/04/04/14.aspx http://www.sqlteam.com/article/application-locks-or-mutexes-in-sql-server-2005

Como verificar si existe un registro en una tabla de SQL?


hola a todos lo que quiero es lo siguiente tengo un programa en visual studio 2008 conectado a una base de datos SQL Server 2005 en uno de los form tengo que hacer una consulta para verificar si ese registro ya existe, si existe pues que me muestre un mensaje msgbox("el registro si existe") y si no existe pues que me muestre otro mensaje msgbox("el registro no existe") muchas Gracias...mostrar ms Respuesta

Mejor respuesta Seleccin de los votantes


BYTE q' te pusistes Triste respondido hace 3 aos Hola poon este codigo en tu boton y quieres que valide --------------------------------------... Dim Consulta As String = "SELECT CodCliente, NombCliente, Imagen FROM Clientes WHERE NombCliente='" & TextBox1.Text & "'" Con.Open() Dim Cadena As SqlDataAdapter = New SqlDataAdapter(Consulta, Con) Dim Dt As DataTable = New DataTable Cadena.Fill(Dt)

If Dt.Rows.Count > 0 Then MessageBox.Show("Ya Existe", "Informacin", MessageBoxButtons.OK, MessageBoxIcon.Information) Else MessageBox.Show("no Existe Existe", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error) End If --------------------------------------... pero esta parte adaptalo a tu medida Dim Consulta As String = "SELECT CodCliente, NombCliente, Imagen FROM Clientes WHERE NombCliente='" & TextBox1.Text & "'" donde Con es la conexion buena suerte saludos

Source: YooO Calificar Comentario

Otras respuestas (1)

respondido hace 3 aos Primero tienes tener tu consulta SQL con este formato: Select count (*) as total_registros from [nombre_tabla] Luego en tu visual pones algo asi: total_registros= rs.recordcount donde rs es el Resulset generado al llamar a tu consulta SQL

validar si un registro existe antes de ejecutar insert


Estas en el tema de validar si un registro existe antes de ejecutar insert en el foro de SQL Server en Foros del Web. Buenas. Tengo un procedimiento almacenado que inserta en una tabla. pero lo que

necesito es que antes de relizar dicha operacion, se valide si el ...


#1 (permalink) 03/07/2010, 16:32

papurri
validar si un registro existe antes de ejecutar insert

Fecha de Ingreso: agosto-2008 Ubicacin: Frente al pc Mensajes: 71 Antigedad: 5 aos, 7 meses Puntos: 2

Buenas. Tengo un procedimiento almacenado que inserta en una tabla. pero lo que necesito es que antes de relizar dicha operacion, se valide si el registro existe y justamente eso es lo que no se hacer, ya que mis conocimientos en t-sql son nulos. la clave primeria de mi tabla es un campo llamado rut, por lo que creo que debo consultar si existe un registros con una fila de datos que incluya ese rut. de todas formas dejo el condigo sql para ver si alguien me orienta en este tema saludos

ALTER procedure [dbo].[spInsertEjecutivo] ( @Nombres as varchar(50), @apellido_pat as varchar(50), @apellido_mat as varchar(50), @rut as varchar(50), @dv as int, @supervisor as varchar(100), @rut_supervisor as varchar(100), @plataforma as varchar(150), @user_ejecutivo as int )as if(@rut exist) Insert into ejecutivo ( nombres, apellido_pat, apellido_mat, rut, dv, supervisor, rut_supervisor,

plataforma, user_ejecutivo ) Values ( ltrim(rtrim(@Nombres)), ltrim(rtrim(@apellido_pat)), ltrim(rtrim(@apellido_mat)), ltrim(rtrim(@rut)), ltrim(rtrim(@dv)), ltrim(rtrim(@supervisor)), ltrim(rtrim(@rut_supervisor)), ltrim(rtrim(@plataforma)), ltrim(rtrim(@user_ejecutivo)) )
Avisos Google

#2 (permalink) 03/07/2010, 20:12

devilguzz
Respuesta: validar si un registro existe antes de ejecutar insert

Fecha de Ingreso: marzo-2004 Mensajes: 70 Antigedad: 10 aos Puntos: 0

eso lo puedes hacer en la parte logica de tu aplicacion, pero si no deseas que sea asi.. puedes agregar que RUT sea UNIQUE
Avisos Google

AqpHost
ofertas en Hosting y dominios para tus clientes y proyectos web aqphost.com
__________________ GuzZpaWn
#3 (permalink) 05/07/2010, 07:35

-rommel_
Respuesta: validar si un registro existe antes de ejecutar insert

Fecha de Ingreso: junio-2008 Ubicacin: Lima Mensajes: 361 Antigedad: 5 aos, 9 meses Puntos: 1

y si antes de ejecutar ese Procedimiento "[dbo].[spInsertEjecutivo]" haces una validacion Cdigo PSEUDOCODIGO:

Ver original

1. PROCEDURE [dbo].[Condiciones] 2. 3. SI Cumple todas las condiciones ENTONCES 4. 5. EJCECUTAR [dbo].[spInsertEjecutivo] 6. 7. SINO 8. 9. MENSAJE "Existen Condiciones que no se Cumplen" 10. 11. FIN SI

Algunos sistemas hacen eso... ejecutan un PA antes de insertar un registro... Saludos!!!


#4 (permalink) 05/07/2010, 16:37

iislas
Colaborador Respuesta: validar si un registro existe antes de ejecutar insert

Fecha de Ingreso: julio-2007 Ubicacin: Mexico, D.F. Mensajes: 5.921 Antigedad: 6 aos, 8 meses Puntos: 153

Con un simple IF EXISTS(TU SELECT)

lunes, 18 de febrero de 2008

Si existe: actualizar; si no: insertar


Comparto con ustedes un tip sobre BD que encontr aqui A menudo necesitamos actualizar un registro existente en una tabla o insertarlo en caso de no existir. La forma mas simple de hacerlo es: IF EXISTS(SELECT * FROM MiTabla WHERE MiLlave = 10) THEN UPDATE MiTabla SET MiCampo = 100 WHERE MiLlave = 10 ELSE INSERT INTO MiTabla (MiLlave, MiCampo) VALUES (10,100) Este script funciona, sin embargo no es la forma ms ptima de realizar esta operacin, pues el motor de la BD realiza dos bsquedas en la tabla. Una para el SELECT y otra para el Update. Una mejor forma de hacer esta operacin es: UPDATE MiTabla SET MiCampo = 100 WHERE MiLlave = 10 IF @@ROWCOUNT = 0 THEN INSERT INTO MiTabla (MiLlave, MiCampo) VALUES (10,100) Asi le ahorramos un poco de trabajo a nuestro servidor. Saludos
Posted by J. Marcos Troncoso a las 8:54 a. m. Labels: snippets, SQL Server

3 comentarios:

Annimo dijo...

Excelente inf

Gracias 7:22 p. m.

J. Marcos Troncoso dijo...

Gracias a t por visitar el blog y dejar tu comentario.

Saludos 8:35 a. m.

Annimo dijo...

todo bien pero en sql no me funciona a no ser que borre el "THEN", sin eso funciona perfecto. 11:17 a. m.

SQL: If Exists Update Else Insert


RATE THIS

Jeremiah.Clark 17 Feb 2008 10:30 PM

45
This is a pretty common situation that comes up when performing database operations. A stored procedure is called and the data needs to be updated if it already exists and inserted if it does not. If we refer to the Books Online documentation, it gives examples that are similar to: IF EXISTS (SELECT * FROM Table1 WHERE Column1='SomeValue') UPDATE Table1 SET (...) WHERE Column1='SomeValue' ELSE INSERT INTO Table1 VALUES (...) This approach does work, however it might not always be the best approach. This will do a table/index scan for both the SELECT statement and the UPDATE statement. In most standard approaches, the following statement will likely provide better performance. It will only perform one table/index scan instead of the two that are performed in the previous approach. UPDATE Table1 SET (...) WHERE Column1='SomeValue' IF @@ROWCOUNT=0 INSERT INTO Table1 VALUES (...) The saved table/index scan can increase performance quite a bit as the number of rows in the targeted table grows. Just remember, the examples in the MSDN documentation are usually the easiest way to implement something, not necessarily the best way. Also (as I re-learned recently), with any database operation, it is good to performance test the different approaches that you take. Sometimes the method that you think would be the worst might actually outperform the way that you think would be the better way.

Performance, SQL

Comments

17 Feb 2008 10:41 PM # PingBack from http://msdnrss.thecoderblogs.com/2008/02/17/sql-if-exists-update-else-insert/

jackhanbond 17 Feb 2008 11:31 PM # Thanks for the tip, I have a lot of code with the inferior approach that I will be updating. Fortunately, SQL 2008's Merge statement will make this a non-issue.

Jeremiah.Clark 18 Feb 2008 3:53 PM # Sent to me by Chris: "Since I don't have a blog and you don't allow anonymous comments I thought I'd shoot a quick email with a question/concern. Regarding your post "SQL: If Exists Update Else Insert" with the alternative method of doing the Update and then checking the @@ROWCOUNT as to whether to perform an insert or not... I definitely would not have thought of it that way either. However, I was wondering, with the scope of @@ROWCOUNT being global is there the possibility that the @@ROWCOUNT value could be incorrect within the local scope if there is heavy use on the database? Or am I incorrect on the scope being global? The reason I thought of this goes back to the use of SCOPE_IDENTITY() over @@IDENTITY to get the last identity in the same scope. Thanks for your time."

Jeremiah.Clark 18 Feb 2008 4:11 PM # I have enabled anonymous comments. I thought that I had done that before, but I guess not. Chris, Great question! The scope of @@ROWCOUNT (or ROWCOUNT_BIG() in the case of a VERY large result) is limited to the current scope that contains the statement that was previously executed. So you are guaranteed the correct result when using @@ROWCOUNT. Like you mentioned, this is not the case with @@IDENTITY. You can get some really unexpected results if it is used improperly. Jeremiah

Andrew Herron 21 Feb 2008 12:37 PM # Will this code work for any SQL compliant server?

Jeremiah.Clark 21 Feb 2008 2:19 PM # Andrew, The basic idea should work with other types of SQL servers (however, I have not verified this). You should just be able to use the @@ROWCOUNT equivalent for the system that you are using. For example: MySql uses "row_count()"

Oracle uses "sql%rowcount"

Guy 21 Feb 2008 2:26 PM # If you are thinking of MySQL there is a function called ROW_COUNT() that serves the same purpose (available as of version 5). Theoretically Jeremiah's suggestion should result in improved performance on MySQL also, but you should test it to make sure.

Richard Ayotte 21 Feb 2008 2:42 PM # MySQL does something much better. It's not part of the standard but still very useful. REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name,...)] VALUES ({expr | DEFAULT},...),(...),... It does what you describe. If the record exists, it is updated, else inserted. http://dev.mysql.com/doc/refman/5.0/en/replace.html

Jeremiah.Clark 21 Feb 2008 2:53 PM # Richard, Thanks for the comment. I was not aware of the REPLACE statement in MySQL.

Looking at the documentation, it does effectively do the same thing. But it seems to do it in a different manner. If a row with the same PK or UNIQUE index exists, it deletes the old row and then inserts the new row. For anything that does not already exist in the table, it inserts. I don't know if the deleting is more or less efficient than doing an update in MySQL. I would advise trying both ways and then compare the performance to see which solution better fits your needs.

Usar un procedimiento almacenado con un estado de devolucin


SQL Server 2012 Otras versiones

Este tema an no ha recibido ninguna valoracin - Valorar este tema Un procedimiento almacenado de SQL Server al que puede llamar es el que devuelve un parmetro de estado o resultado. Se usa normalmente para indicar el funcionamiento correcto o incorrecto del procedimiento almacenado. El Controlador JDBC de Microsoft para SQL Server proporciona la clase SQLServerCallableStatement, que puede usar para llamar a este tipo de procedimiento almacenado y procesar los datos que devuelve. Al llamar a este tipo de procedimiento almacenado mediante el controlador JDBC, debe usar la secuencia de escape call de SQL junto con el mtodo prepareCall de la claseSQLServerConnection. La sintaxis para la secuencia de escape call con un parmetro de estado de devolucin es la siguiente: {[?=]call procedure-name[([parameter][,[parameter]]...)]}

Nota

Para obtener ms informacin acerca de las secuencias de escape de SQL, consulte Usar secuencias de escap
Al crear la secuencia de escape call especifique el parmetro de estado de devolucin mediante el carcter ? (signo de interrogacin). Este carcter acta como un marcador de posicin para el valor del parmetro que devolver el procedimiento almacenado. Para especificar un valor para un parmetro de estado de devolucin, debe especificar el tipo de datos del parmetro mediante el mtodo registerOutParameter de la clase SQLServerCallableStatement antes de ejecutar el procedimiento almacenado.

Nota

Al usar el controlador JDBC con una base de datos de SQL Server, el valor especificado para el parmetro de mtodo registerOutParametersiempre es un entero, que se puede especificar mediante el tipo de datos java.

Adems, al pasar un valor al mtodo registerOutParameter para un parmetro de estado de devolucin, debe especificar no solo los tipos de datos usados para el parmetro, sino tambin la posicin ordinal del parmetro en la llamada al procedimiento almacenado. En el caso del parmetro de estado de devolucin, su posicin ordinal siempre es 1 debido a que es siempre el primer parmetro de la llamada al procedimiento almacenado. Aunque la clase SQLServerCallableStatement proporciona la compatibilidad para utilizar el nombre del parmetro para indicar el parmetro concreto, puede utilizar el nmero de la posicin ordinal de solo un parmetro para los parmetros de estado de retorno. Cree, a modo de ejemplo, el siguiente procedimiento almacenado en la base de datos de ejemplo AdventureWorks de SQL Server 2005: CREATE PROCEDURE CheckContactCity (@cityName CHAR(50)) AS BEGIN IF ((SELECT COUNT(*) FROM Person.Address WHERE City = @cityName) > 1) RETURN 1 ELSE RETURN 0 END Este procedimiento almacenado devuelve un valor de estado de 1 0 en funcin de si la ciudad especificada en el parmetro cityName se encuentra en la tabla Person.Address. En el siguiente ejemplo, se pasa una conexin abierta a la base de datos de ejemplo AdventureWorks a la funcin y se usa el mtodo execute para llamar al procedimiento almacenado CheckContactCity: Java public static void executeStoredProcedure(Connection con) { try { CallableStatement cstmt = con.prepareCall("{? = call dbo.CheckContactCity(?)}"); cstmt.registerOutParameter(1, java.sql.Types.INTEGER); cstmt.setString(2, "Atlanta"); cstmt.execute(); System.out.println("RETURN STATUS: " + cstmt.getInt(1)); cstmt.close(); } catch (Exception e) { e.printStackTrace(); } }

Vea tambi

Retornar dos resultados en Funcion o Procedimiento Almacenado


Foros de Acceso a Datos > SQL Server

Pregunta

0
Inicie sesin para votar

Hola comunidad!!! Estoy trabajando con SQLServer 2008 Express y me gustara saber si pudieran orientarme en base a lo que quiero hacer. Necesito crear un Stored Procedure que inserte un valor y devuelva dos (el ID del registro de la tabla (@@Identity) y un codigo armado. La estructura de mi tabla es la siguiente: Tabla: Venta, Campos: idVEnta int not null, cliente varchar(50) not null, fecha date null, secuencia int null, sigla nvarchar(15) not null No se como hacer esto, no se se utilizar una funcion y un procedimiento que llame a esta funcin, usar dos procedimientos aparte (uno para insertar el registro y el otro para armar la cadena de codigo, o no se si en un solo stored porcedure se puede hacer esto. Lo que necesito es que al insertar la app me guarde el ID del registro insertado pero a la vez me devuelva la cadena de cdigo armada. A continuacin las dos instrucciones individuales: Instruccin para insertar: Declare @Fecha Date=GetDate(); Insert Into Venta Select 'Cliente200820131', @Fecha, Count(1)+1 From Venta WhereFecha=@Fecha; RETURN @@IDENTITY INSTRUCCION PARA ARMAR EL CODIGO select siglas +'-'+ convert(char(8), getdate(), 112) + '-' + cast(secuencial as varchar(12)) as codigo from ventas Qu se puede hacer en este caso? Gracias de antemano Saludos.

Quien no conoce el pasado est condenado a repetirlo. Napolen Bonaparte


sbado, 31 de agosto de 2013 2:50 Responder | Citar |

Paoli_vb Independiente 70 Puntos

Respuestas

0
Inicie sesin para votar

Hola. Debes emplear parmetros de salida en un procedimiento almacenado. Deja el valor de retorno para gestionar estados de error del procedimiento. Si no sabes cmo, aqu tienes la referencia: http://technet.microsoft.com/es-es/library/ms187004(v=sql.105).aspx

Alberto Lpez Grande SQL Server MVP Visita mi blog en http://qwalgrande.com o Sgueme en twitter en http://twitter.com/qwalgrande Marcado como respuesta Alberto Lpez Grande (qwalgrande)MVP, Moderatorsbado, 14 de septiembre de
2013 18:43 sbado, 31 de agosto de 2013 8:25 Responder

| Citar |

Alberto Lpez Grande (qwalgrande) Plus Ultra Seguros (MVP) 58.370 Puntos

Todas las respuestas

0
Inicie sesin para votar

Hola: Lo tendrias que hacer un procedimiento almacenado es la mejor forma, para eso fijate este link http://technet.microsoft.com/es-es/library/ms345415.aspx Al momento de traer la info, usas un SELECT para tu variable y el identity, ahora el @@Identity no es recomendable usar si no el SCOPE_IDENTITY, ya que el primero es el valor de un campo de identidad de una ultima insercin en toda las sesiones, en cambio el segundo solo retorna el valor del proceso que abarca el comando, te dejo un link donde te explican. http://technet.microsoft.com/es-es/library/ms187342.aspx Espero te ayude. Saludos Lincoln VS
sbado, 31 de agosto de 2013 7:10 Responder | Citar

Lincoln_VS 382 Puntos

0
Inicie sesin para votar

Hola. Debes emplear parmetros de salida en un procedimiento almacenado. Deja el valor de retorno para gestionar estados de error del procedimiento. Si no sabes cmo, aqu tienes la referencia: http://technet.microsoft.com/es-es/library/ms187004(v=sql.105).aspx

Alberto Lpez Grande SQL Server MVP Visita mi blog en http://qwalgrande.com o Sgueme en twitter en http://twitter.com/qwalgrande Marcado como respuesta Alberto Lpez Grande (qwalgrande)MVP, Moderatorsbado, 14 de septiembre de
2013 18:43 sbado, 31 de agosto de 2013 8:25 Responder | Citar |

Alberto Lpez Grande (qwalgrande) Plus Ultra Seguros (MVP) 58.370 Puntos

0
Inicie sesin para votar

Una vez que sepas como declarar una variable de salida en el procemiento almacenado, una forma fcil de halar n cantidad de parmetros hacia tu aplicacin es usar la variable output como varchar y luego concatenas todos los valores que necesitas en esa nica variable (usas un separador que no te d problemas: un guin, la coma, punto y coma...cualquiera que desees) y luego, desde donde la quieras utilizar, la separas por substring (si la trabajars desde la misma base de datos) o con un mid (si usas .net) o su equivalente en cualquier otro lenguaje. Saludos

Editado Jos Rolando sbado, 31 de agosto de 2013 16:10 sbado, 31 de agosto de 2013 16:09 Responder | Citar |

Jos Rolando 50 Puntos

1
Inicie sesin para votar

Una vez que sepas como declarar una variable de salida en el procemiento almacenado, una forma fcil de halar n cantidad de parmetros hacia tu aplicacin es usar la variable output como varchar y luego concatenas todos los valores que necesitas en esa nica variable (usas un separador que no te d problemas: un guin, la coma, punto y coma...cualquiera que desees) y luego, desde donde la quieras utilizar, la separas por substring (si la trabajars desde la misma base de datos) o con un mid (si usas .net) o su equivalente en cualquier otro lenguaje.

Saludos

Esto es completamente inncesario, siendo que los procedimientos almacenados pueden tener mas de un parametro output sin problemas.

Blog
Obtener ID autonumerico insertado en SQL Server con ASP clasico
Recuperar la identidad de un registro recin insertado puede ser muy til si desea devolver el valor en el navegador o utilizarlo en una insercin o comando de actualizacin con el fin de crear o mantener una relacin entre dos o ms registros. Primero debe crear un Stored Procedure:

Ahora puede llamar al SP desde una pgina de ASP clsico:

<% set commInsert = Server.CreateObject("ADODB.Command") = = = = = strConnection "spInsertRecord" 4 0 true

commInsert.ActiveConnection commInsert.CommandText commInsert.CommandType commInsert.CommandTimeout commInsert.Prepared commInsert.Parameters.Append 3, commInsert.Parameters.Append 200,_ commInsert.Parameters.Append 1,4,"123") commInsert.Execute() %>

commInsert.CreateParameter("@RETURN_VALUE", 4,4) commInsert.CreateParameter("@Text", 1,20,"ABC") commInsert.CreateParameter("@Number", 3,

As es como se puede recuperar el identificador del nuevo registro:

<% intNewID = commInsert.Parameters.Item("@RETURN_VALUE").Value %>

Al programar en ASP clsico es recomendable usar Stored Procedures en SQL Server. Sin embargo, si no le es posible crear un SP entonces puede hacerse directamente desde ASP clsico:

<% strSQL = "SET NOCOUNT ON INSERT INTO tblName(TextField, NumberField)_ VALUES('ABC', 123) SELECT @@IDENTITY AS NewID SET NOCOUNT OFF"

strConnection Security User

"Provider=SQLOLEDB.1;Password=YourPassword;Persist Info=True;_

ID=YourUserID;

Initial

Catalog=YourDB;Data

Source=YOUR_REMOTE_SERVER_NAME"

Set

commInsert

Server.CreateObject("ADODB.Connection") strConnection

commInsert.Open Set intNewID commInsert.Close() rsNewID = =

commInsert.Execute(strSQL) rsNewID("NewID")

Set rsNewID.Close() Set %>

commInsert

Nothing

rsNewID

Nothing

El comando de insercin se ejecuta y la nueva identidad devuelta se almacena en la variable varNewID. Tenga en cuenta el SET NOCOUNT ON y OFF, a ambos lados del comando INSERT, esto es importante, el comando fallar sin ellos. Por Consultores en sistemas (07/08/2012 @ 14:24:14, en Programacion ASP clasico , 782 clicks.) Votar Comentar (0) Historico Imprimir

Tags: autonumerico en sql, server sql, sql server 2008, sql server 2005, sql base de datos, ejemplos base datos, sql server

Santiago Ezequiel Rueda Blog

Pgina Principal
VIERNES, 13 DE ENERO DE 2012

Transact SQL - Obtener ID de registro insertado (SQL Server)


Introduccin Generalmente necesitamos guardar un registro e inmediatamente insertar otros relacionados en otras tablas. Un ejemplo claro sera el de la facturacin, para el cual necesitamos por lo menos dos tablas: una para guardar la informacin de la factura y las partes implicadas, y otra para el detalle de la misma. Tal vez muchos se han encontrado con el problema de obtener el ID del registro recien insertado, para solucionar esto tenemos a nuestra disposicin una funcin llamada SCOPE_IDENTITY. (Para SQLServer CE investigar sobre @@IDENTITY).

Definicin SCOPE_IDENTITY() es una funcin capaz de devolver el valor de la columna de identidad (llave, index, etc) recien insertada.

Implementacin Para llevar a cabo la implementacin de esta funcin tomaremos como ejemplo un caso en el cul un registro se guarda en dos tablas: una tabla de Clientes y otra de Monitoreo de Actividad.

Estructura de Tablas Clientes Cli_Id (int) (identidad) (NO NULL) Cli_Nombre (nvarchar(60)) (NO NULL) Cli_Direccion (nvarchar(50))(NULL) Cli_Telefono (nvarchar(30))(NULL) Cli_Email (nvarchar(30))(NULL)

Monitor Mon_Id (int) (identidad) (NO NULL) Mon_IdRegistro (int) (NO NULL) Mon_NombreTabla (nvarchar(50))(NO NULL)

Code-behind C# 01.//Variable de Conexin 02.SqlConnection con = new SqlConnection("Data Source=USER\\SQLEXPRESS;Initial Catalog=basePrueba;Integrated Security=True"); 03.con.Open(); 04. 05.//Variable que contendr el valor de la columna de identidad devuelto por la funcin SCOPE_IDENTITY() 06.int idRegistro = 0; 07. 08.//Armo el Query para Clientes 09.//A la hora de declarar el query agrego la funcin SCOPE_IDENTITY() 10.SqlCommand cmd = new SqlCommand("INSERT INTO Clientes " + 11."(Cli_Nombre, Cli_Direccion, Cli_Telefono, Cli_Email) " + 12."VALUES" + 13."(@nombre, @direccion, @telefono, @email) " + 14."SELECT SCOPE_IDENTITY()", con); 15. 16.cmd.Parameters.Add("@nombre", SqlDbType.NVarChar).Value = txtNombre.Text; 17.cmd.Parameters.Add("@direccion", SqlDbType.NVarChar).Value = txtDireccion.Text; 18.cmd.Parameters.Add("@telefono", SqlDbType.NVarChar).Value = txtTelefono.Text; 19.cmd.Parameters.Add("@email", SqlDbType.NVarChar).Value = txtEmail.Text; 20. 21.//Ejecuto la consulta y obtengo el valor devuelto por la misma 22.idRegistro = Convert.ToInt32(cmd.ExecuteScalar()); 23. 24.//Armo Query para el Monitor de Actividades 25.//En la consulta paso un parmetro con el valor obtenido de la consulta anterior

26.cmd.CommandText = "INSERT INTO Monitor " + 27."(Mon_IdRegistro, Mon_NombreTabla) " + 28."VALUES" + 29."(@idRegistro, @nombreTabla)"; 30. 31.cmd.Parameters.Add("@idRegistro", SqlDbType.Int).Value = idRegistro; 32.cmd.Parameters.Add("@nombreTabla", SqlDbType.NVarChar).Value = "Clientes"; 33. 34.con.Close();

VB.NET 01.'Variable de Conexin 02.Dim con As New SqlClient.SqlConnection("Data Source=USER\\SQLEXPRESS;Initial Catalog=basePrueba;Integrated Security=True") 03.con.Open() 04. 05.'Variable que contendr el valor de la columna de identidad devuelto por la funcin SCOPE_IDENTITY() 06.Dim idRegistro As Integer = 0 07. 08.'Armo el Query para Clientes 09.'A la hora de declarar el query agrego la funcin SCOPE_IDENTITY() 10.Dim cmd As New SqlClient.SqlCommand("INSERT INTO Clientes " _ 11.& "(Cli_Nombre, Cli_Direccion, Cli_Telefono, Cli_Email) " _ 12.& "VALUES" _ 13.& "(@nombre, @direccion, @telefono, @email) " _ 14.& "SELECT SCOPE_IDENTITY()", con) 15. 16.cmd.Parameters.Add("@nombre", SqlDbType.NVarChar).Value = txtNombre.Text

17.cmd.Parameters.Add("@direccion", SqlDbType.NVarChar).Value = txtDireccion.Text 18.cmd.Parameters.Add("@telefono", SqlDbType.NVarChar).Value = txtTelefono.Text 19.cmd.Parameters.Add("@email", SqlDbType.NVarChar).Value = txtEmail.Text 20. 21.'Ejecuto la consulta y obtengo el valor devuelto por la misma 22.idRegistro = Convert.ToInt32(cmd.ExecuteScalar()) 23. 24.'Armo Query para el Monitor de Actividades 25.'En la consulta paso un parmetro con el valor obtenido de la consulta anterior 26.cmd.CommandText = "INSERT INTO Monitor " _ 27.& "(Mon_IdRegistro, Mon_NombreTabla) " _ 28.& "VALUES" _ 29.& "(@idRegistro, @nombreTabla)" 30. 31.cmd.Parameters.Add("@idRegistro", SqlDbType.Int).Value = idRegistro 32.cmd.Parameters.Add("@nombreTabla", SqlDbType.NVarChar).Value = "Clientes" 33. 34.con.Close()

Seudocdigo 1. Declaro variable de conexin y le asigno un Connection String 2. Abro la Conexin 3. Declaro la variable 'idRegistro' que contendr el valor de la columna de identidad del registro recin insertado 4. Declaro variable Command y le asigno un CommandText --CommandText: Insertar en Clientes: en los campos (campos) los valores (valores) y seleccionar el valor del campo de identidad 5. Agrego los parmetros necesarios 6. Ejecuto la consulta y obtengo el valor solicitado 7. Asigno CommandText --CommandtText: Insertar en Monitor: en los campos (campos) los valores (valores) 8. Agrego parmetros necesarios --Parametro 'idRegistro': lo igualo al valor obtenido en la consulta anterior. 9. Ejecuto el query 10. Cierro la conexin

Publicadas por Santiago Ezequiel Rueda a la/s 2:08 Enviar esto por correo electrnicoBlogThis!Compartir en TwitterCompartir en FacebookCompartir en Pinterest Etiquetas: SQL Server, Transact-SQL

12 comentarios:
1. Fajgri Isa Espinoza19 de enero de 2012, 2:43 y como lo gurdo en la otra tabla Responder Respuestas

1.
Santiago Ezequiel Rueda19 de enero de 2012, 12:17 Buenos das Isa. Como vers el valor de la columna de identidad de guarda en la variable "idRegistro". Seguidamente utilizamos el valor de esta variable para insertar el registro en la otra tabla, como lo muestra el ejemplo. Primero se inserta un registro en la tabla de Clientes y se obtiene el ID del mismo, luego se inserta un registro en la tabla de Monitor de Actividades. Saludos. Responder

% (Mdulo) (SQL Server Compact)


Otras versiones

Personas que lo han encontrado til: 4 de 5 - Valorar este tema Proporciona el resto de un nmero dividido entre otro.

Sintaxis
dividend % divisor

Argumentos
dividend
La expresin numrica que se va a dividir. El valor de dividend puede ser cualquier expresin vlida de MicrosoftSQL Server Compact perteneciente a la categora de tipos de datos enteros.

divisor
La expresin numrica entre la que se va a dividir el dividendo. El valor de divisorpuede ser cualquier expresin vlida de SQL Server perteneciente a cualquier tipo de datos de la categora de tipos de datos enteros.

Tipos de resultado
int

Ejemplo de cdigo
En el ejemplo siguiente se utiliza la instruccin modulo para identificar a aquellos empleados cuyos valores de EmployeeID son nmeros pares. SELECT EmployeeID, LastName, EmployeeID % 2 FROM Employees WHERE EmployeeID % 2 = '0' ste es el conjunto de resultados: EmployeeID LastName #2 ------------------2 Funk 0 4 Pearson 0 6 Sutton 0 8 Calafato 0

Obtener columnas del registro q tiene el campo con valor mximo. max()
Foros de Acceso a Datos > SQL Server

Pregunta

0
Inicie sesin para votar

Hola amigos, tengo la siguiente inquietud: Es posible usando el estandar de sql o con transact SQL, obtener las dems columnas de un registro que cumple la condicin max() y group by, sin utilizar joins Actualmente estoy desarrollado la siguiente consulta y quiero saber si puedo optimizarla sin necesidad de usar Join:

Cdigo : SELECT T.nombreID, T.cualidad, maxPer.maxPeriodo FROM T INNER JOIN ( select nombreID, max(periodo) as maxPeriodo from T where estado =1 group by nombreID ) as maxPer ON maxPer.maxPeriodo = T.periodo and maxPer.nombreID= T.nombreID En este momento estoy desarrollando en SQLServer 2005. o Agradezco sus ideas y comentarios. Editado charJ lunes, 31 de enero de 2011 15:47
lunes, 31 de enero de 2011 15:15 Responder | Citar

charJ 0 Puntos

Respuestas

0
Inicie sesin para votar

Por ejemplo:

;WITH cte AS (SELECT nombreId, cualidad, periodo, ROW_NUMBER OVER (PARTITION BY nombreID ORDER BY periodo DESC) AS rn FROM T WHERE estado = 1) SELECT nombreId, cualidad, periodo FROM cte WHERE rn = 1

Pero revisa el plan de ejecucin de ambas consultas para ver cul es efectivamente ms eficiente o o o o o o
Propuesto como respuesta Carlos Sacristan lunes, 31 de enero de 2011 15:27 Votado como til charJ lunes, 31 de enero de 2011 15:39 Propuesto como respuesta Willy TaverasModerator lunes, 31 de enero de 2011 16:30 Votado como til charJ lunes, 31 de enero de 2011 16:40 Propuesto como respuesta HunchbackMVP lunes, 31 de enero de 2011 20:13 Marcado como respuesta Alberto Lpez Grande (qwalgrande)MVP, Moderatorlunes, 31 de enero de 2011 20:43 lunes, 31 de enero de 2011 15:26 Responder | Citar |

Carlos Sacristan

Kabel (Partner) 28.425 Puntos

Todas las respuestas

0
Inicie sesin para votar

Por ejemplo:

;WITH cte AS (SELECT nombreId, cualidad, periodo, ROW_NUMBER OVER (PARTITION BY nombreID ORDER BY periodo DESC) AS rn FROM T WHERE estado = 1) SELECT nombreId, cualidad, periodo FROM cte WHERE rn = 1

Pero revisa el plan de ejecucin de ambas consultas para ver cul es efectivamente ms eficiente o o o o o o
Propuesto como respuesta Carlos Sacristan lunes, 31 de enero de 2011 15:27 Votado como til charJ lunes, 31 de enero de 2011 15:39 Propuesto como respuesta Willy TaverasModerator lunes, 31 de enero de 2011 16:30 Votado como til charJ lunes, 31 de enero de 2011 16:40 Propuesto como respuesta HunchbackMVP lunes, 31 de enero de 2011 20:13 Marcado como respuesta Alberto Lpez Grande (qwalgrande)MVP, Moderatorlunes, 31 de enero de 2011 20:43 lunes, 31 de enero de 2011 15:26 Responder | Citar |

Carlos Sacristan Kabel

(Partner) 28.425 Puntos

0
Inicie sesin para votar

Gracias. Pero en la consulta que expones supones todos los registros como si fueran un solo grupo y tomas el primero. La idea es traer las columnas del registro mximo agrupado por el campo nombreID.
lunes, 31 de enero de 2011 15:33 Responder | Citar |

charJ 0 Puntos

0
Inicie sesin para votar

No entiendo tu comentario. Has comprobado que los resultados son diferentes entre tu query y la que propuse yo?
lunes, 31 de enero de 2011 16:28 Responder | Citar |

Carlos Sacristan Kabel (Partner) 28.425 Puntos

0
Inicie sesin para votar

Se tiene la siguiente tabla: Tabla T:

nombreID estado cualidad periodo n1 n1 n1 n2 n2 n3 n3 1 1 2 1 1 1 1 a b a d e d a 1 2 3 2 3 1 2

Se debe obtener el mximo <periodo> para cada <nombreID> en donde el estado sea igual a 1. Y del periodo obtenido para cada nombreId se debe obtener la <cualidad>; de tal forma que el resultado obtenido ser:

nombreID cualidad maxPeriodo n1 n2 n3 b e a 2 3 2

La consulta empleada y que se quiere optimizar para no utilizar 'join' es la siguiente:

SELECT T.nombreID, T.cualidad, maxPer.maxPeriodo FROM T

INNER JOIN ( select nombreID, max(periodo) as maxPeriodo from T where estado =1 group by nombreID ) as maxPer ON maxPer.maxPeriodo = T.periodo and maxPer.nombreID= T.nombreID

lunes, 31 de enero de 2011 16:57 Responder | Citar |

charJ 0 Puntos

0
Inicie sesin para votar

Hola. Coincido con Carlos, la consulta que l ha expuesto es tal t la has especificado. Si hay algn error (salvo quiz ponerle los "()" tras ROW_NUMBER), a m tambin se me escapa. Otra cosa es que sea mejor que la que ya tienes, que tengo mis dudas. Para eso, nada como evaluar las lecturas lgicas que hace cada una. Qu nmero de lecturas lgicas se obtienen en cada caso? Para mostrar las lecturas lgicas, ejecuta "set statistics io on", luego lanza cada consulta. Djanos saber qu se retorna en cada caso.

Alberto Lpez Grande SQL Server MVP Visita mi blog en http://qwalgrande.blogspot.es/


lunes, 31 de enero de 2011 19:41

Responder | Citar |

Alberto Lpez Grande (qwalgrande) Plus Ultra Seguros (MVP) 58.370 Puntos

0
Inicie sesin para votar

Hola. Muchas gracias a todos por su tiempo y las respuestas. Realizando la prueba sobre la tabla de datos T expuesta anteriormente, se obtuvieron las siguientes lecturas para cada consulta:

1. SELECT T.nombreID, T.cualidad, maxPer.maxPeriodo FROM T INNER JOIN ( select nombreID, max(periodo) as maxPeriodo from T where estado =1 group by nombreID ) as maxPer ON maxPer.maxPeriodo = T.periodo and maxPer.nombreID= T.nombreID

LECTURAS OBTENIDAS: (3 filas afectadas)

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'T'. Scan count 2, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

2. ;WITH cte AS (SELECT nombreId, cualidad, periodo, ROW_NUMBER () OVER (PARTITION BY nombreID ORDER BY periodo DESC) AS rn FROM T WHERE estado = 1) SELECT nombreId, cualidad, periodo FROM cte WHERE rn = 1 LECTURAS OBTENIDAS (3 filas afectadas) Table 'T'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Al parecer es mas eficiente la segunda opcin. Muchas gracias.

lunes, 31 de enero de 2011 20:40 Responder | Citar |

charJ 0 Puntos

Inicie sesin para votar

Hola. Ojo, si la tabla tiene 3 registros (o 3.000), la opcin de estas opciones de agregado es muy til. Pero si tienes millones, la cosa puede cambiar.

Alberto Lpez Grande SQL Server MVP Visita mi blog en http://qwalgrande.blogspot.es/

RETURN (Transact-SQL)
SQL Server 2012 Otras versiones

Personas que lo han encontrado til: 2 de 3 - Valorar este tema Sale incondicionalmente de una consulta o procedimiento. RETURN es inmediata y completa, y se puede utilizar en cualquier punto para salir de un procedimiento, lote o bloque de instrucciones. Las instrucciones que siguen a RETURN no se ejecutan. Convenciones de sintaxis de Transact-SQL

Sintaxis
RETURN [ integer_expression ]

Argumentos
integer_expression Es el valor entero que se devuelve. Los procedimientos almacenados pueden devolver un valor entero al procedimiento que realiza la llamada o a una aplicacin.

Tipos de valor devueltos


Opcionalmente devuelve int.

Nota

A menos que se documente de otra manera, todos los procedimientos almacenados del sistema devuelven el v valor distinto de cero indica que se ha producido un error.

Comentarios
Cuando se utiliza con un procedimiento almacenado, RETURN no puede devolver un valor NULL. Si un procedimiento intenta devolver un valor NULL (por ejemplo, al utilizar RETURN @status cuando @status es NULL), se genera un mensaje de advertencia y se devuelve un valor 0. El valor de estado devuelto se puede incluir en las siguientes instrucciones Transact-SQL del lote o procedimiento que ha ejecutado el procedimiento actual, pero se debe escribir de la forma siguiente: EXECUTE @return_status = <procedure_name>.

Ejemplos

A.Devolver desde un procedimiento


En el siguiente ejemplo se muestra que si no se proporciona ningn nombre de usuario como parmetro al ejecutar findjobs, RETURN provoca la salida del procedimiento tras enviar un mensaje a la pantalla del usuario. Si se especifica un nombre de usuario, se obtienen de las tablas del sistema adecuadas los nombres de todos los objetos creados por este usuario en la base de datos actual. CREATE PROCEDURE findjobs @nm sysname = NULL AS IF @nm IS NULL BEGIN PRINT 'You must give a user name' RETURN END ELSE BEGIN SELECT o.name, o.id, o.uid FROM sysobjects o INNER JOIN master..syslogins l ON o.uid = l.sid WHERE l.name = @nm END;

B.Devolver cdigos de estado


En el siguiente ejemplo se comprueba el estado del Id. de un contacto especificado. Si el estado es Washington (WA), se devuelve un estado de 1. En caso contrario, se devuelve 2 para cualquier otra condicin (un valor distinto de WA para StateProvince o ContactID que no coincida con una fila). USE AdventureWorks2012; GO CREATE PROCEDURE checkstate @param varchar(11) AS IF (SELECT StateProvince FROM Person.vAdditionalContactInfo WHERE ContactID = @param) = 'WA' RETURN 1 ELSE RETURN 2; GO En los siguientes ejemplos se muestra el estado devuelto al ejecutar checkstate. En el primer ejemplo se muestra un contacto en Washington, en el segundo ejemplo un contacto distinto de Washington y en el tercer ejemplo un contacto no vlido. Se debe declarar la variable local @return_status para poder utilizarla. DECLARE @return_status int; EXEC @return_status = checkstate '2'; SELECT 'Return Status' = @return_status; GO El conjunto de resultados es el siguiente. Return Status ------------1 Ejecute la consulta de nuevo con un nmero de contacto diferente. DECLARE @return_status int; EXEC @return_status = checkstate '6';

SELECT 'Return Status' = @return_status; GO El conjunto de resultados es el siguiente. Return Status ------------2 Ejecute la consulta de nuevo con otro nmero de contacto. DECLARE @return_status int EXEC @return_status = checkstate '12345678901'; SELECT 'Return Status' = @return_status; GO El conjunto de resultados es el siguiente. Return Status ------------2

Vea tambin
Referencia

ALTER PROCEDURE (Transact-SQL) CREATE PROCEDURE (Transact-SQL) DECLARE @local_variable (Transact-SQL) EXECUTE (Transact-SQL) SET @local_variable (Transact-SQL)
Te ha resultado til? S No

Adiciones de comunidad
AGREGAR

2014 Microsoft Administre su perfil


Boletn | Contacte con nosotros | Privacidad y Cookies | Condiciones de Uso

| Marcas registrada |

Comentario del sitio

SQL: Cmo obtener la primera y la ltima fila de los registros de una consulta

En el mundo de la programacin y el desarrollo de aplicaciones, a veces nos pasa que queremos hacer algo muy sencillo pero no recordamos cmo hacerlo. Pues bien, a m me ha pasado algo parecido, as que os lo voy a comentar con un breve ejemplo por si a alguien ms le pasa, espero que os sirva de ayuda.

A continuacin os indico las sentencias SQL generadas para obtener la primera y ltima fila de una tabla, probados con SQL Server. Para el ejemplo he generado una pequea tabla de Pedidoscon los campos: ID del pedido Descripcin del pedido Fecha del pedido Cliente Direccin de entrega de dicho pedido.

Paso 1: Identificar el criterio de ordenacin de la consulta para saber qu datos


queremos coger exctamente. En este caso realizaremos el ejemplo ordenando los pedidos por fecha, cogiendo as el primer y el ltimo pedido de todos los realizados. SELECT * FROM Pedido ORDER BY Fecha

Paso 2: Obtenemos el primer y el ltimo registro de la consulta


Obtenemos el primer y el ltimo registro. Utilizando la palabra reservada TOP podemos especificar el nmero de registros que queremos obtener, por lo tanto, realizaremos dos sentencias obteniendo slo el primer valor. Las dos sentencias solo se diferenciarn en el criterio de ordenacin, de modo que en una sentencia obtengamos el primer registro y en la siguiente el ltimo.

Primer registro: Utilizamos ordenacin Ascendente (ASC). SELECT TOP 1 * FROM Pedido ORDER BY Fecha ASC ltimo registro: Utilizamos ordenacion Descencente (DESC), para obtener los resultados en orden inverso. SELECT TOP 1 * FROM Pedido ORDER BY Fecha DESC

Paso 3: Unimos los dos registros devueltos en una nica consulta


Para unir las dos consultas en una ncia sentencias utilizaremos UNION: ( SELECT TOP 1 * FROM Pedido ORDER BY Fecha ASC ) UNION ( SELECT TOP 1 * FROM Pedido ORDER BY Fecha DESC ) Si ejecutamos esta sentencia en SQL Server nos dara el siguiente error: Incorrect syntax near the keyword 'ORDER'. Esto se debe a que los UNION no permiten utilizar un ORDER BY en sus consultas, para ello debemos "camuflar" ese ORDER BY en una subconsulta de manera que pueda ejecutarse sin ningn problema

SELECT ( SELECT TOP 1 * FROM Pedido ORDER BY Fecha ASC

) UNION SELECT (

SELECT TOP 1 * FROM Pedido ORDER BY Fecha DESC ) El resultado sera el siguiente:

Quizs tambin le interese:

Anda mungkin juga menyukai