Эквивалент RowID Oracle в SQL Server - PullRequest
74 голосов
/ 26 мая 2009

Что эквивалентно RowID Oracle в SQL Server?

Ответы [ 13 ]

114 голосов
/ 24 сентября 2011

Из документов Oracle

Псевдоколонка ROWID

Для каждой строки в базе данных псевдостолбец ROWID возвращает адрес строки. В значениях строк базы данных Oracle содержится информация необходимо найти строку:

  • Номер объекта данных объекта
  • Блок данных в файле данных, в котором находится строка
  • Положение строки в блоке данных (первая строка 0)
  • Файл данных, в котором находится строка (первый файл - 1). Файл число относительно табличного пространства.

Ближайшим эквивалентом этого в SQL Server является rid, который состоит из трех компонентов File:Page:Slot.

В SQL Server 2008 можно использовать недокументированный и неподдерживаемый виртуальный столбец %%physloc%%, чтобы увидеть это. Это возвращает значение binary(8) с идентификатором страницы в первых четырех байтах, затем 2 байта для идентификатора файла, а затем 2 байта для расположения слота на странице.

Скалярная функция sys.fn_PhysLocFormatter или sys.fn_PhysLocCracker TVF может использоваться для преобразования ее в более читаемую форму

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

Пример вывода

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

Обратите внимание, что это не используется обработчиком запросов. Хотя возможно использовать это в WHERE предложении

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

SQL Server не будет напрямую искать указанную строку. Вместо этого он выполнит полное сканирование таблицы, оценит %%physloc%% для каждой строки и вернет ту, которая соответствует (если есть).

Чтобы отменить процесс, выполняемый двумя ранее упомянутыми функциями, и получить значение binary(8), соответствующее известным значениям File, Page, Slot, ниже могут использоваться следующие значения.

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))
9 голосов
/ 26 мая 2009

Если вы хотите однозначно идентифицировать строку в таблице, а не в наборе результатов, вам нужно использовать что-то вроде столбца IDENTITY. См. «Свойство IDENTITY» в справке по SQL Server. SQL Server не генерирует автоматически идентификатор для каждой строки в таблице, как это делает Oracle, поэтому вам придется столкнуться с проблемой создания собственного столбца идентификаторов и явно получить его в своем запросе.

РЕДАКТИРОВАТЬ: для динамической нумерации строк набора результатов см. Ниже, но это, вероятно, эквивалентно Oracle ROWNUM, и я предполагаю из всех комментариев на странице, что вы хотите материал выше. Для SQL Server 2005 и более поздних версий вы можете использовать новую функцию Функции ранжирования для достижения динамической нумерации строк.

Например, я делаю это по моему запросу:

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

Даст вам:

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

Также есть статья на support.microsoft.com о динамической нумерации строк.

8 голосов
/ 26 мая 2009

Проверьте новую функцию ROW_NUMBER . Это работает так:

SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE
6 голосов
/ 10 ноября 2016

Я должен вывести очень большую таблицу со многими столбцами, и скорость важна. Таким образом я использую этот метод, который работает для любой таблицы:

delete T from 
(select Row_Number() Over(Partition By BINARY_CHECKSUM(*) order by %%physloc%% ) As RowNumber, * From MyTable) T
Where T.RowNumber > 1
6 голосов
/ 28 сентября 2011

Некоторые из приведенных выше ответов будут работать вокруг отсутствия прямой ссылки на конкретную строку, но не будет работать , если произойдут изменения в других строках таблицы. Это мои критерии, по которым ответы технически не дотягивают.

Обычно ROWID используется Oracle для обеспечения (несколько) стабильного метода выбора строк и последующего возврата к строке для ее обработки (например, для ее ОБНОВЛЕНИЯ). Метод нахождения строки (сложные объединения, полнотекстовый поиск или просмотр строки за строкой и применение процедурных тестов к данным) не может быть легко или безопасно повторно использован для квалификации оператора UPDATE.

Кажется, что RID SQL Server обеспечивает ту же функциональность, но не обеспечивает такую ​​же производительность. Это единственная проблема, которую я вижу, и, к сожалению, цель сохранения ROWID состоит в том, чтобы избежать повторения дорогостоящей операции, чтобы найти строку, скажем, в очень большой таблице. Тем не менее, производительность во многих случаях является приемлемой. Если Microsoft настроит оптимизатор в будущем выпуске, проблема производительности может быть устранена.

Также возможно просто использовать FOR UPDATE и держать CURSOR открытым в процедурной программе. Однако это может оказаться дорогостоящим в больших или сложных пакетной обработке.

Предупреждение: Даже ROWID Oracle не будет стабильным, если, например, администратор базы данных между SELECT и UPDATE будет перестраивать базу данных, поскольку это физический идентификатор строки. Таким образом, устройство ROWID должно использоваться только в рамках хорошо определенной задачи.

3 голосов
/ 19 сентября 2013

Если вы хотите постоянно нумеровать строки в таблице, пожалуйста, не используйте решение RID для SQL Server. Он будет работать хуже, чем Access на старом 386. Для SQL Server просто создайте столбец IDENTITY и используйте этот столбец в качестве кластерного первичного ключа. Это поместит постоянное быстрое целочисленное B-дерево в таблицу, и, что более важно, каждый некластеризованный индекс будет использовать его для поиска строк. Если вы попытаетесь развиваться в SQL Server, как будто это Oracle, вы создадите плохо работающую базу данных. Вам нужно оптимизировать двигатель, а не делать вид, что это другой двигатель.

также, пожалуйста, не используйте NewID () для заполнения первичного ключа идентификаторами GUID, вы снизите производительность вставки. Если вы должны использовать GUID, используйте NewSequentialID () в качестве столбца по умолчанию. Но INT все равно будет быстрее.

Если, с другой стороны, вы просто хотите нумеровать строки, полученные в результате запроса, используйте функцию RowNumber Over () в качестве одного из столбцов запроса.

3 голосов
/ 26 мая 2009

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

У Oracle есть rownum для доступа к строкам таблицы с использованием номера строки или идентификатора строки. Есть ли аналог в SQL Server? Или как сгенерировать вывод с номером строки в SQL Server?

В SQL нет прямого эквивалента rownum или id строки Oracle Сервер. Строго говоря, в реляционной базе данных строки внутри таблица не упорядочена, и идентификатор строки не имеет смысла. Но если ты нужна эта функциональность, рассмотрим следующие три альтернативы:

  • Добавьте столбец IDENTITY в таблицу.

  • Используйте следующий запрос для генерации номера строки для каждой строки. Следующий запрос генерирует номер строки для каждой строки в авторах таблица базы данных пабов. Чтобы этот запрос работал, таблица должна иметь уникальный ключ.

    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
    
  • Использование подхода временной таблицы, чтобы сохранить весь набор результатов во временной таблице вместе с идентификатором строки, сгенерированным IDENTITY() функция. Создание временной таблицы будет дорогостоящим, особенно когда вы работаете с большими столами. Перейти на этот подход, если вы не иметь уникальный ключ в вашей таблице.

2 голосов
/ 24 июля 2017

Пожалуйста, попробуйте

select NEWID()

Источник: https://docs.microsoft.com/en-us/sql/t-sql/data-types/uniqueidentifier-transact-sql

2 голосов
/ 28 января 2010

если вы просто хотите получить базовую нумерацию строк для небольшого набора данных, как насчет чего-то подобного?

SELECT row_number() OVER (order by getdate()) as ROWID, * FROM Employees
1 голос
/ 12 марта 2013

Пожалуйста, смотрите http://msdn.microsoft.com/en-us/library/aa260631(v=SQL.80).aspx В SQL-сервере отметка времени отличается от столбца DateTime. Это используется для уникальной идентификации строки в базе данных, не только таблицы, но и всей базы данных. Это может быть использовано для оптимистичного параллелизма. например ОБНОВЛЕНИЕ [Задание] SET [Имя] = @ Имя, [XCustomData] = @ XCustomData WHERE ([ModifiedTimeStamp] = @ Original_ModifiedTimeStamp AND [GUID] = @ Original_GUID

ModifiedTimeStamp гарантирует, что вы обновляете исходные данные, и потерпит неудачу, если в строке произошло другое обновление.

...