वर्किंग प्रपोजल, w / कुछ सैंपल डेटा, @ rextester: bigtable unpivot से मिल सकते हैं
ऑपरेशन का सार:
1 - unpivot ऑपरेशन के लिए हमारे कॉलम सूचियों को गतिशील रूप से उत्पन्न करने के लिए syscolumns और xml का उपयोग करें ; सभी मानों को varchar (अधिकतम), w / NULL में बदलकर स्ट्रिंग 'NULL' में परिवर्तित कर दिया जाएगा (यह पतों को जारी करने के साथ NULL मानों को जारी करता है)
2 - #columns अस्थायी तालिका में डेटा को अनपाइव करने के लिए एक गतिशील क्वेरी उत्पन्न करें
- क्यों एक अस्थायी तालिका बनाम सीटीई (के माध्यम से) खंड के साथ )? डेटा की एक बड़ी मात्रा के लिए संभावित प्रदर्शन के मुद्दे और एक सीटीई स्व-शामिल होने के साथ कोई प्रयोग करने योग्य सूचकांक / हैशिंग योजना; एक अस्थायी तालिका एक इंडेक्स के निर्माण की अनुमति देती है, जिसमें सेल्फ-ज्वाइन पर प्रदर्शन में सुधार होना चाहिए [ धीमी CTE सेल्फ ज्वाइन देखें ]
- डेटा को PK + ColName + UpdateDate क्रम में #columns को लिखा गया है, जिससे हम आसन्न पंक्तियों में PK / Colname मानों को संग्रहीत कर सकते हैं; एक पहचान स्तंभ ( छुटकारा ) हमें छुटकारा = 1 + के माध्यम से इन लगातार पंक्तियों में शामिल होने की अनुमति देता है
3 - वांछित आउटपुट जेनरेट करने के लिए # टेबल का एक सेल्फ ज्वाइन करें
कटिंग-एन-चिपकाने से rextester ...
कुछ नमूना डेटा और हमारी #columns तालिका बनाएँ:
CREATE TABLE dbo.bigtable
(UpdateDate datetime not null
,PK varchar(12) not null
,col1 varchar(100) null
,col2 int null
,col3 varchar(20) null
,col4 datetime null
,col5 char(20) null
,PRIMARY KEY (PK)
);
CREATE TABLE dbo.bigtable_archive
(UpdateDate datetime not null
,PK varchar(12) not null
,col1 varchar(100) null
,col2 int null
,col3 varchar(20) null
,col4 datetime null
,col5 char(20) null
,PRIMARY KEY (PK, UpdateDate)
);
insert into dbo.bigtable values ('20170512', 'ABC', NULL, 6, 'C1', '20161223', 'closed')
insert into dbo.bigtable_archive values ('20170427', 'ABC', NULL, 6, 'C1', '20160820', 'open')
insert into dbo.bigtable_archive values ('20170315', 'ABC', NULL, 5, 'C1', '20160820', 'open')
insert into dbo.bigtable_archive values ('20170212', 'ABC', 'C1', 1, 'C1', '20160820', 'open')
insert into dbo.bigtable_archive values ('20170109', 'ABC', 'C1', 1, 'C1', '20160513', 'open')
insert into dbo.bigtable values ('20170526', 'XYZ', 'sue', 23, 'C1', '20161223', 're-open')
insert into dbo.bigtable_archive values ('20170401', 'XYZ', 'max', 12, 'C1', '20160825', 'cancel')
insert into dbo.bigtable_archive values ('20170307', 'XYZ', 'bob', 12, 'C1', '20160825', 'cancel')
insert into dbo.bigtable_archive values ('20170223', 'XYZ', 'bob', 12, 'C1', '20160820', 'open')
insert into dbo.bigtable_archive values ('20170214', 'XYZ', 'bob', 12, 'C1', '20160513', 'open')
;
create table #columns
(rid int identity(1,1)
,PK varchar(12) not null
,UpdateDate datetime not null
,ColName varchar(128) not null
,ColValue varchar(max) null
,PRIMARY KEY (rid, PK, UpdateDate, ColName)
);
समाधान की हिम्मत:
declare @columns_max varchar(max),
@columns_raw varchar(max),
@cmd varchar(max)
select @columns_max = stuff((select ',isnull(convert(varchar(max),'+name+'),''NULL'') as '+name
from syscolumns
where id = object_id('dbo.bigtable')
and name not in ('PK','UpdateDate')
order by name
for xml path(''))
,1,1,''),
@columns_raw = stuff((select ','+name
from syscolumns
where id = object_id('dbo.bigtable')
and name not in ('PK','UpdateDate')
order by name
for xml path(''))
,1,1,'')
select @cmd = '
insert #columns (PK, UpdateDate, ColName, ColValue)
select PK,UpdateDate,ColName,ColValue
from
(select PK,UpdateDate,'+@columns_max+' from bigtable
union all
select PK,UpdateDate,'+@columns_max+' from bigtable_archive
) p
unpivot
(ColValue for ColName in ('+@columns_raw+')
) as unpvt
order by PK, ColName, UpdateDate'
--select @cmd
execute(@cmd)
--select * from #columns order by rid
;
select c2.PK, c2.UpdateDate, c2.ColName as ColumnName, c1.ColValue as 'Old Value', c2.ColValue as 'New Value'
from #columns c1,
#columns c2
where c2.rid = c1.rid + 1
and c2.PK = c1.PK
and c2.ColName = c1.ColName
and isnull(c2.ColValue,'xxx') != isnull(c1.ColValue,'xxx')
order by c2.UpdateDate, c2.PK, c2.ColName
;
और परिणाम:
नोट: माफी ... कोड कोड में rextester आउटपुट को कट-एन-पेस्ट करने का एक आसान तरीका समझ नहीं सका। मैं सुझाव के लिए खुला हूँ।
संभावित मुद्दे / चिंताएँ:
1 - डेटा को जेनेरिक वर्चर (अधिकतम) में परिवर्तित करने से डेटा परिशुद्धता का नुकसान हो सकता है, जिसका अर्थ है कि हम कुछ डेटा परिवर्तनों को याद कर सकते हैं; निम्नलिखित डेटाइम और फ्लोट जोड़े पर विचार करें, जब जेनेरिक 'वर्चर (अधिकतम)' में परिवर्तित / कास्ट किया जाता है, तो अपनी परिशुद्धता खो देते हैं (यानी, परिवर्तित मान समान हैं):
original value varchar(max)
------------------- -------------------
06/10/2017 10:27:15 Jun 10 2017 10:27AM
06/10/2017 10:27:18 Jun 10 2017 10:27AM
234.23844444 234.238
234.23855555 234.238
29333488.888 2.93335e+007
29333499.999 2.93335e+007
जबकि डेटा परिशुद्धता को बनाए रखा जा सकता है, इसके लिए थोड़ा और कोडिंग की आवश्यकता होगी (जैसे, स्रोत स्तंभ डेटाटिप्स के आधार पर कास्टिंग); अभी के लिए मैंने ओपी की सिफारिश के अनुसार जेनेरिक वर्चर (अधिकतम) के साथ छड़ी करने का विकल्प चुना है (और यह धारणा कि ओपी डेटा को अच्छी तरह से जानता है कि हम डेटा परिशुद्धता हानि के किसी भी मुद्दे में नहीं चलेंगे)।
2 - डेटा के वास्तव में बड़े सेटों के लिए हम कुछ सर्वर संसाधनों को उड़ाने का जोखिम उठाते हैं, चाहे वह अस्थायी स्पेस हो और / या कैश / मेमोरी हो; प्राथमिक मुद्दा डेटा विस्फोट से आता है जो एक अनप्राइवेट के दौरान होता है (उदाहरण के लिए, हम 1 पंक्ति और 302 डेटा डेटा से 300 पंक्तियों और 1200-1500 टुकड़े डेटा तक जाते हैं, जिसमें पीके और अपडेटडेट कॉलम, 300 कॉलम नाम की 300 प्रतियां शामिल हैं)