Equivalente del RowID de Oracle en SQL Server

82

¿Cuál es el equivalente de RowID de Oracle en SQL Server?

John Saunders
fuente
Stephanie: la suposición es que hay una clave única en los datos, lo que supone que los datos están normalizados, lo que a veces es una suposición incorrecta. Por lo tanto, ¿cuál es el equivalente al RowID de Oracle en el servidor SQL?
Christopher Mahan

Respuestas:

115

De los documentos de Oracle

Pseudocolumna ROWID

Para cada fila de la base de datos, la pseudocolumna ROWID devuelve la dirección de la fila. Los valores de rowid de la base de datos Oracle contienen la información necesaria para ubicar una fila:

  • El número de objeto de datos del objeto.
  • El bloque de datos en el archivo de datos en el que reside la fila
  • La posición de la fila en el bloque de datos (la primera fila es 0)
  • El archivo de datos en el que reside la fila (el primer archivo es 1). El número de archivo es relativo al espacio de tabla.

El equivalente más cercano a esto en SQL Server es el ridque tiene tres componentes File:Page:Slot.

En SQL Server 2008 es posible utilizar la %%physloc%%columna virtual no documentada y no compatible para ver esto. Esto devuelve un binary(8)valor con el ID de página en los primeros cuatro bytes, luego 2 bytes para el ID de archivo, seguido de 2 bytes para la ubicación de la ranura en la página.

La función escalar sys.fn_PhysLocFormattero sys.fn_PhysLocCrackerTVF se puede utilizar para convertir esto en una forma más legible

CREATE TABLE T(X INT);

INSERT INTO T VALUES(1),(2)

SELECT %%physloc%% AS [%%physloc%%],
       sys.fn_PhysLocFormatter(%%physloc%%) AS [File:Page:Slot]
FROM T

Salida de ejemplo

+--------------------+----------------+
|    %%physloc%%     | File:Page:Slot |
+--------------------+----------------+
| 0x2926020001000000 | (1:140841:0)   |
| 0x2926020001000100 | (1:140841:1)   |
+--------------------+----------------+

Tenga en cuenta que esto no es aprovechado por el procesador de consultas. Si bien es posible usar esto en una WHEREcláusula

SELECT *
FROM T
WHERE %%physloc%% = 0x2926020001000100 

SQL Server no buscará directamente la fila especificada. En su lugar, hará un escaneo completo de la tabla, evaluará %%physloc%%cada fila y devolverá la que coincida (si alguna lo hace).

Para revertir el proceso llevado a cabo por las 2 funciones mencionadas anteriormente y obtener el binary(8)valor correspondiente a los valores conocidos de Archivo, Página, Slot, se puede utilizar el siguiente.

DECLARE @FileId int = 1,
        @PageId int = 338,
        @Slot   int = 3

SELECT CAST(REVERSE(CAST(@PageId AS BINARY(4))) AS BINARY(4)) +
       CAST(REVERSE(CAST(@FileId AS BINARY(2))) AS BINARY(2)) +
       CAST(REVERSE(CAST(@Slot   AS BINARY(2))) AS BINARY(2))
Martin Smith
fuente
En SQL Server 2005, puede usar las columnas virtuales no documentadas y no admitidas %% LockRes %% en su lugar
Henrik Holmgaard Høyer
absolutamente correcto. %% LockRes %% no es la "forma correcta" - utilícelo solo si se trata de arreglos rápidos y sucios de datos en versiones antiguas de servidores SQL anteriores a 2008
Henrik Holmgaard Høyer
11

Tengo que deducir una tabla muy grande con muchas columnas y la velocidad es importante. Por lo tanto, uso este método que funciona para cualquier tabla:

delete T from 
(select Row_Number() Over(Partition By BINARY_CHECKSUM(*) order by %%physloc%% ) As RowNumber, * From MyTable) T
Where T.RowNumber > 1
S Wright
fuente
9

Consulte la nueva función ROW_NUMBER . Funciona así:

SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE
Daren Thomas
fuente
14
Creo que este es un reemplazo de rownum y no rowid.
Tuinstoel
9

Si desea identificar de manera única una fila dentro de la tabla en lugar de su conjunto de resultados, entonces debe usar algo como una columna IDENTIDAD. Consulte "Propiedad IDENTITY" en la ayuda de SQL Server. SQL Server no genera automáticamente una ID para cada fila de la tabla como lo hace Oracle, por lo que debe tomarse la molestia de crear su propia columna de ID y buscarla explícitamente en su consulta.

EDITAR: para la numeración dinámica de las filas del conjunto de resultados, vea a continuación, pero eso probablemente sería un equivalente para ROWNUM de Oracle y supongo que, por todos los comentarios en la página, desea lo anterior. Para SQL Server 2005 y versiones posteriores, puede utilizar la nueva función de funciones de clasificación para lograr la numeración dinámica de filas.

Por ejemplo, hago esto en una consulta mía:

select row_number() over (order by rn_execution_date asc) as 'Row Number', rn_execution_date as 'Execution Date', count(*) as 'Count'
from td.run
where rn_execution_date >= '2009-05-19'
group by rn_execution_date
order by rn_execution_date asc

Te regalaré:

Row Number  Execution Date           Count
----------  -----------------        -----
1          2009-05-19 00:00:00.000  280
2          2009-05-20 00:00:00.000  269
3          2009-05-21 00:00:00.000  279

También hay un artículo en support.microsoft.com sobre la numeración dinámica de filas.

Xiaofu
fuente
Creo que una columna de identidad identifica de forma única una fila en una tabla pero no en una base de datos.
Tuinstoel
Esto es cierto, pero se ajusta a la definición de ROWID que veo en los documentos de Oracle: "El tipo de datos externo ROWID identifica una fila en particular en una tabla de base de datos" ... pero veo que está diciendo esto debido a mi error tipográfico en el parte superior. :) Gracias por señalar eso.
Xiaofu
Un "número" de fila no es un ROWID. El ROWID contiene la ubicación física de la fila, es algo diferente a un número único. Especialmente es único en todas las tablas de la base de datos (con algunas excepciones cuando se utilizan técnicas de almacenamiento especiales)
a_horse_with_no_name
6

Varias de las respuestas anteriores se trabajará en torno a la falta de una referencia directa a una fila específica, pero no funcionará si se producen cambios en las otras filas en una tabla. Ese es mi criterio para el que las respuestas son técnicamente cortas.

Un uso común de ROWID de Oracle es proporcionar un método (algo) estable para seleccionar filas y luego regresar a la fila para procesarla (por ejemplo, para ACTUALIZARla). Es posible que el método para encontrar una fila (combinaciones complejas, búsqueda de texto completo o examinar fila por fila y aplicar pruebas de procedimiento contra los datos) no se pueda reutilizar de manera fácil o segura para calificar la instrucción UPDATE.

El RID de SQL Server parece ofrecer la misma funcionalidad, pero no el mismo rendimiento. Ese es el único problema que veo, y desafortunadamente el propósito de retener un ROWID es evitar repetir una operación costosa para encontrar la fila en, digamos, una tabla muy grande. No obstante, el rendimiento en muchos casos es aceptable. Si Microsoft ajusta el optimizador en una versión futura, el problema de rendimiento podría solucionarse.

También es posible simplemente usar FOR UPDATE y mantener el CURSOR abierto en un programa de procedimiento. Sin embargo, esto podría resultar caro en el procesamiento por lotes grandes o complejos.

Advertencia: incluso el ROWID de Oracle no sería estable si el DBA, entre SELECT y UPDATE, por ejemplo, reconstruyera la base de datos, porque es el identificador de fila física. Por lo tanto, el dispositivo ROWID solo debe usarse dentro de una tarea bien definida.

Vincent
fuente
3

si solo desea una numeración básica de filas para un conjunto de datos pequeño, ¿qué tal algo como esto?

SELECT row_number() OVER (order by getdate()) as ROWID, * FROM Employees
Adriano Carneiro
fuente
8
No lo que es un alboroto.
Stephanie Page
Pero funciona para una identificación agregada rápida que algunos espectadores buscarán, sin saber qué es ROWID.
Graeme
3

De http://vyaskn.tripod.com/programming_faq.htm#q17 :

Oracle tiene un rownum para acceder a las filas de una tabla utilizando el número de fila o la identificación de fila. ¿Hay algún equivalente para eso en SQL Server? ¿O cómo generar resultados con el número de fila en SQL Server?

No existe un equivalente directo al rownum o la identificación de fila de Oracle en SQL Server. Estrictamente hablando, en una base de datos relacional, las filas dentro de una tabla no están ordenadas y una identificación de fila realmente no tendrá sentido. Pero si necesita esa funcionalidad, considere las siguientes tres alternativas:

  • Agrega una IDENTITYcolumna a tu tabla.

  • Utilice la siguiente consulta para generar un número de fila para cada fila. La siguiente consulta genera un número de fila para cada fila en la tabla de autores de la base de datos pubs. Para que esta consulta funcione, la tabla debe tener una clave única.

    SELECT (SELECT COUNT(i.au_id) 
            FROM pubs..authors i 
            WHERE i.au_id >= o.au_id ) AS RowID, 
           au_fname + ' ' + au_lname AS 'Author name'
    FROM          pubs..authors o
    ORDER BY      RowID
    
  • Utilice un enfoque de tabla temporal para almacenar todo el conjunto de resultados en una tabla temporal, junto con una identificación de fila generada por la IDENTITY() función. La creación de una tabla temporal será costosa, especialmente cuando se trabaja con tablas grandes. Opte por este enfoque, si no tiene una clave única en su tabla.

cjs
fuente
3

Si desea numerar permanentemente las filas de la tabla, no utilice la solución RID para SQL Server. Funcionará peor que Access en un 386 antiguo. Para SQL Server, simplemente cree una columna IDENTITY y use esa columna como clave primaria agrupada. Esto colocará un árbol B entero rápido y permanente en la tabla y, lo que es más importante, cada índice no agrupado lo usará para ubicar filas. Si intenta desarrollar en SQL Server como si fuera Oracle, creará una base de datos de bajo rendimiento. Necesita optimizar para el motor, no pretender que es un motor diferente.

Además, no utilice NewID () para completar la clave principal con GUID, matará el rendimiento de inserción. Si debe utilizar GUID, utilice NewSequentialID () como columna predeterminada. Pero INT seguirá siendo más rápido.

Si, por otro lado, simplemente desea numerar las filas que resultan de una consulta, use la función RowNumber Over () como una de las columnas de la consulta.

usuario2793105
fuente
1

Consulte http://msdn.microsoft.com/en-us/library/aa260631(v=SQL.80).aspx En el servidor SQL, una marca de tiempo no es lo mismo que una columna DateTime. Esto se usa para identificar de forma única una fila en una base de datos, no solo una tabla, sino toda la base de datos. Esto se puede utilizar para una simultaneidad optimista. por ejemplo UPDATE [Job] SET [Name] = @ Name, [XCustomData] = @ XCustomData WHERE ([ModifiedTimeStamp] = @ Original_ModifiedTimeStamp AND [GUID] = @ Original_GUID

ModifiedTimeStamp garantiza que está actualizando los datos originales y fallará si se ha producido otra actualización en la fila.

Jim
fuente
0

Tomé este ejemplo del ejemplo de MS SQL y puede ver que el @ID se puede intercambiar con integer o varchar o lo que sea. Esta era la misma solución que estaba buscando, así que la comparto. ¡¡Disfrutar!!

-- UPDATE statement with CTE references that are correctly matched.
DECLARE @x TABLE (ID int, Stad int, Value int, ison bit);
INSERT @x VALUES (1, 0, 10, 0), (2, 1, 20, 0), (6, 0, 40, 0), (4, 1, 50, 0), (5, 3, 60, 0), (9, 6, 20, 0), (7, 5, 10, 0), (8, 8, 220, 0);
DECLARE @Error int;
DECLARE @id int;

WITH cte AS (SELECT top 1 * FROM @x WHERE Stad=6)
UPDATE x -- cte is referenced by the alias.
SET ison=1, @id=x.ID
FROM cte AS x

SELECT *, @id as 'random' from @x
GO
barry austra
fuente
0

Puede obtener el ROWID utilizando los métodos que se indican a continuación:

1.Crear una nueva tabla con un campo de incremento automático en ella

2.Utilice la función analítica Row_Number para obtener la secuencia en función de sus requisitos. Preferiría esto porque ayuda en situaciones en las que desea el row_id en forma ascendente o descendente de un campo específico o combinación de campos

Ejemplo: Row_Number () Over (Partición por orden de departamento por sal desc)

La muestra anterior le dará el número de secuencia basado en el salario más alto de cada departamento. La partición por es opcional y puede eliminarla según sus requisitos.

Saurabh Gautam
fuente