Новичок SQL Server: Как обновить табличные данные из другой таблицы?

#sql #sql-server #sql-server-2008 #tsql #sql-update

#sql #sql-server #sql-server-2008 #tsql #sql-обновление

Вопрос:

Я все еще изучаю SQL. У меня вопрос об обновлении таблицы. Как я могу обновить свою таблицу на основе другой таблицы? Пожалуйста, посмотрите пример ниже:

 create table batch_info (
    batch_key int identity(1, 1) not null primary key,
    batch_num int not null,
    batch_name varchar(50) null,
    batch_start datetime null,
    batch_end datetime null,
    table_name varchar(50) null,
    insert_rows int null
)
go

insert into batch_info (batch_num, batch_name, batch_start)
    values ('32', 'Batch_to_insert_rows', '20110414')
go

select * from batch_info

create table ref_table (
    bat_num int not null,
    bat_end_date datetime null,
    bat_table_name varchar(50) null,
    bat_ins_rows int null,
)
go

insert into ref_table 
    values  ('32','20110414 02:12:00.000','Table1','10'),
            ('32','20110414 02:12:00.000','Table2','33'),
            ('32','20110414 02:12:00.000','Table3','12') 

select * from ref_table

--How can I update batch_info table to get this info?
select 
bi.batch_key, 
bi.batch_num, 
bi.batch_name,
bi.batch_start,
rt.bat_end_date,
rt.bat_table_name, 
rt.bat_ins_rows
 from batch_info as bi
inner join ref_table as rt on bi.batch_num = rt.bat_num
  

Редактировать: пакетный ключ является суррогатным, поэтому он должен быть инкрементным, а не (1, 1, 1), как в моем запросе join.

Ответ №1:

Предполагая, что комбинации batch_num и bat_end_date уникальны, это должно сработать:

 update  batch_info 
set     batch_end = rt.bat_end_date,
        table_name = rt.bat_table_name,
        insert_rows = rt.bat_ins_rows 
from    batch_info bi
        inner join ref_table rt on rt.bat_num = bi.batch_num 
        inner join 
        (
            select  bat_num,
                    MIN(bat_end_date) as min_bat_end_date
            from    ref_table 
        ) oldest on oldest.bat_num = rt.bat_num 
                    and oldest.min_bat_end_date = rt.bat_end_date 
where   bi.batch_end is null

insert into batch_info 
(batch_num, batch_name, batch_start, batch_end, table_name, insert_rows)
select  bi.batch_num,
        bi.batch_name,
        bi.batch_start,
        rt.bat_end_date,
        rt.bat_table_name,
        rt.bat_ins_rows 
from    batch_info bi
        inner join ref_table rt on rt.bat_num = bi.batch_num 
where   not exists 
        (
            select   * 
            from     batch_info e 
            where    e.batch_num = bi.batch_num 
                     and e.batch_end = rt.bat_end_date
        )
  

Если уникальность устанавливается другой комбинацией значений, то они могут быть добавлены к oldest в первом запросе и e во втором.

Я согласен с @Jim, что это должно быть разделено на две таблицы. Сложность выполнения этой операции является предвестником трудностей, которые создаст этот дизайн. Вы пытаетесь поместить две разные вещи (пакеты и пакетные запуски) в одну таблицу, а это никогда не бывает хорошей идеей.

Комментарии:

1. @Jeffrey 1 тебе за ответ на вопрос без курсора (ick), как я предлагал. Но, как мы оба согласны, это должно быть две таблицы.

2. Спасибо. Первая инструкция выдает ошибку: Сообщение 8120, уровень 16, состояние 1, строка 9, столбец ‘ref_table.bat_num’ недопустим в списке выбора, поскольку он не содержится ни в агрегатной функции, ни в предложении GROUP BY.

3. И оператор insert, похоже, ничего не вставляет в этом примере.

4. @jrara — В этом примере это ничего не делает, потому что, очевидно, bat_num end_date не определяет уникальные записи. Вы никогда не указывали в вопросе, что определяет уникальные записи. Я сказал в своем ответе, что эти вещи необходимо добавить в запрос, чтобы заставить его работать. Вероятно, я мог бы сделать другое предположение на основе данных примера, но только вы знаете правильный ответ на этот вопрос, поэтому мои предположения были бы бессмысленными.

5. Что касается другой ошибки, я пропустил GROUP BY. Должно быть, я спешил! Просто поместите «group by rt.bat_num» после «from ref_table» в производном табличном выражении (подзапросе) инструкции update.

Ответ №2:

 insert into batch_info
SELECT batch_num, batch_name, batch_start,
bat_end, bat_table_name, bat_ins_rows
FROM batch_info inner join ref_table
on batch_info.batch_num = ref_table.bat_num

delete from batch_info
where batch_end is null
  

РЕДАКТИРОВАТЬ: INSERT генерирует все совпадающие строки и вставляет их заново. К ним будут добавлены новые значения идентификаторов. Существующая строка (с другими полями null) используется для INSERT инструкции и позже удаляется с помощью 2-й инструкции.

Ответ №3:

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

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

Комментарии:

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

Ответ №4:

Сделайте автоматическое увеличение поля batch_info.batch_key.

 create table batch_info (
batch_key int identity(1, 1) not null primary key, -- <<- make autoincrement.
...