Проблема при изменении имен столбцов с использованием SQL Server - PullRequest
0 голосов
/ 18 января 2020

Это мой первый вопрос о переполнении стека; Я столкнулся с проблемой изменения имен столбцов.

У меня есть таблица INS_Sink с такими столбцами, как

INS2017, INS2018, INS2019, INS2020 

Теперь мне нужно изменить имена существующих столбцов, например:

INS2017 to INS CY-3,
INS2018 to INS CY-2,
INS2019 to INS CY-1,
INS2020 to INS CY,

где CY = CurrentYear.

Мне нужно динамически изменять все столбцы, как указано выше, и имена столбцов должны изменяться автоматически при изменении года, как в 2021 году, INS2020 должен станьте INS CY-1 ..

Кто-нибудь может мне помочь, как добиться этого, и я не хочу менять свои столбцы здесь?

Заранее спасибо ...

Ответы [ 2 ]

2 голосов
/ 18 января 2020

Во-первых, вы не должны этого делать. Базовая таблица должна отражать правильные данные.

Во-вторых, вы не должны использовать имена вроде INS CY-1. Такое имя нужно избегать. Вместо этого вы должны использовать INS_CY_1. Это чище.

Далее у вас проблема с вашей моделью данных. Вы должны хранить данные как:

YEAR     INSVALUE
2017     ?
2018     ?

Конечно, у вас могут быть другие столбцы, которые вы не указали.

С этой структурой данных легко создать представление это делает то, что вы хотите. Скажем, текущий год определяется с помощью YEAR(GETDATE()). Тогда:

select sum(case when t.year = v.yyyy then t.insvalue end) as ins_cy,
       sum(case when t.year = v.yyyy - 1 then t.insvalue end) as ins_cy_1,
       sum(case when t.year = v.yyyy then t.insvalue end) as ins_cy_2
from t cross join
     (values (year(getdate())) v(yyyy);

Вы можете продолжить эту логику c на сколько угодно лет назад go.

0 голосов
/ 18 января 2020

если вам действительно нужно получить данные в столбцах CY-xyz, то может быть лучше создать представление и настроить представление при необходимости (вы можете использовать как представление, так и таблицу для операций DML).

create table dbo.INS_Sink_test
(
id int identity(1,1) constraint pk_id_ins_sink_test primary key clustered,
col1 int,
col2 int,
INS2010 int,
INS2011 int,
INS2012 int,
INS2013 int,
INS2014 int,
INS2015 int,
INS2016 int,
INS2017 int,
INS2018 int,
INS2019 int,
INS2020 int
)
go
insert into dbo.INS_Sink_test
(
    col1, col2, INS2010, INS2011, INS2012, INS2013, INS2014, INS2015, INS2016, INS2017, INS2018, INS2019, INS2020
)
values
(1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4)
go

--create/adjust a view

declare @year smallint = year(getdate());

newyear:

declare @colssql nvarchar(max) = N'';
select @colssql = @colssql + N',' + quotename(name) + ' as ' + quotename(newcolname)
from
(
select column_id,
    name,
    case when name like 'INS[0-9][0-9][0-9][0-9]' then 'CY' + isnull(cast(nullif(cast(replace(name, 'INS', '') as smallint)-@year, 0) as sysname), '')
        else name
    end as newcolname
from sys.columns
where object_id = object_id('dbo.INS_Sink_test')
) as a
order by column_id;

declare @viewsql nvarchar(max) = N'view dbo.v_INS_Sink_test
as
select 
'  + stuff(@colssql, 1, 1, N'') + N'
from dbo.INS_Sink_test
';

select @viewsql = case when object_id('dbo.v_INS_Sink_test') is null then N'create' else N'alter' end + N' ' + @viewsql ;
--print @viewsql
exec(@viewsql);
--dont forget to refresh other views that depend on v_ins_sink_test
--exec sp_refreshview 'dbo.view_xyz';
exec sp_refreshview 'dbo.v_INS_Sink_test';


select @year as theyear;
select *
from dbo.INS_Sink_test;

select *
from dbo.v_INS_Sink_test;


if @year = 2021
begin
    --cleanup
    if object_id('dbo.INS_Sink_test') is not null
    begin
        drop table dbo.INS_Sink_test;
    end 

    if object_id('dbo.v_INS_Sink_test') is not null
    begin
        drop view dbo.v_INS_Sink_test;
    end 

    return;
end

--i know what you did in 2021..
select @year = 2021;
goto newyear
--cleanup
/*
if object_id('dbo.INS_Sink_test') is not null
begin
    drop table dbo.INS_Sink_test;
end 

if object_id('dbo.v_INS_Sink_test') is not null
begin
    drop view dbo.v_INS_Sink_test;
end 
*/

Для изменения имен столбцов таблицы:

create table dbo.INS_Sink_test
(
id int identity(1,1) constraint pk_id_ins_sink_test primary key clustered,
col1 int,
col2 int,
INS2010 int,
INS2011 int,
INS2012 int,
INS2013 int,
INS2014 int,
INS2015 int,
INS2016 int,
INS2017 int,
INS2018 int,
INS2019 int,
INS2020 int
)
go
insert into dbo.INS_Sink_test
(
    col1, col2, INS2010, INS2011, INS2012, INS2013, INS2014, INS2015, INS2016, INS2017, INS2018, INS2019, INS2020
)
values
(1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4)
go

select *
from dbo.INS_Sink_test
go

--rename columns
declare @year smallint = year(getdate());
declare @renamecolssql nvarchar(max) = N'';
select @renamecolssql = @renamecolssql + N'exec sp_rename '''  + quotename(object_schema_name(object_id)) + N'.' + quotename(object_name(object_id)) + N'.' + quotename(name) + ''', '+ quotename(newcolname) + '; '
from
(
select 
    object_id,
    column_id,
    name,
  'INS CY' + isnull(cast(nullif(cast(replace(name, 'INS', '') as smallint)-@year, 0) as sysname), '') as  newcolname
from sys.columns
where object_id = object_id('dbo.INS_Sink_test') --<-- change the name of the table
and name like 'INS[0-9][0-9][0-9][0-9]'
) as a
order by column_id;

exec(@renamecolssql);
go

select *
from dbo.INS_Sink_test
go

--cleanup
drop table dbo.INS_Sink_test
go
...