Advertisement
anchormodeling

Anchor Model Generator

Nov 15th, 2016
22,472
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
T-SQL 23.58 KB | None | 0 0
  1. /* -----------------------------------------------------------------------------------------------------------------------------------
  2.  
  3.     Script for automatically generating an Anchor model based on a normalized or dimensional model.
  4.  
  5.     VERSION HISTORY
  6.     2016-11-15  Lars Rönnbäck         CREATED
  7.     2016-11-17  Lars Rönnbäck         Merged features from the script made by Juan-José van der Linden.
  8.                                         Added metadata and descriptions, improved ties.
  9.     2016-11-29  Lars Rönnbäck         Added features suggested by Frederik Carlsson:
  10.                                         + Existing stats that are not FULLSCAN are updated.
  11.                                         + When determining knot identity a fill factor is respected.
  12.                                         + Historization of all, no, or only knotted attributes.
  13.                                         + Data length can be checked to avoid creating poor performing knots.
  14.                                         + Knot loading code is generated in the knot descriptions.
  15.                                         + Generate checksums if key length larger than 900 bytes.
  16.                                         + Add support for anchorizing views
  17.                                         + Made it possible to control validity tracking.
  18.                                         Foreign keys can be used instead of column names to find relationships.
  19.     2017-05-02  Lars Rönnbäck         Fix for other schemas than 'dbo'.
  20.     2017-05-05  Lars Rönnbäck         Knot loading code now excludes null values.
  21.  
  22.     LIMITATIONS
  23.     - Creates only binary ties.
  24.     - Does not handle composed primary keys.
  25.     - Skips self referencing ties.
  26.  
  27. -------------------------------------------------- VARIABLES CONTROLLING THE SCRIPT ----------------------------------------------- */
  28.  
  29. declare @tableName varchar(555) = null; -- null for all tables
  30. declare @schemaName varchar(555) = 'dbo'; -- null for all schemas
  31. declare @knotSize varchar(42) = 'smallint'; -- largest allowed data type for knots
  32. declare @fillFactor float = 0.6; -- knots that become filled to more than 60% are switched to a larger datatype
  33. declare @checkLengths bit = 1; -- controls if average data length should determine the existance of knots
  34. declare @timeRange varchar(42) = 'datetime'; -- default time range for historized constructs
  35. declare @historization char(1) = 'K'; -- historization options (K = knotted attributes, 0 = no attributes, * = all attributes)
  36. declare @metadataUsage varchar(5) = 'true'; -- whether to use metadata or not (true/false)
  37. declare @objectTypes varchar(555) = 'USER_TABLE'; -- this can be USER_TABLE and/or VIEW
  38. declare @trackValidity char(1) = 'T'; -- validity tracking options (T = only for ties, 0 = never, * = ties and anchors)
  39. declare @relationshipDetection char(1) = 'N'; -- options for finding relationships (F = foreign keys, N = column names, * = use both)
  40.  
  41. --------------------------------------------------------------------------------------------------------------------------------------
  42.  
  43. if OBJECT_ID('tempdb..#schema') is not null
  44. drop table #schema;
  45.  
  46. with mnemonics as (
  47.     select
  48.         o.object_id,
  49.         0 as column_id,
  50.         cast(
  51.             char(65 + (row_number() over (order by o.object_id) - 1) / 26) +
  52.             char(65 + (row_number() over (order by o.object_id) - 1) % 26)
  53.         as varchar(3)) as [mnemonic],
  54.         (row_number() over (order by o.object_id) - 1) as startIndex,
  55.         o.name,
  56.         s.name as schemaName
  57.     from -- select * from
  58.         sys.objects o
  59.     join
  60.         sys.schemas s
  61.     on
  62.         s.schema_id = o.schema_id
  63.     and
  64.         s.name = isnull(@schemaName, s.name)
  65.     where
  66.         @objectTypes like '%' + o.type_desc + '%'
  67.     union all
  68.     select
  69.         o.object_id,
  70.         isnull(c.column_id, 0) as column_id,
  71.         cast (
  72.             left(o.mnemonic, 1) +
  73.             char(65 + (o.startIndex + (row_number() over (order by o.object_id) - 1) / 26) % 26) +
  74.             char(65 + (row_number() over (order by o.object_id, c.column_id) - 1) % 26)
  75.         as varchar(3)) as [mnemonic],
  76.         o.startIndex,
  77.         c.name,
  78.         o.schemaName
  79.     from -- select * from
  80.         mnemonics o
  81.     join
  82.         sys.columns c
  83.     on
  84.         c.object_id = o.object_id
  85.     where
  86.         o.column_id = 0
  87. )
  88. select
  89.     object_id,
  90.     column_id,
  91.     mnemonic,
  92.     name,
  93.     schemaName,
  94.     cast(null as float) as [density],
  95.     cast(null as float) as [averageLength],
  96.     cast(null as varchar(555)) as [dataType],
  97.     cast(null as varchar(555)) as [dataRange],
  98.     cast(null as int) as [maxLength]
  99. into
  100.     #schema
  101. from
  102.     mnemonics
  103. where
  104.     @tableName is null
  105. or
  106.     @tableName = object_name(object_id);
  107.  
  108. update s
  109. set
  110.     s.[dataType] = d.name,
  111.     s.[dataRange] = d.name +
  112.         -- select * from sys.columns where system_type_id = (select system_type_id from sys.types where name = 'time')
  113.         case
  114.             when d.name in ('varbinary', 'varchar', 'nvarchar', 'char', 'nchar')
  115.             then '(' + cast(c.max_length as varchar(10)) + ')'
  116.             when d.name in ('numeric', 'decimal')
  117.             then '(' + cast(c.precision as varchar(10)) + ',' + cast(c.scale as varchar(10)) + ')'
  118.             when d.name in ('time')
  119.             then '(' + cast(c.precision as varchar(10)) + ')'
  120.             else ''
  121.         end,
  122.     s.[maxLength] = c.max_length
  123. from
  124.     #schema s
  125. join
  126.     sys.columns c
  127. on
  128.     c.object_id = s.object_id
  129. and
  130.     c.column_id = s.column_id
  131. join -- select * from
  132.     sys.types d
  133. on
  134.     d.system_type_id = c.system_type_id
  135.  
  136. declare @object_id int;
  137. declare @column_id int;
  138. declare @mnemonic char(3);
  139. declare @name varchar(555);
  140.  
  141. if OBJECT_ID('tempdb..#densities') is not null
  142. drop table #densities;
  143.  
  144. create table #densities (
  145.     [All density] float,
  146.     [Average Length] float,
  147.     [Columns] varchar(555)
  148. );
  149.  
  150. if OBJECT_ID('tempdb..#header') is not null
  151. drop table #header;
  152.  
  153. create table #header (
  154.     [Name] varchar(555),
  155.     [Updated] datetime,
  156.     [Rows] bigint,
  157.     [Rows Sampled] bigint,
  158.     [Steps] int,
  159.     [Density] float,
  160.     [Average key length] float,
  161.     [String Index] varchar(3),
  162.     [Filter Expression] varchar(555),
  163.     [Unfiltered Rows] bigint
  164. );
  165.  
  166.  
  167. declare column_cursor cursor for (
  168.     select
  169.         object_id,
  170.         column_id,
  171.         mnemonic,
  172.         name,
  173.         schemaName
  174.     from
  175.         #schema
  176.     where
  177.         column_id > 0
  178. )
  179.  
  180. open column_cursor;
  181. fetch next from column_cursor into @object_id, @column_id, @mnemonic, @name, @schemaName;
  182.  
  183. declare @sql varchar(max);
  184. declare @stats varchar(555);
  185.  
  186. while @@FETCH_STATUS = 0
  187. begin
  188.     set @stats = null;
  189.  
  190.     select
  191.         @stats = s.name
  192.     from
  193.         sys.stats_columns sc
  194.     join
  195.         sys.stats s
  196.     on
  197.         s.object_id = sc.object_id
  198.     and
  199.         s.stats_id = sc.stats_id
  200.     where
  201.         sc.object_id = @object_id
  202.     and
  203.         sc.column_id = @column_id;
  204.  
  205.     set @sql = 'dbcc show_statistics(''' + @schemaName + '.' + object_name(@object_id) + ''', ''' + @stats + ''') WITH STAT_HEADER';
  206.     print @sql;
  207.  
  208.     truncate table #header;
  209.     insert into #header exec(@sql);
  210.  
  211.     -- update existing stats that are outdated
  212.     if exists (
  213.         select top 1
  214.             Name
  215.         from
  216.             #header
  217.         where
  218.             [Rows Sampled] <> [Rows]
  219.     )
  220.     begin
  221.         set @sql = 'update statistics [' + @schemaName + '].[' + object_name(@object_id) + ']([' + @stats + ']) WITH FULLSCAN';
  222.         print @sql;
  223.         exec(@sql);
  224.     end
  225.  
  226.     if @stats is null and not exists (
  227.         select top 1
  228.             name
  229.         from
  230.             sys.columns
  231.         where
  232.             object_id = @object_id
  233.         and
  234.             column_id = @column_id
  235.         and
  236.             -- these types cannot have statistics
  237.             system_type_id in (
  238.                 241 -- xml
  239.             )
  240.     )
  241.     begin  
  242.         set @stats = 's_' + @mnemonic + '_' + @name + '';
  243.         set @sql = 'create statistics [' + @stats + '] on [' + @schemaName + '].[' + object_name(@object_id) + ']([' + @name + ']) WITH FULLSCAN';
  244.         print @sql;
  245.         exec(@sql);
  246.     end
  247.  
  248.     set @sql = 'dbcc show_statistics(''' + @schemaName + '.' + object_name(@object_id) + ''', ''' + @stats + ''') WITH DENSITY_VECTOR';
  249.     print @sql;
  250.  
  251.     truncate table #densities;
  252.     insert into #densities exec(@sql);
  253.  
  254.     update #schema
  255.     set
  256.         density = (select top 1 [All density] from #densities where [Columns] = @name),
  257.         averageLength = (select top 1 [Average Length] from #densities where [Columns] = @name)
  258.     where
  259.         object_id = @object_id
  260.     and
  261.         column_id = @column_id;
  262.  
  263.     fetch next from column_cursor into @object_id, @column_id, @mnemonic, @name, @schemaName;
  264. end
  265.  
  266. close column_cursor;
  267. deallocate column_cursor;
  268.  
  269. --- find primary keys
  270. if OBJECT_ID('tempdb..#primaryKeyColumns') is not null
  271. drop table #primaryKeyColumns;
  272.  
  273. select
  274.     i.object_id,
  275.     max(COL_NAME(i.OBJECT_ID, ic.column_id)) AS name
  276. into
  277.     #primaryKeyColumns
  278. from
  279.     sys.indexes i
  280. join
  281.     sys.index_columns ic
  282. on
  283.     ic.OBJECT_ID = i.OBJECT_ID
  284. and
  285.     ic.index_id = i.index_id
  286. where
  287.     i.is_primary_key = 1   
  288. group by
  289.     i.object_id
  290. having
  291.     COUNT(*) = 1;
  292.  
  293. --- find foreign key relationships
  294. if OBJECT_ID('tempdb..#foreignKeyRelationships') is not null
  295. drop table #foreignKeyRelationships;
  296.  
  297. select distinct
  298.     parent_object_id,  
  299.     referenced_object_id
  300. into
  301.     #foreignKeyRelationships
  302. from
  303.     sys.foreign_key_columns;
  304.  
  305. --- find foreign key columns
  306. if OBJECT_ID('tempdb..#foreignKeyColumns') is not null
  307. drop table #foreignKeyColumns;
  308.  
  309. select distinct
  310.     parent_object_id,  
  311.     parent_column_id,
  312.     referenced_object_id,
  313.     referenced_column_id
  314. into
  315.     #foreignKeyColumns
  316. from
  317.     sys.foreign_key_columns;
  318.  
  319.  
  320. -- XML generation
  321. with knots as (
  322.     select
  323.         object_id,
  324.         column_id,
  325.         mnemonic,
  326.         name,
  327.         density,
  328.         averageLength,
  329.         dataType,
  330.         dataRange,
  331.         maxLength
  332.     from
  333.         #schema
  334.     cross apply (
  335.         values (
  336.             case
  337.                 when @knotSize = 'tinyint'  then 1E0 / 255
  338.                 when @knotSize = 'smallint' then 1E0 / 32767
  339.                 when @knotSize = 'int'      then 1E0 / 2147483647
  340.             end / @fillFactor,
  341.             case
  342.                 when @knotSize = 'tinyint'  then 1
  343.                 when @knotSize = 'smallint' then 2
  344.                 when @knotSize = 'int'      then 4
  345.             end
  346.         )
  347.     ) v (minDensity, minLength)
  348.     where
  349.         density > minDensity
  350.     and
  351.         averageLength > (@checkLengths * minLength)
  352.     and
  353.         dataType in ('varchar', 'nvarchar', 'char', 'nchar')
  354.     union
  355.     select
  356.         -- create a validity knot that ties and anchors are connected to
  357.         0, 0, 'VAL', 'Validity', 1, 42, 'varchar', 'varchar(42)', 42
  358.     where
  359.         @trackValidity in ('T', '*')
  360. )
  361. select
  362.     '0.99' as [@format],
  363.     convert(char(10), getdate(), 121) as [@date],
  364.     convert(char(8), cast(getdate() as time(0)), 121) as [@time],
  365.     SYSTEM_USER as [@creator],
  366.     @timeRange as [metadata/@changingRange],
  367.     @schemaName as [metadata/@encapsulation],
  368.     'int' as [metadata/@identity],
  369.     'SQLServer' as [metadata/@databaseTarget],
  370.     'uni' as [metadata/@temporalization],
  371.     @metadataUsage as [metadata/@metadataUsage],
  372.     (   -- knots
  373.         select
  374.             k.mnemonic as [@mnemonic],
  375.             case
  376.                 when k.density > 1E0 / 255        / @fillFactor then 'tinyint'
  377.                 when k.density > 1E0 / 32767      / @fillFactor then 'smallint'
  378.                 when k.density > 1E0 / 2147483647 / @fillFactor then 'int'
  379.             end as [@identity],
  380.             v.descriptor as [@descriptor],
  381.             k.dataRange as [@dataRange],
  382.             @schemaName as [metadata/@capsule],
  383.             'true' as [metadata/@generator],
  384.             case when k.maxLength > 900 then 'true' end as [metadata/@checksum],
  385.             case
  386.                 when t.name is not null then
  387.                 'Density: ' + CAST(k.density as varchar(42)) + CHAR(10) +
  388.                 'Average length: ' + CAST(k.averageLength as varchar(42)) + CHAR(10) +
  389.                 'Column: ' + k.name + CHAR(10) +
  390.                 'Table: ' + t.name + CHAR(10) +
  391.                 'Query: ' +
  392.                 CHAR(10) +
  393.                 'MERGE [' + @schemaName + '].[' + k.mnemonic + '_' + v.descriptor + '] k ' + CHAR(10) +
  394.                 'USING ( ' + CHAR(10) +
  395.                 CHAR(9) + 'SELECT DISTINCT ' + CHAR(10) +
  396.                 CHAR(9) + CHAR(9) + c.name + CHAR(10) +
  397.                 CHAR(9) + 'FROM ' + CHAR(10) +
  398.                 CHAR(9) + CHAR(9) + t.name + CHAR(10) +
  399.                 CHAR(9) + 'WHERE ' + CHAR(10) +
  400.                 CHAR(9) + CHAR(9) + c.name + ' is not null ' + CHAR(10) +
  401.                 ') src ' + CHAR(10) +
  402.                 'ON ' + CHAR(10) +
  403.                 CHAR(9) + 'src.' + c.name + ' = k.[' + k.mnemonic + '_' + v.descriptor + '] ' + CHAR(10) +
  404.                 'WHEN NOT MATCHED THEN INSERT ( ' + CHAR(10) +
  405.                 CHAR(9) + '[' + k.mnemonic + '_' + v.descriptor + ']' +
  406.                 case when @metadataUsage = 'true' then ',' + CHAR(10) + CHAR(9) + '[Metadata_' + k.mnemonic + ']' else '' end + CHAR(10) +
  407.                 ') ' + CHAR(10) +
  408.                 'VALUES ( ' + CHAR(10) +
  409.                 CHAR(9) + 'src.' + c.name +
  410.                 case when @metadataUsage = 'true' then ',' + CHAR(10) + CHAR(9) + '0' else '' end + CHAR(10) +
  411.                 ');' + CHAR(10)
  412.                 else
  413.                 'Tracks existence over time. ' +
  414.                 'Automatically added to all schemas.'
  415.             end as [description]
  416.         from
  417.             knots k
  418.         cross apply (
  419.             values (
  420.                 replace(replace(replace(replace(replace(replace(replace(replace(
  421.                 replace(replace(replace(replace(replace(replace(replace(
  422.                 replace(replace(replace(replace(replace(replace(replace(
  423.                 replace(replace(replace(replace(replace(
  424.                     ' '+replace(k.name,'_',' '),
  425.                 ' a',' A'),' b',' B'),' c',' C'),' d',' D'),' e',' E'),' f',' F'),
  426.                 ' g',' G'),' h',' H'),' i',' I'),' j',' J'),' k',' K'),' l',' L'),
  427.                 ' m',' M'),' n',' N'),' o',' O'),' p',' P'),' q',' Q'),' r',' R'),
  428.                 ' s',' S'),' t',' T'),' u',' U'),' v',' V'),' w',' W'),' x',' X'),
  429.                 ' y',' Y'),' z',' Z'),' ','')
  430.             )
  431.         ) v (descriptor)
  432.         left join
  433.             #schema t
  434.         on
  435.             t.object_id = k.object_id
  436.         and
  437.             t.column_id = 0
  438.         left join
  439.             #schema c
  440.         on
  441.             c.object_id = k.object_id
  442.         and
  443.             c.column_id = k.column_id
  444.         left join
  445.             #primaryKeyColumns pk
  446.         on
  447.             pk.name COLLATE DATABASE_DEFAULT = k.name COLLATE DATABASE_DEFAULT
  448.         and
  449.             pk.object_id <> k.object_id
  450.         where
  451.             pk.object_id is null
  452.         for xml path('knot'), type
  453.     ),
  454.     (   -- anchors
  455.         select
  456.             t.mnemonic as [@mnemonic],
  457.             vt.descriptor as [@descriptor],
  458.             'int' as [@identity],
  459.             @schemaName as [metadata/@capsule],
  460.             'true' as [metadata/@generator],
  461.             (   -- unknotted attributes
  462.                 select
  463.                     c.mnemonic as [@mnemonic],
  464.                     vc.descriptor as [@descriptor],
  465.                     c.dataRange as [@dataRange],
  466.                     case when @historization in ('*') then @timeRange else null end as [@timeRange],
  467.                     @schemaName as [metadata/@capsule],
  468.                     case when c.maxLength > 900 then 'true' end as [metadata/@checksum],
  469.                     case when c.density is not null then 'Density: ' + CAST(c.density as varchar(42)) + CHAR(10) else '' end +
  470.                     'Column: ' + c.name + CHAR(10) +
  471.                     'Table: ' + t.name as [description]
  472.                 from  
  473.                     #schema c
  474.                 cross apply (
  475.                     values (
  476.                         replace(replace(replace(replace(replace(replace(replace(replace(
  477.                         replace(replace(replace(replace(replace(replace(replace(
  478.                         replace(replace(replace(replace(replace(replace(replace(
  479.                         replace(replace(replace(replace(replace(
  480.                             ' '+replace(c.name,'_',' '),
  481.                         ' a',' A'),' b',' B'),' c',' C'),' d',' D'),' e',' E'),' f',' F'),
  482.                         ' g',' G'),' h',' H'),' i',' I'),' j',' J'),' k',' K'),' l',' L'),
  483.                         ' m',' M'),' n',' N'),' o',' O'),' p',' P'),' q',' Q'),' r',' R'),
  484.                         ' s',' S'),' t',' T'),' u',' U'),' v',' V'),' w',' W'),' x',' X'),
  485.                         ' y',' Y'),' z',' Z'),' ','')
  486.                     )
  487.                 ) vc (descriptor)
  488.                 left join
  489.                     knots k
  490.                 on
  491.                     k.object_id = c.object_id
  492.                 and
  493.                     k.column_id = c.column_id
  494.                 left join
  495.                     #primaryKeyColumns pk
  496.                 on
  497.                     pk.name COLLATE DATABASE_DEFAULT = c.name COLLATE DATABASE_DEFAULT
  498.                 and
  499.                     pk.object_id <> c.object_id
  500.                 where
  501.                     c.object_id = t.object_id
  502.                 and
  503.                     c.column_id > 0
  504.                 and
  505.                     k.object_id is null
  506.                 and
  507.                     pk.object_id is null
  508.                 for xml path ('attribute'), type
  509.             ),
  510.             (   -- knotted attributes
  511.                 select
  512.                     c.mnemonic as [@mnemonic],
  513.                     replace(replace(replace(replace(replace(replace(replace(replace(
  514.                     replace(replace(replace(replace(replace(replace(replace(
  515.                     replace(replace(replace(replace(replace(replace(replace(
  516.                     replace(replace(replace(replace(replace(
  517.                         ' '+replace(c.name,'_',' '),
  518.                     ' a',' A'),' b',' B'),' c',' C'),' d',' D'),' e',' E'),' f',' F'),
  519.                     ' g',' G'),' h',' H'),' i',' I'),' j',' J'),' k',' K'),' l',' L'),
  520.                     ' m',' M'),' n',' N'),' o',' O'),' p',' P'),' q',' Q'),' r',' R'),
  521.                     ' s',' S'),' t',' T'),' u',' U'),' v',' V'),' w',' W'),' x',' X'),
  522.                     ' y',' Y'),' z',' Z'),' ','') as [@descriptor],
  523.                     k.mnemonic as [@knotRange],
  524.                     case when @historization in ('*', 'K') then @timeRange else null end as [@timeRange],
  525.                     @schemaName as [metadata/@capsule],
  526.                     'false' as [metadata/@restatable],
  527.                     'true' as [metadata/@idempotent],
  528.                     case when c.density is not null then 'Density: ' + CAST(c.density as varchar(42)) + CHAR(10) else '' end +
  529.                     'Column: ' + c.name + CHAR(10) +
  530.                     'Table: ' + t.name as [description]
  531.                 from
  532.                     #schema c
  533.                 join
  534.                     knots k
  535.                 on
  536.                     k.object_id = c.object_id
  537.                 and
  538.                     k.column_id = c.column_id
  539.                 left join
  540.                     #primaryKeyColumns pk
  541.                 on
  542.                     pk.name COLLATE DATABASE_DEFAULT = c.name COLLATE DATABASE_DEFAULT
  543.                 and
  544.                     pk.object_id <> c.object_id
  545.                 where
  546.                     c.object_id = t.object_id
  547.                 and
  548.                     c.column_id > 0
  549.                 and
  550.                     pk.object_id is null
  551.                 for xml path ('attribute'), type
  552.             ),
  553.             (   -- validity attribute
  554.                 select
  555.                     'VAL' as [@mnemonic],
  556.                     'Validity' as [@descriptor],
  557.                     'VAL' as [@knotRange],
  558.                     @timeRange as [@timeRange],
  559.                     @schemaName as [metadata/@capsule],
  560.                     'false' as [metadata/@restatable],
  561.                     'true' as [metadata/@idempotent],
  562.                     'Tracks existence of that which the anchor represents. ' +
  563.                     'Automatically added to all anchors by the generator.' as [description]
  564.                 where
  565.                     @trackValidity = '*'
  566.                 for xml path ('attribute'), type
  567.             ),
  568.             'Table: ' + t.name as [description]
  569.         from
  570.             #schema t
  571.         cross apply (
  572.             values (
  573.                 replace(replace(replace(replace(replace(replace(replace(replace(
  574.                 replace(replace(replace(replace(replace(replace(replace(
  575.                 replace(replace(replace(replace(replace(replace(replace(
  576.                 replace(replace(replace(replace(replace(
  577.                     ' '+replace(t.name,'_',' '),
  578.                 ' a',' A'),' b',' B'),' c',' C'),' d',' D'),' e',' E'),' f',' F'),
  579.                 ' g',' G'),' h',' H'),' i',' I'),' j',' J'),' k',' K'),' l',' L'),
  580.                 ' m',' M'),' n',' N'),' o',' O'),' p',' P'),' q',' Q'),' r',' R'),
  581.                 ' s',' S'),' t',' T'),' u',' U'),' v',' V'),' w',' W'),' x',' X'),
  582.                 ' y',' Y'),' z',' Z'),' ','')
  583.             )
  584.         ) vt (descriptor)
  585.         where
  586.             t.column_id = 0
  587.         for xml path ('anchor'), type
  588.     ),
  589.     case when @relationshipDetection in ('N', '*') then (  
  590.         -- ties
  591.         select
  592.             case when fk.referenced_object_id is null then @timeRange else null end as [@timeRange],
  593.             @schemaName as [metadata/@capsule],
  594.             case when fk.referenced_object_id is null then 'false' else null end as [metadata/@restatable],
  595.             case when fk.referenced_object_id is null then 'true' else null end as [metadata/@idempotent],
  596.             case when fk.referenced_object_id is null and @trackValidity in ('T', '*') then 'currently' else null end as [knotRole/@role],
  597.             case when fk.referenced_object_id is null and @trackValidity in ('T', '*') then 'VAL' else null end as [knotRole/@type],
  598.             case when fk.referenced_object_id is null and @trackValidity in ('T', '*') then 'false' else null end as [knotRole/@identifier],
  599.             'n' + c.mnemonic + c.name +
  600.             replace(replace(replace(replace(replace(replace(replace(replace(
  601.             replace(replace(replace(replace(replace(replace(replace(
  602.             replace(replace(replace(replace(replace(replace(replace(
  603.             replace(replace(replace(replace(replace(
  604.                 ' '+replace(t1.name,'_',' '),
  605.             ' a',' A'),' b',' B'),' c',' C'),' d',' D'),' e',' E'),' f',' F'),
  606.             ' g',' G'),' h',' H'),' i',' I'),' j',' J'),' k',' K'),' l',' L'),
  607.             ' m',' M'),' n',' N'),' o',' O'),' p',' P'),' q',' Q'),' r',' R'),
  608.             ' s',' S'),' t',' T'),' u',' U'),' v',' V'),' w',' W'),' x',' X'),
  609.             ' y',' Y'),' z',' Z'),' ','') as [anchorRole/@role],
  610.             t1.mnemonic as [anchorRole/@type],
  611.             'true' as [anchorRole/@identifier],
  612.             null, -- this starts a new anchorRole
  613.             'n' +
  614.             replace(replace(replace(replace(replace(replace(replace(replace(
  615.             replace(replace(replace(replace(replace(replace(replace(
  616.             replace(replace(replace(replace(replace(replace(replace(
  617.             replace(replace(replace(replace(replace(
  618.                 ' '+replace(t2.name,'_',' '),
  619.             ' a',' A'),' b',' B'),' c',' C'),' d',' D'),' e',' E'),' f',' F'),
  620.             ' g',' G'),' h',' H'),' i',' I'),' j',' J'),' k',' K'),' l',' L'),
  621.             ' m',' M'),' n',' N'),' o',' O'),' p',' P'),' q',' Q'),' r',' R'),
  622.             ' s',' S'),' t',' T'),' u',' U'),' v',' V'),' w',' W'),' x',' X'),
  623.             ' y',' Y'),' z',' Z'),' ','') as [anchorRole/@role],
  624.             t2.mnemonic as [anchorRole/@type],
  625.             case when fk.referenced_object_id is null then 'true' else 'false' end as [anchorRole/@identifier],
  626.             'Left table: ' + t1.name + CHAR(10) +
  627.             'Relating column: ' + c.name + ' (' + c.mnemonic + ')' + CHAR(10) +
  628.             'Right table: ' + t2.name as [description]
  629.         from
  630.             #schema t1
  631.         join
  632.             #schema c
  633.         on
  634.             c.object_id = t1.object_id
  635.         and
  636.             c.column_id > 0
  637.         join
  638.             #primaryKeyColumns pk
  639.         on
  640.             pk.name COLLATE DATABASE_DEFAULT = c.name COLLATE DATABASE_DEFAULT
  641.         join
  642.             #schema t2
  643.         on
  644.             t2.object_id = pk.object_id
  645.         and
  646.             t2.column_id = 0
  647.         and
  648.             t2.object_id <> t1.object_id
  649.         left join
  650.             #foreignKeyRelationships fk
  651.         on
  652.             fk.parent_object_id = t1.object_id
  653.         and
  654.             fk.referenced_object_id = t2.object_id
  655.         where
  656.             t1.column_id = 0
  657.         for xml path ('tie'), type     
  658.     ) end,
  659.     case when @relationshipDetection in ('F', '*') then (  
  660.         -- ties
  661.         select
  662.             case when @trackValidity in ('T', '*') then @timeRange else null end as [@timeRange],
  663.             @schemaName as [metadata/@capsule],
  664.             case when @trackValidity in ('T', '*') then 'false' else null end as [metadata/@restatable],
  665.             case when @trackValidity in ('T', '*') then 'true' else null end as [metadata/@idempotent],
  666.             case when @trackValidity in ('T', '*') then 'currently' else null end as [knotRole/@role],
  667.             case when @trackValidity in ('T', '*') then 'VAL' else null end as [knotRole/@type],
  668.             case when @trackValidity in ('T', '*') then 'false' else null end as [knotRole/@identifier],
  669.             'f' + c1.mnemonic + c1.name +
  670.             replace(replace(replace(replace(replace(replace(replace(replace(
  671.             replace(replace(replace(replace(replace(replace(replace(
  672.             replace(replace(replace(replace(replace(replace(replace(
  673.             replace(replace(replace(replace(replace(
  674.                 ' '+replace(t1.name,'_',' '),
  675.             ' a',' A'),' b',' B'),' c',' C'),' d',' D'),' e',' E'),' f',' F'),
  676.             ' g',' G'),' h',' H'),' i',' I'),' j',' J'),' k',' K'),' l',' L'),
  677.             ' m',' M'),' n',' N'),' o',' O'),' p',' P'),' q',' Q'),' r',' R'),
  678.             ' s',' S'),' t',' T'),' u',' U'),' v',' V'),' w',' W'),' x',' X'),
  679.             ' y',' Y'),' z',' Z'),' ','') + 'Foreign' as [anchorRole/@role],
  680.             t1.mnemonic as [anchorRole/@type],
  681.             'true' as [anchorRole/@identifier],
  682.             null, -- this starts a new anchorRole
  683.             'f' +
  684.             replace(replace(replace(replace(replace(replace(replace(replace(
  685.             replace(replace(replace(replace(replace(replace(replace(
  686.             replace(replace(replace(replace(replace(replace(replace(
  687.             replace(replace(replace(replace(replace(
  688.                 ' '+replace(t2.name,'_',' '),
  689.             ' a',' A'),' b',' B'),' c',' C'),' d',' D'),' e',' E'),' f',' F'),
  690.             ' g',' G'),' h',' H'),' i',' I'),' j',' J'),' k',' K'),' l',' L'),
  691.             ' m',' M'),' n',' N'),' o',' O'),' p',' P'),' q',' Q'),' r',' R'),
  692.             ' s',' S'),' t',' T'),' u',' U'),' v',' V'),' w',' W'),' x',' X'),
  693.             ' y',' Y'),' z',' Z'),' ','') as [anchorRole/@role],
  694.             t2.mnemonic as [anchorRole/@type],
  695.             case when fk.referenced_object_id is null then 'true' else 'false' end as [anchorRole/@identifier],
  696.             'Left table: ' + t1.name + CHAR(10) +
  697.             'Foreign key column: ' + c1.name + ' (' + c1.mnemonic + ')' + CHAR(10) +
  698.             'Right table: ' + t2.name + CHAR(10) +
  699.             'Referenced column: ' + c2.name + ' (' + c2.mnemonic + ')' as [description]
  700.         from
  701.             #foreignKeyColumns fk
  702.         join
  703.             #schema c1
  704.         on
  705.             c1.object_id = fk.parent_object_id
  706.         and
  707.             c1.column_id = fk.parent_column_id
  708.         join
  709.             #schema t1
  710.         on
  711.             t1.object_id = fk.parent_object_id
  712.         and
  713.             t1.column_id = 0
  714.         join
  715.             #schema c2
  716.         on
  717.             c2.object_id = fk.referenced_object_id
  718.         and
  719.             c2.column_id = fk.referenced_column_id
  720.         join
  721.             #schema t2
  722.         on
  723.             t2.object_id = fk.referenced_object_id
  724.         and
  725.             t2.column_id = 0
  726.         for xml path ('tie'), type     
  727.     ) end
  728. for xml path ('schema')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement