SQL Server 2005 ROW NUMBER() sin ORDENAR POR


Estoy tratando de insertar una tabla en otra usando

DECLARE @IDOffset int;
SELECT @IDOffset = MAX(ISNULL(ID,0)) FROM TargetTable

INSERT INTO TargetTable(ID, FIELD)
SELECT [Increment] + @IDOffset ,FeildValue
FROM SourceTable
WHERE [somecondition]

TargetTable.ID no es una columna de identidad, por lo que tengo que encontrar una manera de auto-incrementarlo yo mismo.

Sé que puedo usar un cursor, o crear una variable de tabla con una columna de identidad y un campo FieldValue, rellenar eso, luego usarlo en mi insert into...select, pero eso no es muy eficiente. Intenté usar la función ROW_NUMBER para incrementar, pero realmente no tengo un ORDEN legítimo POR campo en SourceTable que puedo utilizar, y me gustaría mantener el orden original de la SourceTable (si es posible).

¿alguien Puede sugerir algo?

Author: ErikE, 2011-01-27

2 answers

Puede evitar especificar un orden explícito de la siguiente manera:

INSERT dbo.TargetTable (ID, FIELD)
SELECT
   Row_Number() OVER (ORDER BY (SELECT 1))
      + Coalesce(
         (SELECT Max(ID) FROM dbo.TargetTable WITH (TABLOCKX, HOLDLOCK)),
         0
      ),
   FieldValue
FROM dbo.SourceTable
WHERE {somecondition};

Sin embargo, tenga en cuenta que es simplemente una manera de evitar especificar un pedido y NO garantiza que se conservará cualquier pedido de datos original. Hay otros factores que pueden hacer que el resultado se ordene, como un ORDER BY en la consulta externa. Para entender completamente esto, uno debe darse cuenta de que el concepto "no ordenado (de una manera particular)" no es lo mismo que "retener el orden original" (que ES ordenado de una manera particular!). Creo que desde una perspectiva de base de datos relacional pura, este último concepto no existe, por definición (aunque puede haber implementaciones de bases de datos que violen esto, SQL Server no es una de ellas).

La razón de las sugerencias de bloqueo es evitar el caso en que algún otro proceso se inserta usando el valor que planea usar, entre las partes de la consulta que se ejecutan.

Nota: Muchas personas usan (SELECT NULL) para evitar el " no constantes permitidas en la cláusula ORDER BY de una función de ventana" restriction. Por alguna razón, prefiero 1 sobre NULL.

También: Creo que una columna de identidad es muy superior y debería usarse en su lugar. No es bueno para la concurrencia bloquear exclusivamente tablas enteras. Eufemismo.

 73
Author: ErikE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-01 09:52:20

Puedes ignorar el orden usando order by (select null) así:

declare @IDOffset int;
select  @IDOffset = max(isnull(ID, 0)) from TargetTable

insert  into TargetTable(ID, FIELD)
select  row_number() over (order by (select null)) + @IDOffset, FeildValue
  from  SourceTable
 where  [somecondition]
 3
Author: Mohammad Anini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-19 07:51:45