我有3个表有相同的5列(T2中有+ 1个标志列,稍后我们将使用...让我们关注本例中的5列)。 T1,T2和T3。
所有三个表中的第一列都是Key Columns。
假设T1和T2有5条记录。 T1和T2中的4条记录匹配所有列。 第5条记录有4个匹配列(1个键+ 3个非键)。这意味着,T1和T2在第5条记录中有1个不匹配的非键列。
我想对前4列无所作为 我想从T2到T3插入第5列,并将T2的第6列更新为TRUE。
如何做到这一点?合并查询不起作用,因为只有我知道才能使用2个表...如果我错了,请纠正我。
请注意:这些表实际上有超过100列(相同列)sooo ...呵呵
THANX
更新:我仍然希望将前两列的值从T2传递给T3 ...而不仅仅是更改的列。
答案 0 :(得分:1)
-- Not tuned to any particular syntax, may need to be tweaked.
T1([a],b,c,d,e);
T2([a],b,c,d,e,f);
T3([a],b,c,d,e);
---------
-- SQL --
---------
BT;
INSERT INTO T3
SELECT
T2.a,
CASE WHEN (T1.b <> T2.b) THEN T2.b ELSE null,
CASE WHEN (T1.c <> T2.c) THEN T2.c ELSE null,
CASE WHEN (T1.d <> T2.d) THEN T2.d ELSE null,
CASE WHEN (T1.e <> T2.e) THEN T2.e ELSE null
FROM
T1,
T2
WHERE T1.a = T2.a
AND (
T1.b <> T2.b
OR T1.c <> T2.c
OR T1.d <> T2.d
OR T1.e <> T2.e
);
UPDATE T2
SET T2.f = true
T1.a IN (
SEL T1.a
FROM T1, T2
WHERE T1.a = T2.a
AND (
T1.b <> T2.b
OR T1.c <> T2.c
OR T1.d <> T2.d
OR T1.e <> T2.e
)
);
ET; -- OR COMMIT depending on sytax
示例数据
-- BEFORE -- -- AFTER --
T1 T1
|[a]| b | c | d | e | |[a]| b | c | d | e |
|---+---+---+---+---| |---+---+---+---+---|
| 0 | 1 | 2 | 3 | 4 | | 0 | 1 | 2 | 3 | 4 |
| 1 | 2 | 3 | 4 | 5 | | 1 | 2 | 3 | 4 | 5 |
| 1 | 2 | 3 | 4 | 5 | | 1 | 2 | 3 | 4 | 5 |
| 3 | 4 | 5 | 6 | 7 | | 3 | 4 | 5 | 6 | 7 |
| 4 | 5 | 6 | 7 | 8 | | 4 | 5 | 6 | 7 | 8 |
T2 T2
|[a]| b | c | d | e | f | |[a]| b | c | d | e | f |
|---+---+---+---+---+---| |---+---+---+---+---+---|
| 0 | 1 | 2 | 3 | 4 | f | | 0 | 1 | 2 | 3 | 4 | f |
| 1 | 2 | 3 | 4 |-3 | f | | 1 | 2 | 3 | 4 |-3 | t |
| 2 | 3 | 4 | 5 | 6 | f | | 2 | 3 | 4 | 5 | 6 | f |
| 3 | 4 | 5 |-5 | 7 | f | | 3 | 4 | 5 |-5 | 7 | t |
| 4 | 5 | 6 | 7 | 8 | f | | 4 | 5 | 6 | 7 | 8 | f |
T3 T3
|[a]| b | c | d | e | |[a]| b | c | d | e |
|---+---+---+---+---| |---+---+---+---+---|
| 1 |nul|nul|nul|-3 |
| 3 |nul|nul|-5 |nul|
答案 1 :(得分:1)
该解决方案适用于五列。 100列怎么样。你需要动态的T-SQL。
以下代码很长,分为4个部分。
第1部分 - 创建数据库,测试表和测试数据。
第2节 - 我的用户定义函数用于分隔列列表和Jeff Moden的拆分函数。
第3节 - 动态T-SQL,假设第一列是键,最后一列是标志。使用EXCEPT命令查找行差异。
第4节 - 动态T-SQL,将T1中的第2列与T2中的第2列与case语句进行比较。所有专栏继续。只插入有差异的行的T3。
-- THIS CODE WILL WORK FOR A DYNAMIC LIST OF COLUMNS, NOT JUST 4! --
-- 1 - Create test tables w/data
-- the master db
use master;
go
-- create test database
create database test;
go
-- use test
use test;
go
-- create table 1
if (OBJECT_ID('t1') <> 0) drop table t1;
go
create table t1
( key1 int, col1 int, col2 int, col3 varchar(16), col4 varchar(16) );
go
-- create table 2
if (OBJECT_ID('t2') <> 0) drop table t2;
go
create table t2
( key1 int, col1 int, col2 int, col3 varchar(16), col4 varchar(16), flag1 int default 0);
go
-- create table 3
if (OBJECT_ID('t3') <> 0) drop table t3;
go
create table t3
( key1 int, col1 int, col2 int, col3 varchar(16), col4 varchar(16) );
go
-- Add 5 rows to t1
insert into t1 values (1, 2, 4, 'A', 'B');
insert into t1 values (2, 4, 8, 'C', 'D');
insert into t1 values (3, 6, 12, 'E', 'F');
insert into t1 values (4, 8, 16, 'G', 'H');
insert into t1 values (5, 10, 20, 'I', 'J');
select * from t1;
-- Add 5 rows to t2
insert into t2 (key1, col1, col2, col3, col4) values (1, 2, 4, 'A', 'B');
insert into t2 (key1, col1, col2, col3, col4) values (2, 4, 8, 'C', 'D');
insert into t2 (key1, col1, col2, col3, col4) values (3, 6, 12, 'E', 'F');
insert into t2 (key1, col1, col2, col3, col4) values (4, 8, 16, 'G', 'H');
insert into t2 (key1, col1, col2, col3, col4) values (5, 10, 20, 'I', 'K');
select * from t2;
--
-- 2A - Declare helper function for column name list
--
-- use test
use test;
go
-- remove function if it exists
if (OBJECT_ID('dbo.get_column_list') <> 0)
drop function get_column_list;
go
-- create new function
create function get_column_list (@schema_name sysname, @table_name sysname, @del_value varchar(10) = ',') returns varchar(max)
as
begin
-- nothing to do
if (@table_name is null) return null;
-- misc variables
declare @list varchar(max) = '';
-- select the changed items
select
@list += c.name + @del_value
from
sys.schemas s join sys.objects o on s.schema_id = o.schema_id
join sys.columns c on o.object_id = c.object_id
where
o.type = 'u' and
s.name = @schema_name and
o.name = @table_name
order by c.column_id;
-- remove last delimiter
select @list = substring(@list, 1, len(@list) - len(@del_value));
-- return a list
return @list
end;
go
--
-- 2B - spliter function from jeff moden
--
-- http://www.sqlservercentral.com/articles/Tally+Table/72993/
-- You download and install as TVF in [TEST] database
--
-- 3 - Find row differences using except
--
-- declare/initialize variables
declare @stmt1 varchar(max) = '';
-- column lists
declare @list1 varchar(max) = dbo.get_column_list ('dbo', 't1', ', ');
declare @list2 varchar(max) = dbo.get_column_list ('dbo', 't2', ', ');
-- key (first), flag (last)
declare @key1 sysname = left(@list1, charindex(',', @list1, 1) - 1);
declare @key2 sysname = reverse(left(reverse(@list2), charindex(',', reverse(@list2), 1) - 2));
-- make dynamic sql
select @stmt1 = '(select ' + @list1 + ' from t2 except select ' + @list1 + ' from t1) as d1';
select @stmt1 = 'update t2 set ' + @key2 + ' = 1 where ' + @key1 + ' in (select d1.' + @key1 + ' from ' + @stmt1 + ');';
-- debug line
--print @stmt1;
-- execute the sql
exec (@stmt1);
go
--
-- 4 - Find the columns differences using case
--
-- declare/initialize variables
declare @stmt varchar(max) = '';
-- column list
declare @list varchar(max) = dbo.get_column_list ('dbo', 't2', ',');
-- key (first), flag (last)
declare @key1 sysname = left(@list, charindex(',', @list, 1) - 1);
declare @key2 sysname = reverse(left(reverse(@list), charindex(',', reverse(@list), 1) - 1));
-- select the changed items (skip key & flag)
select
@stmt += 'case when s.' + Item + ' = t.' + Item + ' then null else t.' + Item + ' end as val_' + Item + ', '
from
DelimitedSplit8K (@list, ',')
where
ItemNumber not in
(
select min(ItemNumber) as skip_vals from DelimitedSplit8K (@list, ',')
union
select max(ItemNumber) as skip_vals from DelimitedSplit8K (@list, ',')
);
-- complete the statement
select @stmt = 'insert into t3 select t.' + @key1 + ',' + substring(@stmt, 1, len(@stmt) - 1) + ' from t1 as s join t2 as t on s.' + @key1 + ' = t.' + @key1 + ' where t.' + @key2 + ' = 1 ';
-- debug line
--print @stmt;
-- execute the sql
exec (@stmt);
go