Перенос базы данных PostgreSQL в MS SQL Server [дубликат]

Что вы можете сделать по этому поводу?

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

Проверить аргументы

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

Конструктор для ArgumentNullException даже принимает имя параметра и сообщение как аргументы, чтобы вы могли точно сказать разработчику, что проблема.

public void DoSomething(MyObject obj) {
    if(obj == null) 
    {
        throw new ArgumentNullException("obj", "Need a reference to obj.");
    }
}

Использовать инструменты

Есть также несколько библиотек, которые могут помочь. Например, «Resharper» может предоставить вам предупреждения во время написания кода, особенно если вы используете их атрибут: NotNullAttribute

В разделе «Контракты кода Microsoft» вы используете синтаксис, например Contract.Requires(obj != null), который дает вам проверку выполнения и компиляцию: Представление кодовых контрактов .

Существует также «PostSharp», который позволит вам просто использовать такие атрибуты:

public void DoSometing([NotNull] obj)

Сделав это и сделав PostSharp частью вашего процесса сборки, obj будет проверяться на нуль во время выполнения. См. Ошибка проверки PostSharp

Решение для простого кода

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

[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull where T: class
{
    private T _value;

    public T Value
    {
        get
        {
            if (_value == null)
            {
                throw new Exception("null value not allowed");
            }

            return _value;
        }
        set
        {
            if (value == null)
            {
                throw new Exception("null value not allowed.");
            }

            _value = value;
        }
    }

    public static implicit operator T(NotNull notNullValue)
    {
        return notNullValue.Value;
    }

    public static implicit operator NotNull(T value)
    {
        return new NotNull { Value = value };
    }
}

. Вы использовали бы очень похоже на то, как вы бы использовали Nullable, за исключением того, что цель заключалась в том, чтобы сделать абсолютно противоположное - не разрешать null. Вот несколько примеров:

NotNull person = null; // throws exception
NotNull person = new Person(); // OK
NotNull person = GetPerson(); // throws exception if GetPerson() returns null

NotNull неявно отбрасывается в и из T, поэтому вы можете использовать его в любом месте, где это необходимо. Например, вы можете передать объект Person методу, который принимает значение NotNull:

Person person = new Person { Name = "John" };
WriteName(person);

public static void WriteName(NotNull person)
{
    Console.WriteLine(person.Value.Name);
}

Как вы можете видеть выше, как с помощью nullable, вы получите доступ к базовому значению через Value имущество. Кроме того, вы можете использовать явный или неявный листинг, вы можете увидеть пример с возвращаемым значением ниже:

Person person = GetPerson();

public static NotNull GetPerson()
{
    return new Person { Name = "John" };
}

Или вы даже можете использовать его, когда метод просто возвращает T (в этом случае Person), выполнив бросок. Например, следующий код будет похож на код выше:

Person person = (NotNull)GetPerson();

public static Person GetPerson()
{
    return new Person { Name = "John" };
}

Объединить с Extension

Объединить NotNull с методом расширения, и вы можете охватить еще больше ситуаций. Вот пример того, как может выглядеть метод расширения:

[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
    public static T NotNull(this T @this) where T: class
    {
        if (@this == null)
        {
            throw new Exception("null value not allowed");
        }

        return @this;
    }
}

И вот пример того, как он может быть использован:

var person = GetPerson().NotNull();

GitHub

Для вашей справки я сделал код выше, доступный на GitHub, вы можете найти его по адресу:

https://github.com/luisperezphd/NotNull

Функция родственного языка

В C # 6.0 был введен «оператор с нулевым условием», который немного помогает в этом. С помощью этой функции вы можете ссылаться на вложенные объекты, и если какой-либо из них null, все выражение возвращает null.

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

var address = country?.State?.County?.City;

Представьте, что country является объектом типа Country, который имеет свойство, называемое State и т. Д. Если country, State, County или City - null, то address will be null . Therefore you only have to check whether адрес is null`.

Это отличная функция, но она дает вам меньше информации. Это не делает очевидным, какой из 4 является нулевым.

Встроенный как Nullable?

C # имеет красивую стенографию для Nullable, вы можете сделать что-то нулевое помещая знак вопроса после такого типа int?.

Было бы неплохо, если бы у C # было что-то вроде структуры NotNull выше и имела аналогичную стенографию, может быть, восклицательный знак (!), чтобы вы могли написать что-то вроде: public void WriteName(Person! person).

42
задан marc_s 3 July 2011 в 16:50
поделиться

2 ответа

Я считаю, что вы, возможно, получили пониженные голоса из-за невероятной простоты создания простого сценария SQL из PostgreSQL, который (теоретически) может быть запущен как раз в любой СУБД. Если пользователь является обычным пользователем PostgreSQL, он звучит как тупой вопрос.

Это не справедливо, так как выясняется, что это на самом деле проблема с умеренной сложностью (хотя это связано с нечетным синтаксисом и интерфейсом SQL Server, чем с отказом PostgreSQL).

Вы должны быть способны найти полезную информацию в принятом ответе на этой странице Serverfault: https://serverfault.com/questions/65407/best-tool-to-migrate-a-postgresql-database-to-ms-sql-2005 .

Если вы можете преобразовать схему без данных, вы можете сократить шаги для данных с помощью этой команды:

pg_dump --data-only --column-inserts your_db_name > data_load_script.sql

load будет довольно медленным, но опция --column-inserts генерирует наиболее общие инструкции INSERT, доступные для каждой строки данных, и должна быть совместимой.

EDIT: Предложения по преобразованию схемы следуют:

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

pg_dump --schema-only --no-owner --no-privileges your_db_name > schema_create_script.sql

Отредактируйте этот файл, чтобы добавить строку BEGIN TRANSACTION; в начало и ROLLBACK TRANSACTION; до конца. Теперь вы можете загрузить его и запустить в окне запроса на SQL Server. Если вы получите какие-либо ошибки, убедитесь, что вы переместились в нижнюю часть файла, выделите инструкцию ROLLBACK и запустите ее (нажав F5, когда вы подсвечиваете оператор).

В принципе, вам нужно разрешить каждую ошибку до тех пор, пока скрипт не пройдет чисто. Затем вы можете изменить ROLLBACK TRANSACTION на COMMIT TRANSACTION и выполнить одно последнее время.

К сожалению, я не могу помочь, с какими ошибками вы можете видеть, поскольку я никогда не переходил от PostgreSQL к SQL Server, только другие наоборот. Некоторые вещи, которые я ожидал бы быть проблемой, однако (очевидно, НЕ исчерпывающий список):

  • PostgreSQL делает автоматическое увеличение полей, связывая поле NOT NULL INTEGER с SEQUENCE, используя a DEFAULT. В SQL Server это столбец IDENTITY, но они не совсем то же самое. Я не уверен, что они эквивалентны, но если ваша исходная схема заполнена полями «id», у вас могут быть проблемы. Я не знаю, имеет ли SQL Server CREATE SEQUENCE, поэтому вам, возможно, придется их удалить.
  • Функции базы данных / Хранимые процедуры не переводятся между платформами РСУБД. Вам нужно будет удалить любые CREATE FUNCTION операторы и перевести алгоритмы вручную.
  • Будьте осторожны с кодировкой файла данных. Я человек Linux, поэтому я понятия не имею, как проверить кодировку в Windows, но вам нужно убедиться, что ожидаемый SQL Server такой же, как файл, который вы импортируете из PostgreSQL. pg_dump имеет опцию --encoding=, которая позволит вам установить конкретную кодировку. Я, кажется, помню, что Windows имеет тенденцию использовать двухбайтную кодировку UTF-16 для Unicode, где PostgreSQL использует UTF-8. У меня возникла проблема с SQL Server на PostgreSQL из-за вывода UTF-16, поэтому было бы интересно исследовать.
  • Тип данных PostgreSQL TEXT - это просто VARCHAR без максимальной длины. В SQL Server TEXT является ... сложным (и устаревшим). Каждое поле в исходной схеме, объявленное как TEXT, должно быть пересмотрено для соответствующего типа данных SQL Server.
  • SQL Server имеет дополнительные типы данных для данных UNICODE. Я недостаточно знаком с этим, чтобы делать предложения. Я просто указываю, что это может быть проблемой.
44
ответ дан Dan Neely 26 August 2018 в 13:45
поделиться

Я нашел более быстрый и простой способ выполнить это.

Сначала скопируйте таблицу (или запрос) в файл с разделителями табуляции следующим образом:

COPY (SELECT siteid, searchdist, listtype, list, sitename, county, street, 
   city, state, zip, georesult, elevation, lat, lng, wkt, unlocated_bool, 
   id, status, standard_status, date_opened_or_reported, date_closed, 
   notes, list_type_description FROM mlocal) TO 'c:\SQLAzureImportFiles\data_script_mlocal.tsv' NULL E''

Затем вы нужно создать таблицу в SQL, это не будет обрабатывать никакую схему для вас. Схема должна соответствовать вашему экспортированному файлу TSV в полевом порядке и типах данных.

Наконец, вы запускаете утилиту SQL bcp для ввода файла tsv следующим образом:

bcp MyDb.dbo.mlocal in "\\NEWDBSERVER\SQLAzureImportFiles\data_script_mlocal.tsv" -S tcp:YourDBServer.database.windows.net -U YourUserName -P YourPassword -c

Несколько что я столкнулся. Postgres и SQL Server обрабатывают логические поля по-разному. Для вашей схемы SQL Server необходимо, чтобы ваши логические поля были установлены в varchar (1), а полученные данные будут «f», «t» или «null». Затем вам нужно будет немного перевести это поле. что-то вроде:

ALTER TABLE mlocal ADD unlocated bit;
UPDATE mlocal SET unlocated=1 WHERE unlocated_bool='t';
UPDATE mlocal SET unlocated=0 WHERE unlocated_bool='f';
ALTER TABLE mlocal DROP COLUMN unlocated_bool;

Другое дело, что поля географии / геометрии очень разные между двумя платформами. Экспортируйте поля геометрии как WKT с помощью ST_AsText(geo) и соответствующим образом конвертируйте на конец SQL Server.

Может быть больше несовместимостей, требующих таких настроек.

EDIT. Поэтому, когда этот метод технически работает, я пытаюсь передать несколько миллионов записей из 100 + таблиц в SQL Azure и bcp в SQL Azure, это довольно flaky получается. Я продолжаю получать прерывистый Невозможно открыть ошибки BCP host data-file , сервер периодически отключается, и по какой-то причине некоторые записи не передаются без признаков ошибок или проблем. Таким образом, этот метод нестабилен для передачи больших объемов данных Azure SQL.

1
ответ дан Brad Mathews 26 August 2018 в 13:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: