প্রচুর পরিমাণে ডেটার জন্য সারিগুলির মধ্যে পার্থক্য বিশদ বিশদ অনুসন্ধান করা ery


15

আমার> 300 টি কলাম সহ প্রতিটি বড় বড় টেবিল রয়েছে। আমি যে অ্যাপ্লিকেশনটি ব্যবহার করছি তা সেকেন্ডারি সারণীতে বর্তমান সারিটির একটি অনুলিপি তৈরি করে পরিবর্তিত সারিগুলির "সংরক্ষণাগারগুলি" তৈরি করে।

একটি তুচ্ছ উদাহরণ বিবেচনা করুন:

CREATE TABLE dbo.bigtable
(
  UpdateDate datetime,
  PK varchar(12) PRIMARY KEY,
  col1 varchar(100),
  col2 int,
  col3 varchar(20),
  .
  .
  .
  colN datetime
);

সংরক্ষণাগার সারণী:

CREATE TABLE dbo.bigtable_archive
(
  UpdateDate datetime,
  PK varchar(12) NOT NULL,
  col1 varchar(100),
  col2 int,
  col3 varchar(20),
  .
  .
  .
  colN datetime
);

কোনও আপডেট কার্যকর হওয়ার আগে dbo.bigtable, সারিটির একটি অনুলিপি তৈরি করা হয় dbo.bigtable_archive, তারপরে dbo.bigtable.UpdateDateবর্তমান তারিখের সাথে আপডেট করা হয়।

সুতরাং UNIONদুটি টেবিলকে একত্রে & গোষ্ঠীভুক্তকরণ দ্বারা PKআদেশিত হলে পরিবর্তনের একটি সময়রেখা তৈরি করে UpdateDate

আমি নিম্নলিখিত বিন্যাসে সারি দ্বারা UpdateDateশ্রেণিবদ্ধ, সারিগুলির মধ্যে পার্থক্যগুলির বিশদ সম্পর্কিত একটি প্রতিবেদন তৈরি করতে চাই PK:

PK,   UpdateDate,  ColumnName,  Old Value,   New Value

Old Valueএবং New Valueএটিতে প্রাসঙ্গিক কলামগুলি VARCHAR(MAX)(কোনও জড়িত নেই TEXTবা BYTEকলামগুলি থাকতে পারে) হতে পারে, কারণ আমি নিজেরাই মানগুলির কোনও পোস্ট-প্রসেসিং করার প্রয়োজন নেই।

প্রোগ্রামটিমে কোয়েরি উত্পন্ন না করেই এই মুহুর্তে আমি প্রচুর পরিমাণে কলামের জন্য এটি করার একটি বুদ্ধিমান উপায়ের কথা ভাবতে পারি না - আমাকে এটি করতে হতে পারে।

প্রচুর ধারণাগুলিতে উন্মুক্ত, সুতরাং আমি 2 দিন পরে প্রশ্নে একটি অনুগ্রহ যুক্ত করব।

উত্তর:


15

এটি দেখতে সুন্দর দেখাচ্ছে না, বিশেষত 300 টিরও বেশি কলাম এবং অপ্রাপ্যতা দেওয়া থাকলেও LAGএটি অত্যধিক ভাল পারফর্ম করতে পারে না, তবে কিছুটা শুরু করার সাথে সাথে আমি নিম্নলিখিত পদ্ধতির চেষ্টা করব:

  • UNION দুটি টেবিল।
  • সম্মিলিত সেটে প্রতিটি পিকে জন্য আর্কাইভ টেবিল থেকে এর আগের "অবতার" পান (নীচের প্রয়োগটি OUTER APPLY+ TOP (1)দরিদ্র ব্যক্তির হিসাবে ব্যবহার করে LAG)।
  • প্রতিটি ডেটা কলাম কাস্ট varchar(max)করুন এবং তাদের জোড়া হিসাবে আনবিভোট করুন, যেমন বর্তমান এবং পূর্ববর্তী মান ( CROSS APPLY (VALUES ...)এই ক্রিয়াকলাপের জন্য ভাল কাজ করে)।
  • পরিশেষে, প্রতিটি জোড়ের মান একে অপরের থেকে পৃথক কিনা তার ভিত্তিতে ফলাফলগুলি ফিল্টার করুন।

উপরের লেনদেন-এসকিউএল হিসাবে আমি এটি দেখছি:

WITH
  Combined AS
  (
    SELECT * FROM dbo.bigtable
    UNION ALL
    SELECT * FROM dbo.bigtable_archive
  ) AS derived,
  OldAndNew AS
  (
    SELECT
      this.*,
      OldCol1 = last.Col1,
      OldCol2 = last.Col2,
      ...
    FROM
      Combined AS this
      OUTER APPLY
      (
        SELECT TOP (1)
          *
        FROM
          dbo.bigtable_archive
        WHERE
          PK = this.PK
          AND UpdateDate < this.UpdateDate
        ORDER BY
          UpdateDate DESC
      ) AS last
  )
SELECT
  t.PK,
  t.UpdateDate,
  x.ColumnName,
  x.OldValue,
  x.NewValue
FROM
  OldAndNew AS t
  CROSS APPLY
  (
    VALUES
    ('Col1', CAST(t.OldCol1 AS varchar(max), CAST(t.Col1 AS varchar(max))),
    ('Col2', CAST(t.OldCol2 AS varchar(max), CAST(t.Col2 AS varchar(max))),
    ...
  ) AS x (ColumnName, OldValue, NewValue)
WHERE
  NOT EXISTS (SELECT x.OldValue INTERSECT x.NewValue)
ORDER BY
  t.PK,
  t.UpdateDate,
  x.ColumnName
;

13

আপনি যদি কোনও টেম্প টেবিলটিতে ডেটা আনবিভোট করেন

create table #T
(
  PK varchar(12) not null,
  UpdateDate datetime not null,
  ColumnName nvarchar(128) not null,
  Value varchar(max),
  Version int not null
);

আপনি নিজের সাথে যোগ দেওয়ার সাথে নতুন এবং পুরানো মান সন্ধান করতে সারিগুলির সাথে মিল রাখতে পারেন PK, ColumnNameএবং Version = Version + 1

অবশ্যই খুব সুন্দর অংশটি নয়, দুটি বেস টেবিল থেকে টেম্প টেবিলটিতে আপনার 300 টি কলামের আনপিবট করা।

জিনিসগুলিকে কম বিশ্রী করে তুলতে এক্সএমএলটিকে উদ্ধার করতে।

টেবিলটিতে কী প্রকৃত কলাম রয়েছে তা অপরিবর্তিত থাকবে তা জেনে এক্সএমএল দিয়ে ডেটা আনপিভট করা সম্ভব। কলামের নামগুলি অবশ্যই এক্সএমএলে এলিমেন্টের নাম হিসাবে বৈধ হতে হবে বা এটি ব্যর্থ হবে।

ধারণাটি হ'ল প্রতিটি সারির জন্য একটি সারির জন্য সমস্ত মান রয়েছে X

select bt.PK,
       bt.UpdateDate,
       (select bt.* for xml path(''), elements xsinil, type) as X
from dbo.bigtable as bt;
<UpdateDate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2001-01-03T00:00:00</UpdateDate>
<PK xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">PK1</PK>
<col1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">c1_1_3</col1>
<col2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">3</col2>
<col3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
<colN xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2001-01-03T00:00:00</colN>

elements xsinilএর সাথে কলামগুলির জন্য উপাদান তৈরি করতে হবে NULL

এক্সএমএল এর পরে nodes('*') প্রতিটি কলামের জন্য একটি সারি ব্যবহার করে local-name(.)উপাদান নামটি text()পেতে এবং মান পেতে ব্যবহার করে ছাঁটা যায়।

  select C1.PK,
         C1.UpdateDate,
         T.X.value('local-name(.)', 'nvarchar(128)') as ColumnName,
         T.X.value('text()[1]', 'varchar(max)') as Value
  from C1
    cross apply C1.X.nodes('row/*') as T(X)

নীচে সম্পূর্ণ সমাধান। নোট যে Versionবিপরীত হয়। 0 = শেষ সংস্করণ।

create table #X
(
  PK varchar(12) not null,
  UpdateDate datetime not null,
  Version int not null,
  RowData xml not null
);

create table #T
(
  PK varchar(12) not null,
  UpdateDate datetime not null,
  ColumnName nvarchar(128) not null,
  Value varchar(max),
  Version int not null
);


insert into #X(PK, UpdateDate, Version, RowData)
select bt.PK,
       bt.UpdateDate,
       0,
       (select bt.* for xml path(''), elements xsinil, type)
from dbo.bigtable as bt
union all
select bt.PK,
       bt.UpdateDate,
       row_number() over(partition by bt.PK order by bt.UpdateDate desc),
       (select bt.* for xml path(''), elements xsinil, type)
from dbo.bigtable_archive as bt;

with C as 
(
  select X.PK,
         X.UpdateDate,
         X.Version,
         T.C.value('local-name(.)', 'nvarchar(128)') as ColumnName,
         T.C.value('text()[1]', 'varchar(max)') as Value
  from #X as X
    cross apply X.RowData.nodes('*') as T(C)
)
insert into #T (PK, UpdateDate, ColumnName, Value, Version)
select C.PK,
       C.UpdateDate,
       C.ColumnName,
       C.Value,
       C.Version
from C 
where C.ColumnName not in (N'PK', N'UpdateDate');

/*
option (querytraceon 8649);

The above query might need some trick to go parallel.
For the testdata I had on my machine exection time is 16 seconds vs 2 seconds
https://sqlkiwi.blogspot.com/2011/12/forcing-a-parallel-query-execution-plan.html
http://dataeducation.com/next-level-parallel-plan-forcing-an-alternative-to-8649/

*/

select New.PK,
       New.UpdateDate,
       New.ColumnName,
       Old.Value as OldValue,
       New.Value as NewValue
from #T as New
  left outer join #T as Old
    on Old.PK = New.PK and
       Old.ColumnName = New.ColumnName and
       Old.Version = New.Version + 1;

6

আমি আপনাকে অন্য পদ্ধতির পরামর্শ দেব।

যদিও আপনি বর্তমান অ্যাপ্লিকেশনটি পরিবর্তন করতে পারবেন না, হতে পারে আপনি ডাটাবেসের আচরণ পরিবর্তন করতে পারেন।

যদি সম্ভব হয় তবে আমি বর্তমান সারণিতে দুটি ট্রিগার যুক্ত করব।

Dbo.bigtable_archive- এ একটি INSET OF INSERT যা নতুন রেকর্ডটি কেবলমাত্র এটি উপস্থিত না থাকলে কেবল যোগ করে।

CREATE TRIGGER dbo.IoI_BTA
ON dbo.bigtable_archive
INSTEAD OF INSERT
AS
BEGIN
    IF NOT EXISTs(SELECT 1 
                  FROM dbo.bigtable_archive bta
                  INNER JOIN inserted i
                  ON  bta.PK = i.PK
                  AND bta.UpdateDate = i.UpdateDate)
    BEGIN
        INSERT INTO dbo.bigtable_archive
        SELECT * FROM inserted;
    END
END

এবং বিগ টেবিলের পরে একটি ইন্টারসার্ট ট্রিগার যা ঠিক একই কাজটি করে তবে বিগ টেবলের ডেটা ব্যবহার করে।

CREATE TRIGGER dbo.IoI_BT
ON dbo.bigtable
AFTER INSERT
AS
BEGIN
    IF NOT EXISTS(SELECT 1 
                  FROM dbo.bigtable_archive bta
                  INNER JOIN inserted i
                  ON  bta.PK = i.PK
                  AND bta.UpdateDate = i.UpdateDate)
    BEGIN
        INSERT INTO dbo.bigtable_archive
        SELECT * FROM inserted;
    END
END

ঠিক আছে, আমি এই প্রাথমিক মানগুলি সহ এখানে একটি ছোট উদাহরণ স্থাপন করেছি :

SELECT * FROM bigtable;
SELECT * FROM bigtable_archive;
আপডেটডেট | পিকে | কল 1 | কল 2 | col3
: ------------------ | : - | : --- | ---: | : ---
02/01/2017 00:00:00 | এবিসি | সি 3 | 1 | গ 1  

আপডেটডেট | পিকে | কল 1 | কল 2 | col3
: ------------------ | : - | : --- | ---: | : ---
01/01/2017 00:00:00 | এবিসি | সি 1 | 1 | গ 1  

এখন আপনার bigtable_archive মধ্যে tোকানো উচিত bigtable থেকে সমস্ত মুলতুবি রেকর্ড।

INSERT INTO bigtable_archive
SELECT *
FROM   bigtable
WHERE  UpdateDate >= '20170102';
SELECT * FROM bigtable_archive;
GO
আপডেটডেট | পিকে | কল 1 | কল 2 | col3
: ------------------ | : - | : --- | ---: | : ---
01/01/2017 00:00:00 | এবিসি | সি 1 | 1 | গ 1  
02/01/2017 00:00:00 | এবিসি | সি 3 | 1 | গ 1  

এখন, পরের বার অ্যাপ্লিকেশনটি bigtable_archive টেবিলটিতে একটি রেকর্ড toোকানোর চেষ্টা করবে, ট্রিগারগুলি উপস্থিত থাকলে এটি সনাক্ত করবে এবং সন্নিবেশটি এড়ানো হবে।

INSERT INTO dbo.bigtable_archive VALUES('20170102', 'ABC', 'C3', 1, 'C1');
GO
SELECT * FROM bigtable_archive;
GO
আপডেটডেট | পিকে | কল 1 | কল 2 | col3
: ------------------ | : - | : --- | ---: | : ---
01/01/2017 00:00:00 | এবিসি | সি 1 | 1 | গ 1  
02/01/2017 00:00:00 | এবিসি | সি 3 | 1 | গ 1  

স্পষ্টতই এখন আপনি কেবল সংরক্ষণাগার সারণিকে জিজ্ঞাসা করে পরিবর্তনের সময়রেখা পেতে পারেন। এবং অ্যাপ্লিকেশন কখনই বুঝতে পারবে না যে কোনও ট্রিগার চুপচাপ theাকনার নিচে কাজ করছে।

এখানে ডিবিফিডল


4

ওয়ার্কিং প্রস্তাবনা, ডাব্লু / কিছু নমুনা ডেটা, @ রেক্সটেস্টার: বিগ টেবিল আনপিবট পাওয়া যাবে


অপারেশনের সংক্ষিপ্তসার:

1 - আনপিবট অপারেশনের জন্য আমাদের কলাম তালিকাগুলি গতিশীলভাবে জেনারেটর জন্য সাইকোলোমগুলি এবং এক্সএমএল ব্যবহার করুন; সমস্ত মানগুলি ভারচারে (সর্বাধিক) রূপান্তরিত হবে, ডাব্লু / এনএইউএল স্ট্রিংকে 'নুল' রূপান্তরিত করা হবে (এই উত্সটি ইম্পিভট স্কিপিং নুল মান সহ সমস্যা সমাধান করবে)

2 - # কলামগুলি টেম্প টেবিলের মধ্যে ডেবি আনপিবট করার জন্য একটি গতিশীল ক্যোয়ারী তৈরি করুন

  • কেন একজন টেম্প টেবিল বনাম কোটে (মাধ্যমে সঙ্গে দফা)? প্রচুর পরিমাণে ডেটা এবং কোনও সিটিই কোনও ব্যবহারযোগ্য সূচক / হ্যাশিং স্কিমের সাথে স্ব-যোগদানের জন্য সম্ভাব্য পারফরম্যান্স ইস্যুতে সম্পর্কিত; একটি টেম্প টেবিলটি এমন একটি সূচক তৈরির অনুমতি দেয় যা স্ব-যোগদানের ক্ষেত্রে পারফরম্যান্সকে উন্নত করা উচিত [ স্লো সিটিই স্ব-যোগদান দেখুন ]
  • পিকে + কলনেম + আপডেটডেটের ক্রমে ডেটা # কলামগুলিতে লেখা হয়, যা আমাদের সন্নিহিত সারিগুলিতে পিকে / কলনেম মান সংরক্ষণ করতে দেয়; একটি পরিচয় কলাম ( মুক্তি ) আমাদের পর পরের সারিগুলিকে স্লাইড = মুক্তি + 1 এর মাধ্যমে স্ব-যোগদানের অনুমতি দেয়

3 - পছন্দসই আউটপুট জেনারেট করতে # টেম্প টেবিলের একটি স্ব যোগদান যোগদান করুন

রেক্সটেসটার থেকে কাটিং-এন-পেস্টিং ...

কিছু নমুনা ডেটা এবং আমাদের # কলামের টেবিল তৈরি করুন:

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
;

এবং ফলাফল:

এখানে চিত্র বর্ণনা লিখুন

দ্রষ্টব্য: ক্ষমা চাই ... একটি কোড ব্লকে রেক্সটেসটার আউটপুট কাট-এন-পেস্ট করার সহজ উপায় বের করতে পারেনি। আমি পরামর্শ খোলা।


সম্ভাব্য সমস্যা / উদ্বেগ:

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 কলামের নাম সহ)


1

এই পদ্ধতির পরিবর্তনগুলি পেতে একটি স্ক্যুয়াল তৈরি করতে গতিশীল ক্যোয়ারি ব্যবহার করা হয়। এসপি একটি টেবিল এবং স্কিমা নাম নেয় এবং আপনার আউটপুটটি দেয়।

অনুমানগুলি হ'ল পিকে এবং আপডেটডেট কলামগুলি সমস্ত সারণীতে উপস্থিত রয়েছে। এবং সমস্ত সংরক্ষণাগার সারণীতে মূল টেবিলনাম + "_আরচাইভ" ফর্ম্যাট রয়েছে ..

এনবি: আমি পারফরম্যান্সের জন্য এটি পরীক্ষা করে দেখিনি।

নোট: যেহেতু এটি গতিশীল স্কয়ার ব্যবহার করে, তাই আমার নিরাপত্তা / স্কোয়েল ইনজেকশন সম্পর্কে সতর্কতা যুক্ত করা উচিত। এসপিতে অ্যাক্সেসকে সীমাবদ্ধ করুন এবং এসকিউএল ইনজেকশন প্রতিরোধ করতে অন্যান্য বৈধতা যুক্ত করুন।

    CREATE proc getTableChanges
    @schemaname  varchar(255),
    @tableName varchar(255)
    as

    declare @strg nvarchar(max), @colNameStrg nvarchar(max)='', @oldValueString nvarchar(max)='', @newValueString nvarchar(max)=''

    set @strg = '
    with cte as (

    SELECT  * , ROW_NUMBER() OVER(partition by PK ORDER BY UpdateDate) as RowNbr
    FROM    (

        SELECT  *
        FROM    [' + @schemaname + '].[' + @tableName + ']

        UNION

        SELECT  *
        FROM    [' + @schemaname + '].[' + @tableName + '_archive]

        ) a

    )
    '


    SET @strg = @strg + '

    SELECT  a.pk, a.updateDate, 
    CASE '

    DECLARE @colName varchar(255)
    DECLARE cur CURSOR FOR
        SELECT  COLUMN_NAME
        FROM    INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_SCHEMA = @schemaname
        AND TABLE_NAME = @tableName
        AND COLUMN_NAME NOT IN ('PK', 'Updatedate')

    OPEN cur
    FETCH NEXT FROM cur INTO @colName 

    WHILE @@FETCH_STATUS = 0
    BEGIN

        SET @colNameStrg  = @colNameStrg  + ' when a.' + @colName + ' <> b.' + @colName + ' then ''' + @colName + ''' '
        SET @oldValueString = @oldValueString + ' when a.' + @colName + ' <> b.' + @colName + ' then cast(a.' + @colName + ' as varchar(max))'
        SET @newValueString = @newValueString + ' when a.' + @colName + ' <> b.' + @colName + ' then cast(b.' + @colName + ' as varchar(max))'


    FETCH NEXT FROM cur INTO @colName 
    END

    CLOSE cur
    DEALLOCATE cur


    SET @colNameStrg = @colNameStrg  + '    END as ColumnChanges '
    SET @oldValueString = 'CASE ' + @oldValueString + ' END as OldValue'
    SET @newValueString = 'CASE ' + @newValueString + ' END as NewValue'

    SET @strg = @strg + @colNameStrg + ',' + @oldValueString + ',' + @newValueString

    SET @strg = @strg + '
        FROM    cte a join cte b on a.PK = b.PK and a.RowNbr + 1 = b.RowNbr 
        ORDER BY  a.pk, a.UpdateDate
    '

    print @strg

    execute sp_executesql @strg


    go

নমুনা কল:

exec getTableChanges 'dbo', 'bigTable'

যদি আমি ভুল না হয়ে থাকি তবে এটি ঠিক একই সারিতে করা একাধিক পরিবর্তনগুলি ধরে না?
মিকেল এরিকসন

এটি ঠিক .. একই সময়ে আপডেট হওয়া একাধিক কলাম ক্যাপচার করা হবে না। পরিবর্তন সহ প্রথম কলামটি ক্যাপচার করা হবে।
ধর্মেন্দ্র কুমার 'ডেকে'

1

আমি আমার উদাহরণে অ্যাডভেঞ্চার ওয়ার্কস ২০১২`, প্রোডাকশন.প্রডাক্টকস্ট হিস্ট্রি এবং প্রোডাকশন.প্রডাক্টলিস্টপ্রাইস হিস্টরি ব্যবহার করছি। এটি নিখুঁত ইতিহাসের সারণীর উদাহরণ হতে পারে না, "তবে স্ক্রিপ্টটি আকাঙ্ক্ষার ফলাফল এবং সঠিক আউটপুট একসাথে রাখতে সক্ষম"।

     DECLARE @sql NVARCHAR(MAX)
    ,@columns NVARCHAR(Max)
    ,@table VARCHAR(200) = 'ProductCostHistory'
    ,@Schema VARCHAR(200) = 'Production'
    ,@Archivecolumns NVARCHAR(Max)
    ,@ColForUnpivot NVARCHAR(Max)
    ,@ArchiveColForUnpivot NVARCHAR(Max)
    ,@PKCol VARCHAR(200) = 'ProductID'
    ,@UpdatedCol VARCHAR(200) = 'modifiedDate'
    ,@Histtable VARCHAR(200) = 'ProductListPriceHistory'
SELECT @columns = STUFF((
            SELECT ',CAST(p.' + QUOTENAME(column_name) + ' AS VARCHAR(MAX)) AS ' + QUOTENAME(column_name)
            FROM information_schema.columns
            WHERE table_name = @table
                AND column_name NOT IN (
                    @PKCol
                    ,@UpdatedCol
                    )
            ORDER BY ORDINAL_POSITION
            FOR XML PATH('')
            ), 1, 1, '')
    ,@Archivecolumns = STUFF((
            SELECT ',CAST(p1.' + QUOTENAME(column_name) + ' AS VARCHAR(MAX)) AS ' + QUOTENAME('A_' + column_name)
            FROM information_schema.columns
            WHERE table_name = @Histtable
                AND column_name NOT IN (
                    @PKCol
                    ,@UpdatedCol
                    )
            ORDER BY ORDINAL_POSITION
            FOR XML PATH('')
            ), 1, 1, '')
    ,@ColForUnpivot = STUFF((
            SELECT ',' + QUOTENAME(column_name)
            FROM information_schema.columns
            WHERE table_name = @table
                AND column_name NOT IN (
                    @PKCol
                    ,@UpdatedCol
                    )
            ORDER BY ORDINAL_POSITION
            FOR XML PATH('')
            ), 1, 1, '')
    ,@ArchiveColForUnpivot = STUFF((
            SELECT ',' + QUOTENAME('A_' + column_name)
            FROM information_schema.columns
            WHERE table_name = @Histtable
                AND column_name NOT IN (
                    @PKCol
                    ,@UpdatedCol
                    )
            ORDER BY ORDINAL_POSITION
            FOR XML PATH('')
            ), 1, 1, '')

--SELECT @columns   ,@Archivecolumns    ,@ColForUnpivot
SET @sql = N' 
    SELECT ' + @PKCol + ', ColumnName,
            OldValue,NewValue,' + @UpdatedCol + '
    FROM    (  
    SELECT p.' + @PKCol + '
        ,p.' + @UpdatedCol + '
        ,' + @columns + '
        ,' + @Archivecolumns + '
    FROM ' + @Schema + '.' + @table + ' p
    left JOIN ' + @Schema + '.' + @Histtable + ' p1 ON p.' + @PKCol + ' = p1.' + @PKCol + '

  ) t
    UNPIVOT (
        OldValue
        FOR ColumnName in (' + @ColForUnpivot + ')
    ) up

     UNPIVOT (
        NewValue
        FOR ColumnName1 in (' + @ArchiveColForUnpivot + ')
    ) up1

--print @sql
EXEC (@sql)

এখানে অভ্যন্তরীণ সিলেক্ট ক্যোয়ারিতে p কে প্রধান সারণী এবং p1 কে ইতিহাস সারণী হিসাবে বিবেচনা করুন un

আমার স্ক্রিপ্টটি বুঝতে আপনি আরও কম কলামের নাম সহ অন্য কোনও টেবিলের নাম নিতে পারেন nyএখন কোনও বিবরণ আমাকে পিং করতে হবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.