SQL Server / DB2: один и тот же запрос возвращает разные результаты? - PullRequest
1 голос
/ 10 февраля 2011

Сводка

В настоящее время я работаю над проектом, в котором мне нужно выполнить запрос к базовому ядру базы данных для последних изменений записей, которые представляют доступ пользователей.

Каждый пользователь может и являетсяне обязательно, иметь детей аккаунты.Дочерние учетные записи хранятся в одной и той же таблице данных со ссылкой на своего родителя через поле таблицы ID_PUSR.Если учетная запись является основной, ID_PUSR is null

Каждый раз, когда изменяется доступ, в таблице пользователей базы данных создается новая запись с датой последнего обновления (DT_UPDT).

Образец данных

Обратите внимание на следующее:

create table USERS (
   ID_USERS INT // Primary key
    , LN_USER VARCHAR(128)
    , FN_USER VARCHAR(128)
    , CD_USER VARCHAR(128)
    , DT_UPDT DATETIME
    , ID_PUSR INT // Foreign key to USERS.ID_USERS.
)

ID_USERS CD_USER    LN_USER      FN_USER     DT_UPDT                     ID_PUSR
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   808   T_PEI00    LN_USER_00   FN_USER_00  2011-01-01-00.00.00.000000    NULL
   809   T_PEI00    LN_USER_00   FN_USER_00  2010-01-01-00.00.00.000000    NULL
   810   T_PEI00    LN_USER_00   FN_USER_00  2009-01-01-00.00.00.000000    NULL
   811   T_PEI00    LN_USER_00   FN_USER_00  2008-01-01-00.00.00.000000    NULL
   812   T_PEI00    LN_USER_00   FN_USER_00  2007-01-01-00.00.00.000000    NULL 
   813   T_PEI00A   LN_USER_00   FN_USER_00  2011-01-01-00.00.00.000000    808
   814   T_PEI00A   LN_USER_00   FN_USER_00  2010-01-01-00.00.00.000000    809
   815   T_PEI00A   LN_USER_00   FN_USER_00  2009-01-01-00.00.00.000000    810
   816   T_PEI00A   LN_USER_00   FN_USER_00  2008-01-01-00.00.00.000000    811
   817   T_PEI00A   LN_USER_00   FN_USER_00  2007-01-01-00.00.00.000000    812
   818   T_MAW00    LN_USER_01   FN_USER_01  2010-01-01-00.00.00.000000    NULL 
   819   T_MAW00    LN_USER_01   FN_USER_01  2009-01-01-00.00.00.000000    NULL
   820   T_MAW00    LN_USER_01   FN_USER_01  2008-01-01-00.00.00.000000    NULL
   821   T_MAW00    LN_USER_01   FN_USER_01  2007-01-01-00.00.00.000000    NULL
   822   T_VEM08    LN_USER_08   FN_USER_08  2009-01-01-00.00.00.000000    NULL
   823   T_VEM08    LN_USER_08   FN_USER_08  2008-01-01-00.00.00.000000    NULL
   824   T_VEM08    LN_USER_08   FN_USER_08  2007-01-01-00.00.00.000000    NULL
   825   T_LAC99    LN_USER_99   FN_USER_99  2008-01-01-00.00.00.000000    NULL
   826   T_LAC99    LN_USER_99   FN_USER_99  2007-01-01-00.00.00.000000    NULL

Я дважды проверил содержимое таблицы данных на обоих серверах баз данных и могу подтвердить, что они являются идентичными записями.

Запрос SQL / DB2

Этот запрос полностью совместим с ядрами баз данных SQL Server и DB2:

with UPG as (
    select ID_USERS
            , CD_USER
            , LN_USER
            , FN_USER
            , DT_UPDT
            , ID_PUSR
            , row_number() over (partition by CD_USER order by CD_USER desc) as ROWNUM
        from USERS    
) select ID_USERS
        , CD_USER
        , LN_USER
        , FN_USER
        , DT_UPDT
        , ID_PUSR
        , ROWNUM
    from UPG
    where ROWNUM = 1
    order by CD_USER

Различные результаты!

Несмотря на то, что я выполняю один и тот же точно такой же запрос к вышеупомянутой СУБД, я получаю разные результаты следующим образом:

IBM DB2

ID_USERS CD_USER    LN_USER      FN_USER     DT_UPDT                    ID_PUSR  ROWNUM
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
  826    T_LAC99    LN_USER_99   FN_USER_99  2007-01-01-00.00.00.000000  NULL      1
  821    T_MAW00    LN_USER_01   FN_USER_01  2007-01-01-00.00.00.000000  NULL      1
  808    T_PEI00    LN_USER_00   FN_USER_00  2011-01-01-00.00.00.000000  NULL      1
  814    T_PEI00A   LN_USER_00   FN_USER_00  2010-01-01-00.00.00.000000  809       1
  822    T_VEM08    LN_USER_08   FN_USER_08  2009-01-01-00.00.00.000000  NULL      1

Эти результаты будут хорошими, пока мы не увидим разницу между двумя ядрами базы данных.Обратите внимание на значения даты в поле DT_UPDT.

SQL Server

ID_USERS CD_USER    LN_USER      FN_USER     DT_UPDT                    ID_PUSR  ROWNUM
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
  727    T_LAC99    LN_USER_99   FN_USER_99  2008-01-01 00:00:00.000     NULL      1
  720    T_MAW00    LN_USER_01   FN_USER_01  2010-01-01 00:00:00.000     NULL      1
  710    T_PEI00    LN_USER_00   FN_USER_00  2011-01-01 00:00:00.000     NULL      1
  715    T_PEI00A   LN_USER_00   FN_USER_00  2011-01-01 00:00:00.000     710       1
  724    T_VEM08    LN_USER_08   FN_USER_08  2009-01-01 00:00:00.000     NULL      1

Эти результаты, приведенные здесь, в SQL Server, являются теми, с которыми я приду в DB2.Они представляют "хорошие" данные.Что касается ID_USERS, то это просто идентификаторы, важны даты.

Вопросы

  1. Как один и тот же запрос может возвращать разные результаты, используя два механизма с поддержкой SQL ANSI?
  2. Это что-то с базой данных, которую я не вижу?
  3. Как интерпретируется DB2 WITH...AS (), который будет отличаться от SQL Server?

Nota Benne: простой select * from USERS order by CD_USER показывает те же данные.

1 Ответ

3 голосов
/ 10 февраля 2011

Ваш запрос является недетерминированным для связей.

row_number() over (partition by CD_USER order by CD_USER desc) as ROWNUM

не определяет какой-либо конкретной строки в каждом разделе.Если вы хотите, чтобы обе СУБД возвращали один и тот же порядок результатов по чему-то уникальному, чтобы не было связей и детерминированных результатов.

...