SQLでレポートを作成するためのエンジン。 ドラフト決定

はじめに



最初の記事( SQLレポートエンジン。アイデア )でアイデアを共有しました。 次に、ソリューション(案)を共有します。 このドラフトは、 T-SQLを使用した「真面目な」作業の初めての経験なので、「良い」コードのサンプルとして取り上げるべきではありません。

このドラフトで最も重要なことは、式を動的クエリに代入するメカニズムです。 2番目に重要なのは、計算結果を保存するメカニズムです。



私が働き始めたとき、私は大きな困難を予想していましたが、実際にはすべてが非常にシンプルであることが判明しました。 たくさんの落書きをして、立ち止まって考えなければならなかった瞬間。 最初のポイントはクエリの行番号の生成であり、2番目はキーフィールドの値の生成です。

恐れる目-手はやる!

これに満足していない人のために、最も基本的で興味深いものからすぐに始めます-ロジックの徹底的な分析は以下になります。 始めましょう。



フォーミュラ計算





列とセクションの違い


列に入力する式を計算することと、セクションのフィールド(キャップ​​またはフッター)に入力する式を計算することには大きな違いがあります。 この違いは、列が各行に対して個別に計算され、セクションがすべての行に対して一度に1回計算されることです。

見出しの数式は常に集計関数であり、数式の計算結果はテンプレートの「フットプリント」に「接着」する必要があります。

列の計算値は、この列が計算された行に「バインド」(リンク)されている必要があります。

そのため、列と上限を計算するためのさまざまなテンプレートが開発されました。



セクションテンプレート


SET @sql_text = N' SELECT @result = ' + @formula + N' FROM table '
      
      





すべてが線形です:





スピーカーテンプレート


より複雑な列。 ヘッダーの計算結果が1つの値である場合、列の計算結果は値のセットです。つまり、これは1つの列と特定の行数で構成されるテーブルです。

レポート出力中に列のすべての行を同期するには、結果を( report_cell_instancesテーブルに)保存するときに各行に番号を付ける必要があります。

これを行うには、単一の統一された方法で行をソートする必要があります-ソート。 列を計算するためのクエリに「 ORDER BY 」という句を追加し、「 SELECT 」に「 ROW_NUMBER()OVER(ORDER BY) 」を追加します。

リクエストテンプレート:

 SET @sql_text = N' SELECT ROW_NUMBER() OVER( ORDER BY key_column) ,' + @formula + N' FROM table ORDER BY key_column'
      
      





難しくありません。 次に興味深い点は、計算の保存-私たちの仕事の結果です。



結果を保存します。



セクション(ヘッダーまたは地下室)を保存するのに問題はありません-簡単な「 INSERT 」が必要な場所( report_region_instancesテーブル内)にあります。

計算列を保存することも難しくありません。動的クエリを「 INSERT 」演算子で補完する必要があります。

唯一の問題は、一意のキーフィールド値を生成することです。 自動インクリメントカラム( IDENTITYプロパティ)を使用してこの問題を解決する優れたソリューションがありますが、プログラムの動作を最大限に制御したいので、別のツール(「 シーケンス 」)を使用し、各番号を手動で生成しました。

リクエストテンプレート:

 SET @sql_text = N' INSERT INTO report_cell_instances ( id , row_order , value ) SELECT (NEXT VALUE FOR [dbo].[report_cell_instances_sequence] OVER( ' + @C_ORDER_BY + N' ) ) AS Record_Id , ROW_NUMBER() OVER( ' + @C_ORDER_BY + N' ) AS Row_Order , ' + @formula + N' AS Formula_Result FROM table' + @C_ORDER_BY
      
      







実装の徹底的な分析



実装はT-SQLスクリプトの形式で行われます。実際の実装では、ストアドプロシージャである必要があります。問題の入力パラメーターの構成は、顧客のニーズによって異なります。 私のスクリプトでは、これは次のとおりです。

  1. client-consumer_referenceテーブルからランダムに選択
  2. ステーション番号-meteo_stations_referenceテーブルからランダムに選択、
  3. 日付期間-選択した測点のmeteo_measurementsテーブルから2つのランダムな日付が選択されます


「ハードコード」または「マジックナンバー」のスタイルで作成された少なくとも定数でなければならない他のものは、これを「ドラフト」コストと見なします。

dbForge Studioでコードを記述しました。このIDEには最高のソースフォーマッタがあります(これはこのIDEの唯一のプラスです)が、まだ構成していないので、フォーマットは手動で行い、覚えている場所でのみ行います。

C#PL / SQ Lの習慣から、各文は「;」で終わります。

コードのコメントの残りの部分を読んでください(非常に明白なものにはコメントがありません。申し訳ありませんが、退屈していません)。

詳細なコメント付きのスクリプト
 BEGIN /*  ,        ,           */ DECLARE @C_ORDER_BY NVARCHAR(MAX) = ' ORDER BY mm.meteo_station_id , mm.read_timestamp ' ; /*      */ DECLARE @C_COLUMN_FORMULA_INSERT NVARCHAR(MAX) = N' INSERT INTO report_cell_instances (id ,instance_id ,consumer_id ,column_id ,row_order ,value) '; /*      ,            report_cell_instances */ DECLARE @C_COLUMN_FORMULA_SELECT NVARCHAR(MAX) = N' SELECT (NEXT VALUE FOR [dbo].[report_cell_instances_sequence] OVER( ' + @C_ORDER_BY + N' ) ) AS RecordId , @Instance_Id AS InstanceId , @Consumer_Id AS ConsumerId , @Column_Id AS ColumnId , ROW_NUMBER() OVER( ' + @C_ORDER_BY + N' ) AS Row_Order , '; /*        */ DECLARE @C_COLUMN_FORMULA_FROM NVARCHAR(MAX) = N' FROM meteo_measurements mm WHERE mm.meteo_station_id = @Station_Id AND mm.read_timestamp BETWEEN @FromDate AND @ThruDate ' + @C_ORDER_BY ; /*       @Station_Id -    @FromDate -       @ThruDate -       @Column_Id -       @Instance_Id -     @Consumer_Id -    */ DECLARE @ColumnFormulaParams NVARCHAR(MAX); SET @ColumnFormulaParams = N' @Station_Id bigint , ' + N' @FromDate datetimeoffset(7) , ' + N' @ThruDate datetimeoffset(7) , ' + N' @Column_Id INT , ' + N' @Instance_Id INT , ' + N' @Consumer_Id INT ' ; /*        ,     */ DECLARE @Station BIGINT ; SELECT TOP 1 @Station = sr.id FROM meteo_stations_reference sr ORDER BY NEWID(); /*     ,     "PRINT"     */ PRINT N' @Staton = ' + CAST ( @Station AS NVARCHAR ) ; /*      , @From -   @Thru -   */ DECLARE @From DATETIMEOFFSET(7) ; DECLARE @Thru DATETIMEOFFSET(7) ; /*    */ SELECT TOP 1 @From = mm.read_timestamp FROM meteo_measurements mm ORDER BY NEWID(); SELECT TOP 1 @Thru = mm.read_timestamp FROM meteo_measurements mm ORDER BY NEWID(); /*  ""    */ DECLARE @SwapVariable DATETIMEOFFSET(7) ; IF ( @From > @Thru ) BEGIN SET @SwapVariable = @Thru; SET @Thru = @From ; SET @From = @SwapVariable ; END; PRINT N' @From = ' + CAST ( @From AS NVARCHAR )+ N' @Thru = ' + CAST ( @Thru AS NVARCHAR ); /*    ,     */ DECLARE @Instance INT ; SET @Instance = NEXT VALUE FOR [dbo].[report_instances_sequence] ; /*    ,    1 - "" */ INSERT INTO report_instances ( id , name , description , state_id ) VALUES (@Instance,CAST(@Instance AS NVARCHAR ),' DEBUG ', 1 ) ; /* ,      */ DECLARE @ConsumerId INT ; SELECT TOP 1 @ConsumerId = cr.id FROM consumer_reference cr ORDER BY NEWID(); PRINT N' @ConsumerId = ' + CAST ( @ConsumerId AS NVARCHAR ) ; /*         T-SQL       (      ).        ,          .          T-SQL       . T-SQL     (      ),      ,   .         ,         .                 .         -   .        .   -    ,     1000,         .        ,        . */ -- CREATE TABLE #consumers_report_columns( -- column_id int ) -- -- INSERT INTO #consumers_report_columns ( column_id ) -- SELECT -- rc.column_id -- FROM -- consumers_report_columns rc -- WHERE -- rc.consumer_id = @ConsumerId -- ; /*      */ DECLARE @consumers_report_columns TABLE ( column_id INT ) INSERT INTO @consumers_report_columns (column_id) SELECT rc.column_id FROM consumers_report_columns rc WHERE rc.consumer_id = @ConsumerId ; /* -=* CYCLE BEGIN *=- */ -- DECLARE consumers_report_columns_cursor CURSOR FOR -- SELECT -- rc.column_id -- FROM -- #consumers_report_columns rc -- ; /*         */ DECLARE consumers_report_columns_cursor CURSOR FOR SELECT rc.column_id FROM @consumers_report_columns rc ; /*      */ DECLARE @ColumnId INT ; OPEN consumers_report_columns_cursor ; FETCH NEXT FROM consumers_report_columns_cursor INTO @ColumnId WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' @ColumnId = ' + CAST ( @ColumnId AS NVARCHAR ) ; /*              ,           ,      . */ /*  ""       */ DECLARE @FormulaId INT; SELECT @FormulaId = cl.formula_id FROM columns cl WHERE cl.id = @ColumnId ; PRINT N' @FormulaId = ' + CAST ( @FormulaId AS NVARCHAR ) ; /*       */ DECLARE @formula NVARCHAR(MAX); SELECT @formula = fm.formula FROM formulas fm WHERE fm.id = @FormulaId ; PRINT N' @formula = ' + @formula ; /*       ,          */ DECLARE @column_formula_phrase NVARCHAR(MAX); SET @column_formula_phrase = @C_COLUMN_FORMULA_SELECT + @formula + @C_COLUMN_FORMULA_FROM ; PRINT N' @column_formula_phrase = ' + @column_formula_phrase ; /*  ,       */ DECLARE @column_formula_sql NVARCHAR(MAX); SET @column_formula_sql = @column_formula_phrase ; /*         ,  ,     ,      */ EXEC sp_executesql @column_formula_sql , @ColumnFormulaParams , @Station_Id = @Station , @FromDate = @From , @ThruDate = @Thru , @Column_Id = @ColumnId , @Instance_Id = @Instance , @Consumer_Id = @ConsumerId /*            report_cell_instances */ SET @column_formula_phrase = @C_COLUMN_FORMULA_INSERT + @C_COLUMN_FORMULA_SELECT + @formula + @C_COLUMN_FORMULA_FROM ; PRINT N' @column_formula_phrase = ' + @column_formula_phrase ; /*        */ SET @column_formula_sql = @column_formula_phrase ; EXEC sp_executesql @column_formula_sql , @ColumnFormulaParams , @Station_Id = @Station , @FromDate = @From , @ThruDate = @Thru , @Column_Id = @ColumnId , @Instance_Id = @Instance , @Consumer_Id = @ConsumerId FETCH NEXT FROM consumers_report_columns_cursor INTO @ColumnId END CLOSE consumers_report_columns_cursor; /*    "DEALLOCATE"   */ DEALLOCATE consumers_report_columns_cursor; /* -=* CYCLE END *=- */ /*    */ -- DROP TABLE #consumers_report_columns DELETE @consumers_report_columns ; /*    */ /*      */ DECLARE @consumers_report_regions TABLE ( region_id INT ) INSERT INTO @consumers_report_regions (region_id) SELECT rr.region_id FROM consumers_report_regions rr WHERE rr.consumer_id = @ConsumerId ; /*         */ DECLARE consumers_report_regions_cursor CURSOR FOR SELECT rr.region_id FROM @consumers_report_regions rr ; /*       */ DECLARE @C_REGION_FORMULA_SELECT NVARCHAR(MAX) = N' SELECT @Result = ' ; /*        */ DECLARE @C_REGION_FORMULA_FROM NVARCHAR(MAX) = N' FROM meteo_measurements mm WHERE mm.meteo_station_id = @Station_Id AND mm.read_timestamp BETWEEN @FromDate AND @ThruDate '; /*       @Station_Id -       @FromDate -      @ThruDate -      @Result -    */ DECLARE @C_REGION_FORMULA_PARAMS NVARCHAR(MAX) = N' @Station_Id bigint , ' + N' @FromDate datetimeoffset(7) , ' + N' @ThruDate datetimeoffset(7) , ' + N' @Result NVARCHAR(MAX) OUT ' ; /*     */ DECLARE @RegionId INT ; OPEN consumers_report_regions_cursor ; FETCH NEXT FROM consumers_report_regions_cursor INTO @RegionId WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' @RegionId = ' + CAST ( @RegionId AS NVARCHAR ) ; /*    */ DECLARE @Pattern NVARCHAR(MAX) ; SELECT @Pattern = rg.pattern FROM regions rg WHERE rg.id = @RegionId ; PRINT N' @Pattern = ' + @Pattern ; /*  .         */ DECLARE @region_formulas_and_placeholders TABLE ( formula NVARCHAR(MAX) , placeholder NVARCHAR(MAX) ) /*       */ INSERT INTO @region_formulas_and_placeholders ( formula , placeholder ) SELECT fr.formula , rf.placeholder -- , rg.pattern FROM regions rg JOIN region_formulas rf ON rg.id = rf.region_id JOIN formulas fr ON rf.formula_id = fr.id WHERE rg.id = @RegionId ; /*          */ DECLARE region_formulas_and_placeholders_cursor CURSOR FOR SELECT fp.formula , fp.placeholder FROM @region_formulas_and_placeholders fp ; /*      */ DECLARE @region_formula NVARCHAR(MAX); /*       .        */ DECLARE @placeholder NVARCHAR(MAX); OPEN region_formulas_and_placeholders_cursor ; FETCH NEXT FROM region_formulas_and_placeholders_cursor INTO @region_formula , @placeholder WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' @region_formula = ' + @region_formula + N' @placeholder = ' + @placeholder; /*         */ DECLARE @region_formula_phrase NVARCHAR(MAX) ; SET @region_formula_phrase = @C_REGION_FORMULA_SELECT + @region_formula + @C_REGION_FORMULA_FROM ; PRINT N' @region_formula_phrase = ' + @region_formula_phrase ; DECLARE @region_formula_sql NVARCHAR(MAX) ; SET @region_formula_sql = @region_formula_phrase ; /*                 */ DECLARE @Substitute NVARCHAR(MAX) ; /*      ,    @Substitute */ EXEC sp_executesql @region_formula_sql , @C_REGION_FORMULA_PARAMS , @Station_Id = @Station , @FromDate = @From , @ThruDate = @Thru , @Result = @Substitute OUT ; PRINT N' @Substitute = ' + @Substitute ; /*       */ SET @Pattern = REPLACE ( @Pattern , @placeholder , @Substitute ) ; FETCH NEXT FROM region_formulas_and_placeholders_cursor INTO @region_formula , @placeholder END CLOSE region_formulas_and_placeholders_cursor; DEALLOCATE region_formulas_and_placeholders_cursor; /*       */ DELETE @region_formulas_and_placeholders ; PRINT N' FINISH @Pattern ' + @Pattern ; /*      report_region_instances */ INSERT INTO report_region_instances ( instace_id ,consumer_id ,region_id ,value ) VALUES( @Instance , @ConsumerId , @RegionId , @Pattern ) ; FETCH NEXT FROM consumers_report_regions_cursor INTO @RegionId END CLOSE consumers_report_regions_cursor; DEALLOCATE consumers_report_regions_cursor; /*    -    */ DELETE @consumers_report_regions ; /*     .      -   :) */ END;
      
      









ソリューションテスト



テストは表面的なものであり、データエラー時のスクリプトの動作は確認されませんでした。



テストデータセット


テストスイートを生成するために、 dbForge Studioジェネレーターを使用しました。

meteo_measurementsテーブルでは、 read_timestamp列のタイプを「 timestamp 」から「 datetimeoffset (7)」に変更する必要がありました。これは、サーバーのみが「 timestamp 」タイプの値を作成でき、手動では許可されず、 dbForge Studioでのデータセットの生成が手動で行われるためですmode-特別に規定されたINSERTステートメントを持つスクリプト。

さらに、生成されたスクリプトを完了するという意味で、「meteo_station_id」列の値を手で置き換える必要がありました。

  1. 「measurements(read_timestamp」を「measurements(meteo_station_id、read_timestamp、)」に置き換えます
  2. " wind_speed)VALUES( ' "" wind_speed)VALUES((SELECT TOP 1 id FROM meteo_stations_reference ORDER BY NEWID())、' "


テストセットは15,000レコードに制限する必要があり、16,000を超える改行のスクリプトを生成すると失われました。

設定テーブル


さらに、テストのために、レコードが他のテーブルに追加されました。 一意のインデックスのペアが変更されており、これらのインデックスがどれであるか覚えていないため、すべてのメインテーブルを繰り返します。

GitHubには 、テーブルを作成するためのDDLスクリプトと、データを挿入するDMLスクリプトがあります。

データ挿入を伴うDDLテーブルとDML
 CREATE TABLE Linegro.dbo.meteo_stations_reference ( id BIGINT NOT NULL ,name NVARCHAR(4000) NOT NULL ,description NVARCHAR(MAX) NULL ,CONSTRAINT PK_meteo_stations_reference PRIMARY KEY CLUSTERED (id) ,CONSTRAINT UK_meteo_stations_reference_name UNIQUE (name) ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO SET DATEFORMAT ymd SET ARITHABORT, ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON SET NUMERIC_ROUNDABORT, IMPLICIT_TRANSACTIONS, XACT_ABORT OFF GO INSERT Linegro.dbo.meteo_stations_reference(id, name, description) VALUES (1, N'', N' ""') INSERT Linegro.dbo.meteo_stations_reference(id, name, description) VALUES (2, N'', N'   ') INSERT Linegro.dbo.meteo_stations_reference(id, name, description) VALUES (3, N'', N' ') INSERT Linegro.dbo.meteo_stations_reference(id, name, description) VALUES (4, N'', N'  ') INSERT Linegro.dbo.meteo_stations_reference(id, name, description) VALUES (5, N'', N'   - ') GO CREATE TABLE Linegro.dbo.meteo_measurements ( meteo_station_id BIGINT NOT NULL ,read_timestamp DATETIMEOFFSET NOT NULL ,temperature DECIMAL(4, 1) NULL ,pressure INT NULL ,wind_direction INT NULL ,wind_speed INT NULL ,CONSTRAINT PK_meteo_measurements PRIMARY KEY CLUSTERED (meteo_station_id, read_timestamp) ,CONSTRAINT FK_meteo_measurements_meteo_stations_reference_id FOREIGN KEY (meteo_station_id) REFERENCES dbo.meteo_stations_reference (id) ) ON [PRIMARY] GO CREATE TABLE Linegro.dbo.consumer_reference ( id INT NOT NULL ,name NVARCHAR(4000) NOT NULL ,description NVARCHAR(MAX) NULL ,CONSTRAINT PK_consumer_reference PRIMARY KEY CLUSTERED (id) ,CONSTRAINT UK_consumer_reference_name UNIQUE (name) ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO SET DATEFORMAT ymd SET ARITHABORT, ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON SET NUMERIC_ROUNDABORT, IMPLICIT_TRANSACTIONS, XACT_ABORT OFF GO INSERT Linegro.dbo.consumer_reference(id, name, description) VALUES (1, N' ', N'    ') INSERT Linegro.dbo.consumer_reference(id, name, description) VALUES (2, N' ', N'   ') INSERT Linegro.dbo.consumer_reference(id, name, description) VALUES (3, N' 23', N'   23') INSERT Linegro.dbo.consumer_reference(id, name, description) VALUES (4, N'426  2016', N'  426 ( 2016 )     ') GO CREATE TABLE Linegro.dbo.formulas ( id INT NOT NULL ,code NCHAR(50) NOT NULL ,formula NVARCHAR(MAX) NOT NULL ,CONSTRAINT PK_formulas PRIMARY KEY CLUSTERED (id) ,CONSTRAINT UK_formulas_code UNIQUE (code) ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO SET DATEFORMAT ymd SET ARITHABORT, ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON SET NUMERIC_ROUNDABORT, IMPLICIT_TRANSACTIONS, XACT_ABORT OFF GO INSERT Linegro.dbo.formulas(id, code, formula) VALUES (1, N'temperature', N'COALESCE(temperature ,0) AS temperature') INSERT Linegro.dbo.formulas(id, code, formula) VALUES (2, N'pressure', N'COALESCE(pressure,0) AS pressure') INSERT Linegro.dbo.formulas(id, code, formula) VALUES (3, N'wind_direction', N'COALESCE(wind_direction,0) AS wind_direction') INSERT Linegro.dbo.formulas(id, code, formula) VALUES (4, N'wind_speed', N'wind_speed AS wind_speed') INSERT Linegro.dbo.formulas(id, code, formula) VALUES (5, N'temperature_max', N'MAX(COALESCE(temperature,0)) ') INSERT Linegro.dbo.formulas(id, code, formula) VALUES (6, N'temperature_min', N'MIN(COALESCE(temperature,0)) ') INSERT Linegro.dbo.formulas(id, code, formula) VALUES (7, N'temperature_avg', N'AVG(COALESCE(temperature,0)) ') INSERT Linegro.dbo.formulas(id, code, formula) VALUES (8, N'speed_m_s', N'CAST ( COALESCE(wind_speed ,0) AS NVARCHAR ) + N'' ( $M_S$ )'' AS speed_m_s') GO CREATE TABLE Linegro.dbo.columns ( id INT NOT NULL ,formula_id INT NOT NULL ,name NVARCHAR(MAX) NOT NULL ,description NVARCHAR(MAX) NULL ,CONSTRAINT PK_columns PRIMARY KEY CLUSTERED (id) ,CONSTRAINT FK_columns_formulas_id FOREIGN KEY (formula_id) REFERENCES dbo.formulas (id) ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO SET DATEFORMAT ymd SET ARITHABORT, ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON SET NUMERIC_ROUNDABORT, IMPLICIT_TRANSACTIONS, XACT_ABORT OFF GO INSERT Linegro.dbo.columns(id, formula_id, name, description) VALUES (1, 1, N'', N'  (   ) ') INSERT Linegro.dbo.columns(id, formula_id, name, description) VALUES (2, 2, N'', N'  (    )') INSERT Linegro.dbo.columns(id, formula_id, name, description) VALUES (3, 3, N'', N' ') INSERT Linegro.dbo.columns(id, formula_id, name, description) VALUES (4, 4, N'', N'  ( / )') INSERT Linegro.dbo.columns(id, formula_id, name, description) VALUES (5, 8, N'', N' ') GO CREATE TABLE Linegro.dbo.regions ( id INT NOT NULL ,pattern NVARCHAR(MAX) NOT NULL ,name NVARCHAR(4000) NOT NULL ,description NVARCHAR(MAX) NULL ,CONSTRAINT PK_regions PRIMARY KEY CLUSTERED (id) ,CONSTRAINT UK_regions_name UNIQUE (name) ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO SET DATEFORMAT ymd SET ARITHABORT, ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON SET NUMERIC_ROUNDABORT, IMPLICIT_TRANSACTIONS, XACT_ABORT OFF GO INSERT Linegro.dbo.regions(id, pattern, name, description) VALUES (1, N'max temp = $MAX_TEMP$ , min temp = $MIN_TEMP$ , average temp = $AVG_TEMP$', N'temp_statistics', N'  ') INSERT Linegro.dbo.regions(id, pattern, name, description) VALUES (2, N'  426 ( 2016 )     ', N'426_2016_title', N'') INSERT Linegro.dbo.regions(id, pattern, name, description) VALUES (3, N' ', N'empty', N' ') INSERT Linegro.dbo.regions(id, pattern, name, description) VALUES (4, N'   ', N' ', NULL) INSERT Linegro.dbo.regions(id, pattern, name, description) VALUES (5, N' ', N' ', NULL) GO CREATE TABLE Linegro.dbo.consumers_report_columns ( column_id INT NOT NULL ,consumer_id INT NOT NULL ,column_order INT NOT NULL ,CONSTRAINT PK_consumers_report_columns PRIMARY KEY CLUSTERED (consumer_id, column_id) ,CONSTRAINT UK_consumers_report_columns_column_order UNIQUE (consumer_id, column_order) ,CONSTRAINT FK_consumers_report_columns_columns_id FOREIGN KEY (column_id) REFERENCES dbo.columns (id) ,CONSTRAINT FK_consumers_report_columns_consumer_reference_id FOREIGN KEY (consumer_id) REFERENCES dbo.consumer_reference (id) ) ON [PRIMARY] GO SET DATEFORMAT ymd SET ARITHABORT, ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON SET NUMERIC_ROUNDABORT, IMPLICIT_TRANSACTIONS, XACT_ABORT OFF GO INSERT Linegro.dbo.consumers_report_columns(column_id, consumer_id, column_order) VALUES (3, 1, 1) INSERT Linegro.dbo.consumers_report_columns(column_id, consumer_id, column_order) VALUES (3, 2, 1) INSERT Linegro.dbo.consumers_report_columns(column_id, consumer_id, column_order) VALUES (4, 2, 3) INSERT Linegro.dbo.consumers_report_columns(column_id, consumer_id, column_order) VALUES (2, 2, 5) INSERT Linegro.dbo.consumers_report_columns(column_id, consumer_id, column_order) VALUES (1, 2, 14) INSERT Linegro.dbo.consumers_report_columns(column_id, consumer_id, column_order) VALUES (3, 3, 10) INSERT Linegro.dbo.consumers_report_columns(column_id, consumer_id, column_order) VALUES (5, 3, 20) INSERT Linegro.dbo.consumers_report_columns(column_id, consumer_id, column_order) VALUES (2, 4, 11) INSERT Linegro.dbo.consumers_report_columns(column_id, consumer_id, column_order) VALUES (1, 4, 22) GO CREATE TABLE Linegro.dbo.consumers_report_regions ( consumer_id INT NOT NULL ,region_id INT NOT NULL ,region_order INT NOT NULL ,type_id INT NULL ,CONSTRAINT PK_consumers_report_base PRIMARY KEY CLUSTERED (consumer_id, region_id) ,CONSTRAINT UK_consumers_report_regions_region_order UNIQUE (consumer_id, region_order) ,CONSTRAINT FK_consumers_report_regions_consumer_reference_id FOREIGN KEY (consumer_id) REFERENCES dbo.consumer_reference (id) ,CONSTRAINT FK_consumers_report_regions_regions_id FOREIGN KEY (region_id) REFERENCES dbo.regions (id) ,CONSTRAINT FK_consumers_report_regions_report_region_types_id FOREIGN KEY (type_id) REFERENCES dbo.report_region_types (id) ) ON [PRIMARY] GO SET DATEFORMAT ymd SET ARITHABORT, ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON SET NUMERIC_ROUNDABORT, IMPLICIT_TRANSACTIONS, XACT_ABORT OFF GO INSERT Linegro.dbo.consumers_report_regions(consumer_id, region_id, region_order, type_id) VALUES (1, 5, 1, 2) INSERT Linegro.dbo.consumers_report_regions(consumer_id, region_id, region_order, type_id) VALUES (2, 1, -1, 4) INSERT Linegro.dbo.consumers_report_regions(consumer_id, region_id, region_order, type_id) VALUES (2, 4, 1, 1) INSERT Linegro.dbo.consumers_report_regions(consumer_id, region_id, region_order, type_id) VALUES (3, 1, 50, 5) INSERT Linegro.dbo.consumers_report_regions(consumer_id, region_id, region_order, type_id) VALUES (3, 3, -100, 3) INSERT Linegro.dbo.consumers_report_regions(consumer_id, region_id, region_order, type_id) VALUES (3, 4, 5, 1) INSERT Linegro.dbo.consumers_report_regions(consumer_id, region_id, region_order, type_id) VALUES (4, 2, 10, 3) GO CREATE TABLE Linegro.dbo.region_formulas ( id INT NOT NULL ,formula_id INT NOT NULL ,region_id INT NOT NULL ,placeholder NVARCHAR(4000) NOT NULL ,CONSTRAINT PK_region_formulas PRIMARY KEY CLUSTERED (id) ,CONSTRAINT UK_region_formulas UNIQUE (region_id, formula_id) ,CONSTRAINT FK_region_formulas_formulas_formula_id FOREIGN KEY (formula_id) REFERENCES dbo.formulas (id) ,CONSTRAINT FK_region_formulas_regions_id FOREIGN KEY (region_id) REFERENCES dbo.regions (id) ) ON [PRIMARY] GO SET DATEFORMAT ymd SET ARITHABORT, ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON SET NUMERIC_ROUNDABORT, IMPLICIT_TRANSACTIONS, XACT_ABORT OFF GO INSERT Linegro.dbo.region_formulas(id, formula_id, region_id, placeholder) VALUES (1, 5, 1, N'$MAX_TEMP$') INSERT Linegro.dbo.region_formulas(id, formula_id, region_id, placeholder) VALUES (2, 6, 1, N'$MIN_TEMP$') INSERT Linegro.dbo.region_formulas(id, formula_id, region_id, placeholder) VALUES (3, 7, 1, N'$AVG_TEMP$') GO CREATE TABLE Linegro.dbo.report_instace_states_reference ( id INT NOT NULL ,code NCHAR(50) NOT NULL ,description NVARCHAR(MAX) NULL ,CONSTRAINT PK_report_instace_states_reference PRIMARY KEY CLUSTERED (id) ,CONSTRAINT UK_report_instace_states_reference_code UNIQUE (code) ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO SET DATEFORMAT ymd SET ARITHABORT, ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON SET NUMERIC_ROUNDABORT, IMPLICIT_TRANSACTIONS, XACT_ABORT OFF GO INSERT Linegro.dbo.report_instace_states_reference(id, code, description) VALUES (1, N'', N'') INSERT Linegro.dbo.report_instace_states_reference(id, code, description) VALUES (2, N'', N'') INSERT Linegro.dbo.report_instace_states_reference(id, code, description) VALUES (3, N'', N'') INSERT Linegro.dbo.report_instace_states_reference(id, code, description) VALUES (4, N'', N'') GO
      
      







計算式の値はNVARCHAR(MAX)として「保存」されますが、結果を保存するためのテンプレートは型変換を提供しません-これはユーザーとその資格の良心です。



逃したポイント



ソリューションにはformula_parametersテーブルの処理はありません;任意の値は式に代入されません。



おわりに



実際、今ではすべてがあなたの手にあります。このディスクからは、何でも好きな

ものを作成できます。

ご清聴ありがとうございました。



参照資料



  1. SQLでレポートを作成するためのエンジン。 アイデア
  2. ソース-GitHub
  3. 異種のランダムデータまたは17時間の待機をMS SQLデータベースに取り込む方法
  4. SQL Server用のdbForge Studio
  5. SQLでランダムな行を要求するにはどうすればよいですか?
  6. 動的SQLの呪いと祝福
  7. Temporary Tables , What's the difference between a temp table and table variable in SQL Server?
  8. SQL Server 2014 In Memory OLTP: Memory-Optimized Table Types and Table Variables



All Articles