Как изменить существующую таблицу MS Access на SQL-сервере - PullRequest
2 голосов
/ 04 августа 2011

Я сейчас переписываю базу данных MS Access, которая в настоящее время не нормализована и очень плохо спроектирована. Моя проблема в этом редизайне связана с тем, как они перемещают данные изо дня в день между таблицами.

Текущая настройка похожа на эту. У меня есть текстовый файл, который загружается в таблицу. Записи, которые мне нужны, будут добавлены в Таблицу1, на следующий день некоторые данные из Таблицы1 будут загружены в Таблицу2. Затем Table2 используется для обновления Table1 после импорта за день.

6/1/11
File > Table1
       field1
       field2

11.06.11 файл обновит Таблицу 1 и заполнит поля

6/2/11
Step 1                  Step 2                Step 3
Table1 > Table2         File  > Table1        Table2 > Table1  
field1   field1                 newdata1      field1   newdata1
field2   field2                 newdata2      field2   newdata2

2 июня 2011 г. первый шаг - перемещение поля field1 / field2 в table2 (временная таблица). Затем мы удаляем данные из таблицы 1 и затем импортируем файл с того дня на шаге 2. На шаге 3 мы выполняем обновление таблицы 1, используя данные из таблицы 2, если учетная запись присутствует. По сути, мы соединяем вчерашние данные на сегодня, если учетная запись существует.

В моем новом дизайне у меня есть таблица, похожая на эту. Где первичным ключом в таблице будут BusinessDate и Account, потому что они различны изо дня в день.

CREATE TABLE [dbo].[Table](
    [BusinessDate] [smalldatetime] NOT NULL,
    [Account] [int] NOT NULL,
    [Guid] [uniqueidentifier] NOT NULL,
    [InitialAmount] [money] NULL,
    [LetterDate] [smalldatetime] NULL,
    [LetterType] [varchar](50) NULL,
    [Status] [varchar](50) NULL,
    [Reason] [varchar](50) NULL,
    [FollowUpDate] [smalldatetime] NULL,
    [LastModifiedBy] [varchar](50) NULL,
    [LastModifiedDate] [datetime] NULL
) ON [PRIMARY]

Если бы учетная запись была добавлена ​​6/1, а затем была импортирована 6/2, я бы выполнил обновление, используя данные из 6/1 в полях выше. Мне посоветовали продолжать копировать данные одного и того же типа изо дня в день - плохой дизайн. Но я не знаю, как реализовать это, потому что записи изо дня в день считаются новыми, но некоторые исходные данные должны оставаться привязанными ко всем будущим элементам.

Этот тип настройки используется во всей текущей настройке, и я не знаю, как ее проектировать. Кто-нибудь может предложить какие-либо предложения о том, как продолжить этот дизайн? Это трудно объяснить, поэтому, если это не ясно, пожалуйста, спросите.

EDIT:

Часть моей проблемы заключается в том, что мне нужно иметь доступ к деталям, которые будут перенесены на любой день. Если у меня есть учетная запись, пришедшая 01.08.11 с первоначальной суммой на счете, пользователи назначают статус, тип письма. И затем эта же учетная запись поступает 2/2/11, отправной точкой для 8/2 являются значения на конец дня от 8/1. Затем они обработают счет за этот день. 8/2 счет будет начинаться заново, но вместо нуля он начинается со вчерашних значений.

Пользователи по-прежнему должны иметь возможность доступа к данным с 8/1 и просмотра значений на конец дня.

* +1025 * Пример:
  • 8/1/11 счет 1234567890 добавляется с дебетом - $ 10, представитель присваивает статус = проверено, причина = проверка вопроса
  • 8/2/11 счет 1234567890 добавляется с новым дебетом - $ 50, начальный статус = проверен, причина = проверка
  • 8/2/11 - пользователь обрабатывает данные на счете 1234567890 для дебета $ -50 и изменяет статус = решен, причина = нет
  • 8/3/11 - пользователь выполняет поиск для бизнес-даты 01.08.11 для учетной записи 1234567890, ему необходимо просмотреть данные со статусом = проверено, причина = проверка вопроса

Надеюсь, дополнительные детали помогут. Извините за очень длинное объяснение.

Ответы [ 2 ]

1 голос
/ 16 августа 2011

Хорошо, так что, прочитав изменения к вашему вопросу, вот моя следующая попытка!

Идея этого заключается в том, что мы используем одну таблицу для хранения всего, и эта таблица фактически является журналом изменений для всегочто происходит.Затем, вместо того, чтобы работать непосредственно за столом, мы используем представление, чтобы предоставить нам самую последнюю информацию для каждой учетной записи.Я также включил представление, которое дает вам состояние «закрытия» для каждой учетной записи по дням.

Вы можете легко изменить этот дизайн так, чтобы он содержал только одну строку в день, вместо того, чтобы быть полным журналом изменений.(В этом случае вам не нужно второе представление, поскольку оно фактически совпадает с таблицей.)

CREATE TABLE Accounts (
    ID                  int IDENTITY(1,1),
    BusinessDate        smalldatetime NOT NULL,
    Account             int NOT NULL,
    InitialAmount       money NULL,
    LetterDate          smalldatetime NULL,
    LetterType          varchar(50) NULL,
    Status              varchar(50) NULL,
    Reason              varchar(50) NULL,
    FollowUpDate        smalldatetime NULL,
    LastModifiedBy      varchar(50) NULL,
    LastModifiedDate    datetime NULL
)

insert into Accounts
values ({d '2011-08-01'}, 1234567890, -10, NULL, NULL, 'Reviewed', 'Check issue', NULL, 'User', NULL),
    ({d '2011-08-02'}, 1234567890, -50, NULL, NULL, 'Reviewed', 'Check issue', NULL, 'DataLoad', NULL),
    ({d '2011-08-02'}, 1234567890, -50, NULL, NULL, 'Resolved', 'None', NULL, 'User', NULL),
    ({d '2011-08-02'}, 1234567891, -20, NULL, NULL, 'Reviewed', 'Check issue', NULL, 'DataLoad', NULL)
GO

create view AccountsLatest
as
select a.*
from Accounts a inner join
    (   
        select a.Account, MAX(a.ID) as ID
        from Accounts a
        group by a.Account
    ) mx on a.ID = mx.ID
GO

create view AccountLatestByDate
as
select a.*
from Accounts a inner join
    (   
        select a.Account, a.BusinessDate, MAX(a.ID) as ID
        from Accounts a
        group by a.Account, a.BusinessDate
    ) mx on a.ID = mx.ID
GO

Что касается файла, который загружен, и для которого необходимо «скопировать вперед» некоторые данныеЧто ж, с этим можно справиться примерно так:

--For simplicity's sake, I'm creating a load table that you simply clear and append your file contents to every night
create table MyFile (
    BusinessDate        smalldatetime NOT NULL,
    Account             int NOT NULL,
    InitialAmount       money NULL,
)

insert into Accounts
select f.BusinessDate, f.Account, f.InitialAmount, a.LetterDate, a.LetterType, a.Status, a.Reason, a.FollowUpDate, a.LastModifiedBy, a.LastModifiedDate
from MyFile f inner join
    AccountsLatest a on f.Account = a.Account

Надеюсь, это послужит хорошей отправной точкой для вас - она, очевидно, нуждается в доработке, чтобы соответствовать вашим точным потребностям.

Я думаюВы правы, подвергая сомнению процесс, стоящий за этим, так как я думаю, что решение, которое в настоящее время существует, немного скудно.Это может работать, но звучит далеко не идеально.Я ничего не знаю о вашем бизнесе, но бизнес-процесс, стоящий за ним, тоже может быть немного сложным - возможно, стоит воспользоваться возможностью миграции этой платформы, чтобы хотя бы немного изучить идею очистки этой стороны.

ОРИГИНАЛЬНЫЙ ОТВЕТ (для потомков)

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

CREATE TABLE dbo.Accounts (
    Account int NOT NULL PRIMARY KEY,
    InitialAmount money NULL,
    Status varchar(50) NULL,
    Reason varchar(50) NULL,
    LastModifiedBy varchar(50) NULL,
    LastModifiedDate datetime NULL
)

CREATE TABLE dbo.AccountDetails (
    BusinessDate smalldatetime NOT NULL,
    Account int NOT NULL,
    Guid uniqueidentifier NOT NULL,
    LetterDate smalldatetime NULL,
    LetterType varchar(50) NULL,
    FollowUpDate smalldatetime NULL,
    LastModifiedBy varchar(50) NULL,
    LastModifiedDate datetime NULL
)

--This table will contain all the historic data that used to be in AccountDetails
CREATE TABLE dbo.AccountDetailsHistory (
    BusinessDate smalldatetime NOT NULL,
    Account int NOT NULL,
    Guid uniqueidentifier NOT NULL,
    LetterDate smalldatetime NULL,
    LetterType varchar(50) NULL,
    FollowUpDate smalldatetime NULL,
    LastModifiedBy varchar(50) NULL,
    LastModifiedDate datetime NULL
)

Теперь каждую ночь содержимое AccountDetails перемещается в AccountDetailsHistory, а содержимое файла загружаетсяв AccountDetails.Данные, которые вам нужно было бы «скопировать вперед», хранятся в Учетных записях и поэтому не изменились.

Вы также можете просто иметь одну таблицу AccountDetails и разделить ее, если вам нужно.Вот хорошая статья о том, как работает разбиение и нужно ли вам его использовать: http://msdn.microsoft.com/en-us/library/ms345146%28v=sql.90%29.aspx,, и эта статья показывает вам, как просто настроить: http://blogs.msdn.com/b/manisblog/archive/2009/01/18/easy-table-partitions-with-sql-server-2008.aspx.

Надеюсь, это поможет!

0 голосов
/ 07 сентября 2011

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

Обозначенная проблема, по-видимому, требует только последнего ежедневного снимка (по одному на каждый день изменения данных), поэтому будет достаточно ежедневного просмотра последнего снимка.В качестве альтернативы, если вам действительно нужно записывать и иметь возможность отслеживать все внутридневные транзакции, то вы можете разделить таблицу на две части (транзакция и ежедневный снимок), но я считаю, что в этом нет необходимости.

Решение для хранимой процедуры

Чтобы сохранить все в SQL Server, вы должны использовать процедуру, которая создает, вставляет и копирует ваши данные соответственно, в зависимости отна том, что уже существует,

Следующий скрипт устанавливает таблицу с именем AccountDetails с одной учетной записью образца данных;

    CREATE TABLE [dbo].AccountDetails(
    [BusinessDate] [smalldatetime] NOT NULL,
    [Account] [int] NOT NULL,
    [Guid] [uniqueidentifier] NOT NULL,
    [InitialAmount] [money] NULL,
    [LetterDate] [smalldatetime] NULL,
    [LetterType] [varchar](50) NULL,
    [Status] [varchar](50) NULL,
    [Reason] [varchar](50) NULL,
    [FollowUpDate] [smalldatetime] NULL,
    [LastModifiedBy] [varchar](50) NULL,
    [LastModifiedDate] [datetime] NULL
) ON [PRIMARY]

INSERT INTO AccountDetails
VALUES ('2011-01-01', 123, NEWID(), 20, '2011-01-01', 'initial', 'reviewed', 'check issue', '2011-01-02', 'dwb',GETDATE())

Хранимая процедура AccountDetailsController позволяет вам либо

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

.

CREATE PROCEDURE AccountDetailsController
    @BusinessDate smalldatetime ,
    @Account [int] ,
    @Guid [uniqueidentifier] ,
    @InitialAmount [money] ,
    @LetterDate smalldatetime,
    @LetterType varchar(50) ,
    @Status varchar(50) ,
    @Reason varchar(50) ,
    @FollowUpDate smalldatetime,
    @LastModifiedBy varchar(50)
 AS
 BEGIN

/*
 -- test bed
 -- remove when finished testing
    DECLARE 
    @BusinessDate smalldatetime = '2011-01-01',
    @Account [int] =123,
    @Guid [uniqueidentifier] =null ,
    @InitialAmount [money] =30 ,
    @LetterDate smalldatetime = '2011-01-01',
    @LetterType varchar(50) ='initial',
    @Status varchar(50) =  'reviewed',
    @Reason varchar(50) = 'check issue',
    @FollowUpDate smalldatetime = null,
    @LastModifiedBy varchar(50) = 'dwb'
*/

    IF EXISTS (SELECT * FROM AccountDetails WHERE DateDiff(DAY,BusinessDate, @BusinessDate) = 0 AND @Account = [account])
    BEGIN
        --RECORD ALREADY EXISTS FOR TODAY, UPDATE
        UPDATE  AccountDetails
        SET     BusinessDate = ISNULL(@BusinessDate, BusinessDate),
                [guid] = ISNULL(@Guid, [guid]),
                InitialAmount = ISNULL(@InitialAmount, InitialAmount),
                LetterDate = ISNULL(@LetterDate, LetterDate),
                LetterType = ISNULL(@LetterType, LetterType)  ,
                [Status] = ISNULL(@Status ,[Status] ) ,
                Reason = ISNULL(@Reason, reason) ,
                FollowUpDate = ISNULL(@FollowUpDate, FollowUpDate),
                LastModifiedBy = ISNULL(@LastModifiedBy, LastModifiedBy) ,
                LastModifiedDate = GETDATE()
        FROM    AccountDetails ad 
        WHERE   DateDiff(DAY,BusinessDate, @BusinessDate) = 0 
        AND     @Account = [account]
    END 
    ELSE IF EXISTS (SELECT * FROM AccountDetails WHERE @Account = [account])
    BEGIN
        --RECORD ALREADY EXISTS, BUT FOR ANOTHER DAY.  USE THIS AS THE BASIS OF TODAYS RECORD
        INSERT INTO AccountDetails
        SELECT @BusinessDate,
                @Account,
                ISNULL (@Guid, ad.guid),
                ISNULL(@InitialAmount, InitialAmount),
                ISNULL(@LetterDate, LetterDate),
                ISNULL(@LetterType, LetterType)  ,
                ISNULL(@Status ,[Status] ) ,
                ISNULL(@Reason, reason) ,
                ISNULL(@FollowUpDate, FollowUpDate),
                ISNULL(@LastModifiedBy, LastModifiedBy) ,
                GETDATE()
        FROM    AccountDetails ad
        WHERE   Account = @Account
        AND     BusinessDate = 
        (   
            SELECT  MAX(BusinessDate)
            FROM    AccountDetails 
            WHERE   @Account = [account]
        )
    END 
    ELSE 
    BEGIN
        --NO PREVIOUS RECORD EXISTS
        INSERT INTO AccountDetails
        VALUES (@BusinessDate,
                @Account,
                @Guid,
                @InitialAmount,
                @LetterDate,
                @LetterType,
                @Status,
                @reason ,
                @FollowUpDate,
                @LastModifiedBy ,
                GETDATE())

    END

END

Следующее должно обслуживать все сценарии:

--update a record that exists for today
exec AccountDetailsController '2011-01-01', 123, null, 30, '2011-01-01', 'initial', 'reviewed', 'check issue', null, 'dwb'

--create a new record based on the last date entered for account
exec AccountDetailsController '2011-01-02', 123, null, 50, null, 'considered', null, null, null, 'dwb'

--create an entirely new record, no previous account exists
exec AccountDetailsController '2011-01-02', 456, 'C9CA5430-6D0E-47A3-BC89-D95C53B888E4' , 10, '2011-01-03', 'opened', 'new account', 'unknown','2011-01-03','dwb'

Это приведет кВ следующих;Results of test data applied to AccountDetailsController

Решение SSIS

Если ваша бизнес-логика и рабочий процесс более сложны, чем пример, который вы предоставляете, вы можете рассмотреть SSISуправлять и контролировать данные.Это вывело бы решение из SQL и первоначально привело бы к накладным расходам на установку, но обеспечило бы более четкое представление о том, что происходит с данными, и со временем может быть более управляемым, особенно с импортированными файлами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...