├── .github └── workflows │ └── dotnetcore.yml ├── .gitignore ├── atc-adf-sql-demo ├── .gitignore ├── README.md ├── adf │ ├── dataset │ │ ├── customer_csv.json │ │ └── customer_sql_table.json │ ├── factory │ │ └── atc-adf-sql-dev.json │ ├── linkedService │ │ ├── atc_adf_sql.json │ │ ├── atc_adf_sql_akv.json │ │ └── atc_adf_sql_blob.json │ └── pipeline │ │ └── copy_customer_data.json ├── devops │ └── pipelines │ │ └── deploy-all.yml └── sql │ ├── WideWorldImportersDW.sln │ └── wwi-dw-ssdt │ ├── Dimension │ └── Tables │ │ ├── City.sql │ │ ├── Customer.sql │ │ ├── Date.sql │ │ ├── Employee.sql │ │ ├── Payment Method.sql │ │ ├── Stock Item.sql │ │ ├── Supplier.sql │ │ └── Transaction Type.sql │ ├── Fact │ └── Tables │ │ ├── Movement.sql │ │ ├── Order.sql │ │ ├── Purchase.sql │ │ ├── Sale.sql │ │ ├── Stock Holding.sql │ │ └── Transaction.sql │ ├── Integration │ ├── Functions │ │ └── GenerateDateDimensionColumns.sql │ ├── Stored Procedures │ │ ├── GetLastETLCutoffTime.sql │ │ ├── GetLineageKey.sql │ │ ├── MigrateStagedCityData.sql │ │ ├── MigrateStagedCustomerData.sql │ │ ├── MigrateStagedEmployeeData.sql │ │ ├── MigrateStagedMovementData.sql │ │ ├── MigrateStagedOrderData.sql │ │ ├── MigrateStagedPaymentMethodData.sql │ │ ├── MigrateStagedPurchaseData.sql │ │ ├── MigrateStagedSaleData.sql │ │ ├── MigrateStagedStockHoldingData.sql │ │ ├── MigrateStagedStockItemData.sql │ │ ├── MigrateStagedSupplierData.sql │ │ ├── MigrateStagedTransactionData.sql │ │ ├── MigrateStagedTransactionTypeData.sql │ │ └── PopulateDateDimensionForYear.sql │ └── Tables │ │ ├── City_Staging.sql │ │ ├── Customer_Staging.sql │ │ ├── ETL Cutoff.sql │ │ ├── Employee_Staging.sql │ │ ├── Lineage.sql │ │ ├── Movement_Staging.sql │ │ ├── Order_Staging.sql │ │ ├── PaymentMethod_Staging.sql │ │ ├── Purchase_Staging.sql │ │ ├── Sale_Staging.sql │ │ ├── StockHolding_Staging.sql │ │ ├── StockItem_Staging.sql │ │ ├── Supplier_Staging.sql │ │ ├── TransactionType_Staging.sql │ │ └── Transaction_Staging.sql │ ├── PostDeploymentScripts │ └── AddUsers.sql │ ├── Security │ ├── Application.sql │ ├── Dimension.sql │ ├── Fact.sql │ ├── Integration.sql │ ├── PowerBI.sql │ ├── Reports.sql │ ├── Sequences.sql │ └── Website.sql │ ├── Sequences │ └── Sequences │ │ ├── CityKey.sql │ │ ├── CustomerKey.sql │ │ ├── EmployeeKey.sql │ │ ├── LineageKey.sql │ │ ├── PaymentMethodKey.sql │ │ ├── StockItemKey.sql │ │ ├── SupplierKey.sql │ │ └── TransactionTypeKey.sql │ ├── Storage │ ├── PF_Date.sql │ └── PS_Date.sql │ ├── WideWorldImportersDW.sqlproj │ └── dbo │ └── Tables │ └── SampleVersion.sql ├── azure-pipelines ├── deploy-sqlproj.yml └── test-azcli.yml ├── fitnessdb-datagen ├── Program.cs ├── fitnessdb-datagen.csproj └── fitnessdb-datagen.sln ├── fitnessdb-dbup ├── Program.cs ├── database-migration.csproj └── sql │ ├── 01-change-tracking-setup.sql │ ├── 02-stored-procedure.sql │ └── 03-data.sql ├── fitnessdb-ssdt ├── 01-change-tracking-setup.sql ├── 02-stored-procedure.sql ├── 03-data.sql ├── fitnessdb-ssdt.sln └── fitnessdb-ssdt.sqlproj ├── rest-api-app ├── .gitignore ├── CODE_OF_CONDUCT.md ├── Controllers │ ├── ControllerQuery.cs │ └── TrainingSessionSyncController.cs ├── LICENSE ├── Program.cs ├── README.md ├── SECURITY.md ├── Startup.cs ├── appsettings.json ├── azure-deploy.sh └── azure-sql-db-sync-ct-api.csproj └── sql-add-temps ├── 04-add-temperature.sql ├── 05-stored-proc-update.sql └── 06-temps-data.sql /.github/workflows/dotnetcore.yml: -------------------------------------------------------------------------------- 1 | name: .NET Core 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: windows-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Setup .NET Core 17 | uses: actions/setup-dotnet@v1 18 | with: 19 | dotnet-version: 3.1.101 20 | - name: Change folder and install depen 21 | run: cd fitnessdb-dbup; dotnet restore 22 | - name: Run 23 | env: # as an environment variable 24 | ConnectionString: ${{ secrets.CONNECTIONSTRING }} 25 | SQLPassword: ${{ secrets.SQLPASSWORD }} 26 | run: cd fitnessdb-dbup; dotnet run 27 | 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | fitnessdb-ssdt/fitnessdb-ssdt.jfm 244 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.vspscc 94 | *.vssscc 95 | .builds 96 | *.pidb 97 | *.svclog 98 | *.scc 99 | 100 | # Chutzpah Test files 101 | _Chutzpah* 102 | 103 | # Visual C++ cache files 104 | ipch/ 105 | *.aps 106 | *.ncb 107 | *.opendb 108 | *.opensdf 109 | *.sdf 110 | *.cachefile 111 | *.VC.db 112 | *.VC.VC.opendb 113 | 114 | # Visual Studio profiler 115 | *.psess 116 | *.vsp 117 | *.vspx 118 | *.sap 119 | 120 | # Visual Studio Trace Files 121 | *.e2e 122 | 123 | # TFS 2012 Local Workspace 124 | $tf/ 125 | 126 | # Guidance Automation Toolkit 127 | *.gpState 128 | 129 | # ReSharper is a .NET coding add-in 130 | _ReSharper*/ 131 | *.[Rr]e[Ss]harper 132 | *.DotSettings.user 133 | 134 | # TeamCity is a build add-in 135 | _TeamCity* 136 | 137 | # DotCover is a Code Coverage Tool 138 | *.dotCover 139 | 140 | # AxoCover is a Code Coverage Tool 141 | .axoCover/* 142 | !.axoCover/settings.json 143 | 144 | # Coverlet is a free, cross platform Code Coverage Tool 145 | coverage*.json 146 | coverage*.xml 147 | coverage*.info 148 | 149 | # Visual Studio code coverage results 150 | *.coverage 151 | *.coveragexml 152 | 153 | # NCrunch 154 | _NCrunch_* 155 | .*crunch*.local.xml 156 | nCrunchTemp_* 157 | 158 | # MightyMoose 159 | *.mm.* 160 | AutoTest.Net/ 161 | 162 | # Web workbench (sass) 163 | .sass-cache/ 164 | 165 | # Installshield output folder 166 | [Ee]xpress/ 167 | 168 | # DocProject is a documentation generator add-in 169 | DocProject/buildhelp/ 170 | DocProject/Help/*.HxT 171 | DocProject/Help/*.HxC 172 | DocProject/Help/*.hhc 173 | DocProject/Help/*.hhk 174 | DocProject/Help/*.hhp 175 | DocProject/Help/Html2 176 | DocProject/Help/html 177 | 178 | # Click-Once directory 179 | publish/ 180 | 181 | # Publish Web Output 182 | *.[Pp]ublish.xml 183 | *.azurePubxml 184 | # Note: Comment the next line if you want to checkin your web deploy settings, 185 | # but database connection strings (with potential passwords) will be unencrypted 186 | *.pubxml 187 | *.publishproj 188 | 189 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 190 | # checkin your Azure Web App publish settings, but sensitive information contained 191 | # in these scripts will be unencrypted 192 | PublishScripts/ 193 | 194 | # NuGet Packages 195 | *.nupkg 196 | # NuGet Symbol Packages 197 | *.snupkg 198 | # The packages folder can be ignored because of Package Restore 199 | **/[Pp]ackages/* 200 | # except build/, which is used as an MSBuild target. 201 | !**/[Pp]ackages/build/ 202 | # Uncomment if necessary however generally it will be regenerated when needed 203 | #!**/[Pp]ackages/repositories.config 204 | # NuGet v3's project.json files produces more ignorable files 205 | *.nuget.props 206 | *.nuget.targets 207 | 208 | # Microsoft Azure Build Output 209 | csx/ 210 | *.build.csdef 211 | 212 | # Microsoft Azure Emulator 213 | ecf/ 214 | rcf/ 215 | 216 | # Windows Store app package directories and files 217 | AppPackages/ 218 | BundleArtifacts/ 219 | Package.StoreAssociation.xml 220 | _pkginfo.txt 221 | *.appx 222 | *.appxbundle 223 | *.appxupload 224 | 225 | # Visual Studio cache files 226 | # files ending in .cache can be ignored 227 | *.[Cc]ache 228 | # but keep track of directories ending in .cache 229 | !?*.[Cc]ache/ 230 | 231 | # Others 232 | ClientBin/ 233 | ~$* 234 | *~ 235 | *.dbmdl 236 | *.dbproj.schemaview 237 | *.jfm 238 | *.pfx 239 | *.publishsettings 240 | orleans.codegen.cs 241 | 242 | # Including strong name files can present a security risk 243 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 244 | #*.snk 245 | 246 | # Since there are multiple workflows, uncomment next line to ignore bower_components 247 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 248 | #bower_components/ 249 | 250 | # RIA/Silverlight projects 251 | Generated_Code/ 252 | 253 | # Backup & report files from converting an old project file 254 | # to a newer Visual Studio version. Backup files are not needed, 255 | # because we have git ;-) 256 | _UpgradeReport_Files/ 257 | Backup*/ 258 | UpgradeLog*.XML 259 | UpgradeLog*.htm 260 | ServiceFabricBackup/ 261 | *.rptproj.bak 262 | 263 | # SQL Server files 264 | *.mdf 265 | *.ldf 266 | *.ndf 267 | 268 | # Business Intelligence projects 269 | *.rdl.data 270 | *.bim.layout 271 | *.bim_*.settings 272 | *.rptproj.rsuser 273 | *- [Bb]ackup.rdl 274 | *- [Bb]ackup ([0-9]).rdl 275 | *- [Bb]ackup ([0-9][0-9]).rdl 276 | 277 | # Microsoft Fakes 278 | FakesAssemblies/ 279 | 280 | # GhostDoc plugin setting file 281 | *.GhostDoc.xml 282 | 283 | # Node.js Tools for Visual Studio 284 | .ntvs_analysis.dat 285 | node_modules/ 286 | 287 | # Visual Studio 6 build log 288 | *.plg 289 | 290 | # Visual Studio 6 workspace options file 291 | *.opt 292 | 293 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 294 | *.vbw 295 | 296 | # Visual Studio LightSwitch build output 297 | **/*.HTMLClient/GeneratedArtifacts 298 | **/*.DesktopClient/GeneratedArtifacts 299 | **/*.DesktopClient/ModelManifest.xml 300 | **/*.Server/GeneratedArtifacts 301 | **/*.Server/ModelManifest.xml 302 | _Pvt_Extensions 303 | 304 | # Paket dependency manager 305 | .paket/paket.exe 306 | paket-files/ 307 | 308 | # FAKE - F# Make 309 | .fake/ 310 | 311 | # CodeRush personal settings 312 | .cr/personal 313 | 314 | # Python Tools for Visual Studio (PTVS) 315 | __pycache__/ 316 | *.pyc 317 | 318 | # Cake - Uncomment if you are using it 319 | # tools/** 320 | # !tools/packages.config 321 | 322 | # Tabs Studio 323 | *.tss 324 | 325 | # Telerik's JustMock configuration file 326 | *.jmconfig 327 | 328 | # BizTalk build output 329 | *.btp.cs 330 | *.btm.cs 331 | *.odx.cs 332 | *.xsd.cs 333 | 334 | # OpenCover UI analysis results 335 | OpenCover/ 336 | 337 | # Azure Stream Analytics local run output 338 | ASALocalRun/ 339 | 340 | # MSBuild Binary and Structured Log 341 | *.binlog 342 | 343 | # NVidia Nsight GPU debugger configuration file 344 | *.nvuser 345 | 346 | # MFractors (Xamarin productivity tool) working folder 347 | .mfractor/ 348 | 349 | # Local History for Visual Studio 350 | .localhistory/ 351 | 352 | # BeatPulse healthcheck temp database 353 | healthchecksdb 354 | 355 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 356 | MigrationBackup/ 357 | 358 | # Ionide (cross platform F# VS Code tools) working folder 359 | .ionide/ 360 | 361 | # Fody - auto-generated XML schema 362 | FodyWeavers.xsd 363 | 364 | sql/.vs/ 365 | sql/wwi-dw-ssdt/WideWorldImportersDW.sqlproj.user 366 | sql/wwi-dw-ssdt/bin/ 367 | sql/wwi-dw-ssdt/obj/ 368 | 369 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/README.md: -------------------------------------------------------------------------------- 1 | # Your A-team: Azure Data Factory, Azure SQL, Azure DevOps 2 | These are the code artifacts used in the demo for the "Your A-team: Azure Data Factory, Azure SQL, Azure DevOps" session at the [Around the Clock - Azure SQL and Azure Data Factory](https://github.com/microsoft/aroundtheclock) virtual event. The slide deck is [here](https://github.com/microsoft/aroundtheclock/blob/main/PDFs/1400%20Your%20A-team%20-%20Azure%20Data%20Factory%2C%20Azure%20SQL%2C%20Azure%20DevOps_Arvind.pdf) 3 | 4 | The sub-folders are: 5 | * sql: contains a modified [WideWorldImportersDW](https://github.com/microsoft/sql-server-samples/tree/master/samples/databases/wide-world-importers/wwi-dw-ssdt) SQL Database ("SSDT") project compatible with Visual Studio SQL Projects and Azure Data Studio (with the SQL projects extension). 6 | * adf: sub-folders containing the datasets, linked service definitions, pipeline and ADF definition. 7 | * devops: Azure DevOps YAML pipeline which orchestrates the 0-touch deployment of a logical SQL server, elastic pool, database, DACPAC based schema deployment, ADF deployment using the community-supported [Deploy Azure Data Factory by SQLPlayer](https://marketplace.visualstudio.com/items?itemName=SQLPlayer.DataFactoryTools) task. 8 | 9 | If you want to try this out yourself, you will need: 10 | * An Azure subscription 11 | * A storage account within the subscription, with a container and one file uploaded to that container. This file should be named `wwidw-customer.txt` and contain a few lines corresponding to the CSV schema at the bottom of this page. 12 | * An Azure Key Vault created in the subscription with the following secrets populated: 13 | * `sql-password` - the password used for 2 SQL authentication users defined within the SQL ("SSDT") project 14 | * `wwi-blob-sas` - Azure SAS to the container, with List and Read permissions only. 15 | * `wwi-sql-db` - ADO.NET connection string to Azure SQL. 16 | * Azure DevOps (ADO) account, organization and project 17 | * The code from this folder pushed to a repo within that ADO project 18 | * An ADO Service Connection to the Azure subscription mentioned previously 19 | * The SPN used for the above Service Connection should additionally be granted access to the AzureKey Vault to obtain the secrets used within the ADO pipeline 20 | * Create a ADO pipeline from the deploy-all.yml file under the devops sub-folder 21 | * Create the following variables for that pipeline: 22 | * `akv-name` 23 | * `data-factory-name` 24 | * `elastic-pool-name` 25 | * `logical-sql-server-name` 26 | * `resource-group-name` 27 | * `sql-admin-login` 28 | * `sql-database-name` 29 | * `subscription-name` 30 | * The above variables should be populated with suitable values corresponding to your Azure subscription 31 | * Install the the community-supported [Deploy Azure Data Factory by SQLPlayer](https://marketplace.visualstudio.com/items?itemName=SQLPlayer.DataFactoryTools) task into your ADO project. 32 | 33 | ### Sample data for the wwidw-customer.txt file: 34 | ``` csv 35 | "Customer Key","WWI Customer ID","Customer","Bill To Customer","Category","Buying Group","Primary Contact","Postal Code","Valid From","Valid To","Lineage Key" 36 | "0","0","Unknown","N/A","N/A","N/A","N/A","N/A","2013-01-01 00:00:00.0000000","9999-12-31 23:59:59.9999999","0" 37 | "1","1","Tailspin Toys (Head Office)","Tailspin Toys (Head Office)","Novelty Shop","Tailspin Toys","Waldemar Fisar","90410","2013-01-01 00:00:00.0000000","9999-12-31 23:59:59.9999999","2" 38 | "2","2","Tailspin Toys (Sylvanite, MT)","Tailspin Toys (Head Office)","Novelty Shop","Tailspin Toys","Lorena Cindric","90216","2013-01-01 00:00:00.0000000","9999-12-31 23:59:59.9999999","2" 39 | "3","3","Tailspin Toys (Peeples Valley, AZ)","Tailspin Toys (Head Office)","Novelty Shop","Tailspin Toys","Bhaargav Rambhatla","90205","2013-01-01 00:00:00.0000000","9999-12-31 23:59:59.9999999","2" 40 | "4","4","Tailspin Toys (Medicine Lodge, KS)","Tailspin Toys (Head Office)","Novelty Shop","Tailspin Toys","Daniel Roman","90152","2013-01-01 00:00:00.0000000","9999-12-31 23:59:59.9999999","2" 41 | "5","5","Tailspin Toys (Gasport, NY)","Tailspin Toys (Head Office)","Novelty Shop","Tailspin Toys","Johanna Huiting","90261","2013-01-01 00:00:00.0000000","9999-12-31 23:59:59.9999999","2" 42 | "6","6","Tailspin Toys (Jessie, ND)","Tailspin Toys (Head Office)","Novelty Shop","Tailspin Toys","Biswajeet Thakur","90298","2013-01-01 00:00:00.0000000","9999-12-31 23:59:59.9999999","2" 43 | "7","7","Tailspin Toys (Frankewing, TN)","Tailspin Toys (Head Office)","Novelty Shop","Tailspin Toys","Kalidas Nadar","90761","2013-01-01 00:00:00.0000000","9999-12-31 23:59:59.9999999","2" 44 | "8","8","Tailspin Toys (Bow Mar, CO)","Tailspin Toys (Head Office)","Novelty Shop","Tailspin Toys","Kanti Kotadia","90484","2013-01-01 00:00:00.0000000","9999-12-31 23:59:59.9999999","2" 45 | "9","9","Tailspin Toys (Netcong, NJ)","Tailspin Toys (Head Office)","Novelty Shop","Tailspin Toys","Sointu Aalto","90129","2013-01-01 00:00:00.0000000","9999-12-31 23:59:59.9999999","2" 46 | "10","10","Tailspin Toys (Wimbledon, ND)","Tailspin Toys (Head Office)","Novelty Shop","Tailspin Toys","Siddhartha Parkar","90061","2013-01-01 00:00:00.0000000","9999-12-31 23:59:59.9999999","2" 47 | ``` 48 | 49 | # Disclaimers 50 | ##### THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 51 | 52 | ##### By running the scripts against your Microsoft Azure subscription, you assume full responsibility for any charges incurred. 53 | 54 | ##### This sample code is not supported under any Microsoft standard support program or service. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages. 55 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/adf/dataset/customer_csv.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "customer_csv", 3 | "properties": { 4 | "linkedServiceName": { 5 | "referenceName": "atc_adf_sql_blob", 6 | "type": "LinkedServiceReference" 7 | }, 8 | "annotations": [], 9 | "type": "DelimitedText", 10 | "typeProperties": { 11 | "location": { 12 | "type": "AzureBlobStorageLocation", 13 | "fileName": "wwidw-customer.txt", 14 | "container": "data" 15 | }, 16 | "columnDelimiter": ",", 17 | "escapeChar": "\\", 18 | "firstRowAsHeader": true, 19 | "quoteChar": "\"" 20 | }, 21 | "schema": [ 22 | { 23 | "name": "Customer Key", 24 | "type": "String" 25 | }, 26 | { 27 | "name": "WWI Customer ID", 28 | "type": "String" 29 | }, 30 | { 31 | "name": "Customer", 32 | "type": "String" 33 | }, 34 | { 35 | "name": "Bill To Customer", 36 | "type": "String" 37 | }, 38 | { 39 | "name": "Category", 40 | "type": "String" 41 | }, 42 | { 43 | "name": "Buying Group", 44 | "type": "String" 45 | }, 46 | { 47 | "name": "Primary Contact", 48 | "type": "String" 49 | }, 50 | { 51 | "name": "Postal Code", 52 | "type": "String" 53 | }, 54 | { 55 | "name": "Valid From", 56 | "type": "String" 57 | }, 58 | { 59 | "name": "Valid To", 60 | "type": "String" 61 | }, 62 | { 63 | "name": "Lineage Key", 64 | "type": "String" 65 | } 66 | ] 67 | } 68 | } -------------------------------------------------------------------------------- /atc-adf-sql-demo/adf/dataset/customer_sql_table.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "customer_sql_table", 3 | "properties": { 4 | "linkedServiceName": { 5 | "referenceName": "atc_adf_sql", 6 | "type": "LinkedServiceReference" 7 | }, 8 | "annotations": [], 9 | "type": "AzureSqlTable", 10 | "schema": [], 11 | "typeProperties": { 12 | "schema": "Dimension", 13 | "table": "Customer" 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /atc-adf-sql-demo/adf/factory/atc-adf-sql-dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atc-adf-sql-dev", 3 | "location": "eastus" 4 | } -------------------------------------------------------------------------------- /atc-adf-sql-demo/adf/linkedService/atc_adf_sql.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atc_adf_sql", 3 | "properties": { 4 | "annotations": [], 5 | "type": "AzureSqlDatabase", 6 | "typeProperties": { 7 | "connectionString": { 8 | "type": "AzureKeyVaultSecret", 9 | "store": { 10 | "referenceName": "atc_adf_sql_akv", 11 | "type": "LinkedServiceReference" 12 | }, 13 | "secretName": "wwi-sql-db" 14 | } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /atc-adf-sql-demo/adf/linkedService/atc_adf_sql_akv.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atc_adf_sql_akv", 3 | "properties": { 4 | "annotations": [], 5 | "type": "AzureKeyVault", 6 | "typeProperties": { 7 | "baseUrl": "https://someakv.vault.azure.net" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /atc-adf-sql-demo/adf/linkedService/atc_adf_sql_blob.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atc_adf_sql_blob", 3 | "properties": { 4 | "annotations": [], 5 | "type": "AzureBlobStorage", 6 | "typeProperties": { 7 | "sasUri": { 8 | "type": "AzureKeyVaultSecret", 9 | "store": { 10 | "referenceName": "atc_adf_sql_akv", 11 | "type": "LinkedServiceReference" 12 | }, 13 | "secretName": "wwi-blob-sas" 14 | } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /atc-adf-sql-demo/adf/pipeline/copy_customer_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "copy_customer_data", 3 | "properties": { 4 | "activities": [ 5 | { 6 | "name": "reference_data_pipeline", 7 | "type": "Copy", 8 | "dependsOn": [], 9 | "policy": { 10 | "timeout": "7.00:00:00", 11 | "retry": 0, 12 | "retryIntervalInSeconds": 30, 13 | "secureOutput": false, 14 | "secureInput": false 15 | }, 16 | "userProperties": [], 17 | "typeProperties": { 18 | "source": { 19 | "type": "DelimitedTextSource", 20 | "storeSettings": { 21 | "type": "AzureBlobStorageReadSettings", 22 | "recursive": true, 23 | "enablePartitionDiscovery": false 24 | }, 25 | "formatSettings": { 26 | "type": "DelimitedTextReadSettings" 27 | } 28 | }, 29 | "sink": { 30 | "type": "AzureSqlSink" 31 | }, 32 | "enableStaging": false, 33 | "translator": { 34 | "type": "TabularTranslator", 35 | "mappings": [ 36 | { 37 | "source": { 38 | "name": "Customer Key", 39 | "type": "String", 40 | "physicalType": "String" 41 | }, 42 | "sink": { 43 | "name": "Customer Key", 44 | "type": "Int32", 45 | "physicalType": "int" 46 | } 47 | }, 48 | { 49 | "source": { 50 | "name": "WWI Customer ID", 51 | "type": "String", 52 | "physicalType": "String" 53 | }, 54 | "sink": { 55 | "name": "WWI Customer ID", 56 | "type": "Int32", 57 | "physicalType": "int" 58 | } 59 | }, 60 | { 61 | "source": { 62 | "name": "Customer", 63 | "type": "String", 64 | "physicalType": "String" 65 | }, 66 | "sink": { 67 | "name": "Customer", 68 | "type": "String", 69 | "physicalType": "nvarchar" 70 | } 71 | }, 72 | { 73 | "source": { 74 | "name": "Bill To Customer", 75 | "type": "String", 76 | "physicalType": "String" 77 | }, 78 | "sink": { 79 | "name": "Bill To Customer", 80 | "type": "String", 81 | "physicalType": "nvarchar" 82 | } 83 | }, 84 | { 85 | "source": { 86 | "name": "Category", 87 | "type": "String", 88 | "physicalType": "String" 89 | }, 90 | "sink": { 91 | "name": "Category", 92 | "type": "String", 93 | "physicalType": "nvarchar" 94 | } 95 | }, 96 | { 97 | "source": { 98 | "name": "Buying Group", 99 | "type": "String", 100 | "physicalType": "String" 101 | }, 102 | "sink": { 103 | "name": "Buying Group", 104 | "type": "String", 105 | "physicalType": "nvarchar" 106 | } 107 | }, 108 | { 109 | "source": { 110 | "name": "Primary Contact", 111 | "type": "String", 112 | "physicalType": "String" 113 | }, 114 | "sink": { 115 | "name": "Primary Contact", 116 | "type": "String", 117 | "physicalType": "nvarchar" 118 | } 119 | }, 120 | { 121 | "source": { 122 | "name": "Postal Code", 123 | "type": "String", 124 | "physicalType": "String" 125 | }, 126 | "sink": { 127 | "name": "Postal Code", 128 | "type": "String", 129 | "physicalType": "nvarchar" 130 | } 131 | }, 132 | { 133 | "source": { 134 | "name": "Valid From", 135 | "type": "String", 136 | "physicalType": "String" 137 | }, 138 | "sink": { 139 | "name": "Valid From", 140 | "type": "DateTime", 141 | "physicalType": "datetime2" 142 | } 143 | }, 144 | { 145 | "source": { 146 | "name": "Valid To", 147 | "type": "String", 148 | "physicalType": "String" 149 | }, 150 | "sink": { 151 | "name": "Valid To", 152 | "type": "DateTime", 153 | "physicalType": "datetime2" 154 | } 155 | }, 156 | { 157 | "source": { 158 | "name": "Lineage Key", 159 | "type": "String", 160 | "physicalType": "String" 161 | }, 162 | "sink": { 163 | "name": "Lineage Key", 164 | "type": "Int32", 165 | "physicalType": "int" 166 | } 167 | } 168 | ], 169 | "typeConversion": true, 170 | "typeConversionSettings": { 171 | "allowDataTruncation": true, 172 | "treatBooleanAsNumber": false 173 | } 174 | } 175 | }, 176 | "inputs": [ 177 | { 178 | "referenceName": "customer_csv", 179 | "type": "DatasetReference" 180 | } 181 | ], 182 | "outputs": [ 183 | { 184 | "referenceName": "customer_sql_table", 185 | "type": "DatasetReference" 186 | } 187 | ] 188 | } 189 | ], 190 | "annotations": [] 191 | } 192 | } -------------------------------------------------------------------------------- /atc-adf-sql-demo/devops/pipelines/deploy-all.yml: -------------------------------------------------------------------------------- 1 | # Starter pipeline 2 | # Start with a minimal pipeline that you can customize to build and deploy your code. 3 | # Add steps that build, run tests, deploy, and more: 4 | # https://aka.ms/yaml 5 | 6 | trigger: 7 | - main 8 | 9 | pool: 10 | vmImage: 'windows-latest' 11 | 12 | variables: 13 | - group: 'secrets' 14 | - name: solution 15 | value: '**/*.sln' 16 | - name: buildPlatform 17 | value: 'Any CPU' 18 | - name: buildConfiguration 19 | value: 'Release' 20 | 21 | steps: 22 | - task: AzureCLI@2 23 | displayName: 'Create and configure Azure SQL logical server' 24 | inputs: 25 | azureSubscription: '$(subscription-name)' 26 | scriptType: 'bash' 27 | scriptLocation: 'inlineScript' 28 | inlineScript: | 29 | az sql server create --resource-group $(resource-group-name) --name $(logical-sql-server-name) --admin-user $(sql-admin-login) --admin-password $(sql-password) 30 | 31 | az sql server ad-admin create --resource-group $(resource-group-name) --server-name $(logical-sql-server-name) --display-name $(az ad sp show --id $(az account show --query user.name --output tsv) --query appDisplayName --output tsv) --object-id $(az account show --query user.name --output tsv) 32 | 33 | az sql server firewall-rule create -g $(resource-group-name) -s $(logical-sql-server-name) -n allow-azure-services --start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0 34 | 35 | - task: AzureCLI@2 36 | displayName: 'Create Azure SQL Elastic Pool and Database' 37 | inputs: 38 | azureSubscription: '$(subscription-name)' 39 | scriptType: 'bash' 40 | scriptLocation: 'inlineScript' 41 | inlineScript: | 42 | az sql elastic-pool create -g $(resource-group-name) -s $(logical-sql-server-name) -n $(elastic-pool-name) -e GeneralPurpose -f Gen4 -c 1 43 | 44 | az sql db create --resource-group $(resource-group-name) --server $(logical-sql-server-name) --name $(sql-database-name) --elastic-pool $(elastic-pool-name) 45 | 46 | - task: VSBuild@1 47 | displayName: 'Build DACPAC from SQL Database Project' 48 | inputs: 49 | solution: '$(solution)' 50 | platform: '$(buildPlatform)' 51 | configuration: '$(buildConfiguration)' 52 | 53 | - task: PublishBuildArtifacts@1 54 | displayName: 'Publish SQL Project output as Azure DevOps artifacts' 55 | inputs: 56 | PathtoPublish: '$(System.DefaultWorkingDirectory)/sql' 57 | ArtifactName: 'sqlproj_artifacts_$(System.JobAttempt)' 58 | publishLocation: 'Container' 59 | 60 | - task: DownloadBuildArtifacts@0 61 | displayName: 'Download the artifacts' 62 | inputs: 63 | buildType: 'current' 64 | downloadType: 'single' 65 | artifactName: 'sqlproj_artifacts_$(System.JobAttempt)' 66 | downloadPath: '$(System.ArtifactsDirectory)' 67 | 68 | - task: SqlAzureDacpacDeployment@1 69 | displayName: 'Deploy Azure SQL DB' 70 | inputs: 71 | azureSubscription: '$(subscription-name)' 72 | AuthenticationType: 'servicePrincipal' 73 | ServerName: '$(logical-sql-server-name).database.windows.net' 74 | DatabaseName: '$(sql-database-name)' 75 | deployType: 'DacpacTask' 76 | DeploymentAction: 'Publish' 77 | DacpacFile: '$(System.ArtifactsDirectory)/sqlproj_artifacts_$(System.JobAttempt)/wwi-dw-ssdt/bin/Release/WideWorldImportersDW.dacpac' 78 | AdditionalArguments: '/v:ETLUserPassword="$(sql-password)" /v:AppUserPassword="$(sql-password)"' 79 | IpDetectionMethod: 'AutoDetect' 80 | DeleteFirewallRule: false 81 | 82 | - task: PublishADFTask@1 83 | displayName: 'Publish Azure Data Factory' 84 | inputs: 85 | azureSubscription: '$(subscription-name)' 86 | ResourceGroupName: '$(resource-group-name)' 87 | DataFactoryName: '$(data-factory-name)' 88 | DataFactoryCodePath: '$(System.DefaultWorkingDirectory)/adf' 89 | Location: 'eastus' 90 | PublishMethod: 'AzResource' 91 | 92 | - task: AzurePowerShell@5 93 | displayName: 'Allow ADF to access AKV' 94 | inputs: 95 | azureSubscription: '$(subscription-name)' 96 | ScriptType: 'InlineScript' 97 | Inline: 'Set-AzKeyVaultAccessPolicy -VaultName "$(akv-name)" -ObjectId ((Get-AzDataFactoryV2 -ResourceGroupName "$(resource-group-name)" -Name "$(data-factory-name)").Identity.PrincipalId) -PermissionsToSecrets @("get","list") -BypassObjectIdValidation' 98 | azurePowerShellVersion: 'LatestVersion' 99 | 100 | - task: AzurePowerShell@5 101 | displayName: 'Run and wait for ADF pipeline to complete' 102 | inputs: 103 | azureSubscription: '$(subscription-name)' 104 | ScriptType: 'InlineScript' 105 | Inline: | 106 | $DataFactoryName = "$(data-factory-name)" 107 | $resourceGroupName = "$(resource-group-name)" 108 | 109 | $runId = Invoke-AzDataFactoryV2Pipeline -DataFactoryName "$(data-factory-name)" -ResourceGroupName "$(resource-group-name)" -PipelineName "copy_customer_data" 110 | 111 | while ($True) { 112 | $run = Get-AzDataFactoryV2PipelineRun -ResourceGroupName $resourceGroupName -DataFactoryName $DataFactoryName -PipelineRunId $runId 113 | 114 | if ($run) { 115 | if ($run.Status -ne 'InProgress') { 116 | Write-Host "ADF Pipeline run finished. The status is: " $run.Status -foregroundcolor "Yellow" 117 | $run 118 | if ($run.Status -ne "Succeeded") { 119 | throw ("ADF Pipeline failed") 120 | } 121 | break 122 | } 123 | Write-Host "Pipeline is running...status: InProgress" -foregroundcolor "Yellow" 124 | } 125 | 126 | Start-Sleep -Seconds 5 127 | } 128 | azurePowerShellVersion: 'LatestVersion' 129 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/WideWorldImportersDW.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "WideWorldImportersDW", "wwi-dw-ssdt\WideWorldImportersDW.sqlproj", "{79C14C29-3A96-4B59-BC92-0290AF92F05B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {79C14C29-3A96-4B59-BC92-0290AF92F05B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {79C14C29-3A96-4B59-BC92-0290AF92F05B}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {79C14C29-3A96-4B59-BC92-0290AF92F05B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {79C14C29-3A96-4B59-BC92-0290AF92F05B}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {79C14C29-3A96-4B59-BC92-0290AF92F05B}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {79C14C29-3A96-4B59-BC92-0290AF92F05B}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | EndGlobal 25 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Dimension/Tables/City.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Dimension].[City] ( 2 | [City Key] INT CONSTRAINT [DF_Dimension_City_City_Key] DEFAULT (NEXT VALUE FOR [Sequences].[CityKey]) NOT NULL, 3 | [WWI City ID] INT NOT NULL, 4 | [City] NVARCHAR (50) NOT NULL, 5 | [State Province] NVARCHAR (50) NOT NULL, 6 | [Country] NVARCHAR (60) NOT NULL, 7 | [Continent] NVARCHAR (30) NOT NULL, 8 | [Sales Territory] NVARCHAR (50) NOT NULL, 9 | [Region] NVARCHAR (30) NOT NULL, 10 | [Subregion] NVARCHAR (30) NOT NULL, 11 | [Location] [sys].[geography] NULL, 12 | [Latest Recorded Population] BIGINT NOT NULL, 13 | [Valid From] DATETIME2 (7) NOT NULL, 14 | [Valid To] DATETIME2 (7) NOT NULL, 15 | [Lineage Key] INT NOT NULL, 16 | CONSTRAINT [PK_Dimension_City] PRIMARY KEY CLUSTERED ([City Key] ASC) 17 | ); 18 | 19 | 20 | GO 21 | CREATE NONCLUSTERED INDEX [IX_Dimension_City_WWICityID] 22 | ON [Dimension].[City]([WWI City ID] ASC, [Valid From] ASC, [Valid To] ASC); 23 | 24 | 25 | GO 26 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Allows quickly locating by WWI ID', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'INDEX', @level2name = N'IX_Dimension_City_WWICityID'; 27 | 28 | 29 | GO 30 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'City dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City'; 31 | 32 | 33 | GO 34 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for the city dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'City Key'; 35 | 36 | 37 | GO 38 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Numeric ID used for reference to a city within the WWI database', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'WWI City ID'; 39 | 40 | 41 | GO 42 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Formal name of the city', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'City'; 43 | 44 | 45 | GO 46 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'State or province for this city', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'State Province'; 47 | 48 | 49 | GO 50 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Country name', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'Country'; 51 | 52 | 53 | GO 54 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Continent that this city is on', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'Continent'; 55 | 56 | 57 | GO 58 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Sales territory for this StateProvince', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'Sales Territory'; 59 | 60 | 61 | GO 62 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Name of the region', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'Region'; 63 | 64 | 65 | GO 66 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Name of the subregion', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'Subregion'; 67 | 68 | 69 | GO 70 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Geographic location of the city', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'Location'; 71 | 72 | 73 | GO 74 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Latest available population for the City', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'Latest Recorded Population'; 75 | 76 | 77 | GO 78 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid from this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'Valid From'; 79 | 80 | 81 | GO 82 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid until this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'Valid To'; 83 | 84 | 85 | GO 86 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Lineage Key for the data load for this row', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'City', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 87 | 88 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Dimension/Tables/Customer.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Dimension].[Customer] ( 2 | [Customer Key] INT CONSTRAINT [DF_Dimension_Customer_Customer_Key] DEFAULT (NEXT VALUE FOR [Sequences].[CustomerKey]) NOT NULL, 3 | [WWI Customer ID] INT NOT NULL, 4 | [Customer] NVARCHAR (100) NOT NULL, 5 | [Bill To Customer] NVARCHAR (100) NOT NULL, 6 | [Category] NVARCHAR (50) NOT NULL, 7 | [Buying Group] NVARCHAR (50) NOT NULL, 8 | [Primary Contact] NVARCHAR (50) NOT NULL, 9 | [Postal Code] NVARCHAR (10) NOT NULL, 10 | [Valid From] DATETIME2 (7) NOT NULL, 11 | [Valid To] DATETIME2 (7) NOT NULL, 12 | [Lineage Key] INT NOT NULL, 13 | CONSTRAINT [PK_Dimension_Customer] PRIMARY KEY CLUSTERED ([Customer Key] ASC) 14 | ); 15 | 16 | 17 | GO 18 | CREATE NONCLUSTERED INDEX [IX_Dimension_Customer_WWICustomerID] 19 | ON [Dimension].[Customer]([WWI Customer ID] ASC, [Valid From] ASC, [Valid To] ASC); 20 | 21 | 22 | GO 23 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Allows quickly locating by WWI ID', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'INDEX', @level2name = N'IX_Dimension_Customer_WWICustomerID'; 24 | 25 | 26 | GO 27 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Customer dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer'; 28 | 29 | 30 | GO 31 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for the customer dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'COLUMN', @level2name = N'Customer Key'; 32 | 33 | 34 | GO 35 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Numeric ID used for reference to a customer within the WWI database', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'COLUMN', @level2name = N'WWI Customer ID'; 36 | 37 | 38 | GO 39 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Customer''s full name (usually a trading name)', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'COLUMN', @level2name = N'Customer'; 40 | 41 | 42 | GO 43 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Bill to customer''s full name', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'COLUMN', @level2name = N'Bill To Customer'; 44 | 45 | 46 | GO 47 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Customer''s category', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'COLUMN', @level2name = N'Category'; 48 | 49 | 50 | GO 51 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Customer''s buying group', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'COLUMN', @level2name = N'Buying Group'; 52 | 53 | 54 | GO 55 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Primary contact', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'COLUMN', @level2name = N'Primary Contact'; 56 | 57 | 58 | GO 59 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Delivery postal code for the customer', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'COLUMN', @level2name = N'Postal Code'; 60 | 61 | 62 | GO 63 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid from this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'COLUMN', @level2name = N'Valid From'; 64 | 65 | 66 | GO 67 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid until this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'COLUMN', @level2name = N'Valid To'; 68 | 69 | 70 | GO 71 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Lineage Key for the data load for this row', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Customer', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 72 | 73 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Dimension/Tables/Employee.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Dimension].[Employee] ( 2 | [Employee Key] INT CONSTRAINT [DF_Dimension_Employee_Employee_Key] DEFAULT (NEXT VALUE FOR [Sequences].[EmployeeKey]) NOT NULL, 3 | [WWI Employee ID] INT NOT NULL, 4 | [Employee] NVARCHAR (50) NOT NULL, 5 | [Preferred Name] NVARCHAR (50) NOT NULL, 6 | [Is Salesperson] BIT NOT NULL, 7 | [Photo] VARBINARY (MAX) NULL, 8 | [Valid From] DATETIME2 (7) NOT NULL, 9 | [Valid To] DATETIME2 (7) NOT NULL, 10 | [Lineage Key] INT NOT NULL, 11 | CONSTRAINT [PK_Dimension_Employee] PRIMARY KEY CLUSTERED ([Employee Key] ASC) 12 | ); 13 | 14 | 15 | GO 16 | CREATE NONCLUSTERED INDEX [IX_Dimension_Employee_WWIEmployeeID] 17 | ON [Dimension].[Employee]([WWI Employee ID] ASC, [Valid From] ASC, [Valid To] ASC); 18 | 19 | 20 | GO 21 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Allows quickly locating by WWI ID', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Employee', @level2type = N'INDEX', @level2name = N'IX_Dimension_Employee_WWIEmployeeID'; 22 | 23 | 24 | GO 25 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Employee dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Employee'; 26 | 27 | 28 | GO 29 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for the employee dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Employee', @level2type = N'COLUMN', @level2name = N'Employee Key'; 30 | 31 | 32 | GO 33 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Numeric ID (PersonID) in the WWI database', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Employee', @level2type = N'COLUMN', @level2name = N'WWI Employee ID'; 34 | 35 | 36 | GO 37 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Full name for this person', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Employee', @level2type = N'COLUMN', @level2name = N'Employee'; 38 | 39 | 40 | GO 41 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Name that this person prefers to be called', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Employee', @level2type = N'COLUMN', @level2name = N'Preferred Name'; 42 | 43 | 44 | GO 45 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Is this person a staff salesperson?', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Employee', @level2type = N'COLUMN', @level2name = N'Is Salesperson'; 46 | 47 | 48 | GO 49 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Photo of this person', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Employee', @level2type = N'COLUMN', @level2name = N'Photo'; 50 | 51 | 52 | GO 53 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid from this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Employee', @level2type = N'COLUMN', @level2name = N'Valid From'; 54 | 55 | 56 | GO 57 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid until this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Employee', @level2type = N'COLUMN', @level2name = N'Valid To'; 58 | 59 | 60 | GO 61 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Lineage Key for the data load for this row', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Employee', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 62 | 63 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Dimension/Tables/Payment Method.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Dimension].[Payment Method] ( 2 | [Payment Method Key] INT CONSTRAINT [DF_Dimension_Payment_Method_Payment_Method_Key] DEFAULT (NEXT VALUE FOR [Sequences].[PaymentMethodKey]) NOT NULL, 3 | [WWI Payment Method ID] INT NOT NULL, 4 | [Payment Method] NVARCHAR (50) NOT NULL, 5 | [Valid From] DATETIME2 (7) NOT NULL, 6 | [Valid To] DATETIME2 (7) NOT NULL, 7 | [Lineage Key] INT NOT NULL, 8 | CONSTRAINT [PK_Dimension_Payment_Method] PRIMARY KEY CLUSTERED ([Payment Method Key] ASC) 9 | ); 10 | 11 | 12 | GO 13 | CREATE NONCLUSTERED INDEX [IX_Dimension_Payment_Method_WWIPaymentMethodID] 14 | ON [Dimension].[Payment Method]([WWI Payment Method ID] ASC, [Valid From] ASC, [Valid To] ASC); 15 | 16 | 17 | GO 18 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Allows quickly locating by WWI ID', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Payment Method', @level2type = N'INDEX', @level2name = N'IX_Dimension_Payment_Method_WWIPaymentMethodID'; 19 | 20 | 21 | GO 22 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'PaymentMethod dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Payment Method'; 23 | 24 | 25 | GO 26 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for the payment method dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Payment Method', @level2type = N'COLUMN', @level2name = N'Payment Method Key'; 27 | 28 | 29 | GO 30 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Numeric ID for the payment method in the WWI database', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Payment Method', @level2type = N'COLUMN', @level2name = N'WWI Payment Method ID'; 31 | 32 | 33 | GO 34 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Payment method name', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Payment Method', @level2type = N'COLUMN', @level2name = N'Payment Method'; 35 | 36 | 37 | GO 38 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid from this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Payment Method', @level2type = N'COLUMN', @level2name = N'Valid From'; 39 | 40 | 41 | GO 42 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid until this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Payment Method', @level2type = N'COLUMN', @level2name = N'Valid To'; 43 | 44 | 45 | GO 46 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Lineage Key for the data load for this row', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Payment Method', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 47 | 48 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Dimension/Tables/Stock Item.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Dimension].[Stock Item] ( 2 | [Stock Item Key] INT CONSTRAINT [DF_Dimension_Stock_Item_Stock_Item_Key] DEFAULT (NEXT VALUE FOR [Sequences].[StockItemKey]) NOT NULL, 3 | [WWI Stock Item ID] INT NOT NULL, 4 | [Stock Item] NVARCHAR (100) NOT NULL, 5 | [Color] NVARCHAR (20) NOT NULL, 6 | [Selling Package] NVARCHAR (50) NOT NULL, 7 | [Buying Package] NVARCHAR (50) NOT NULL, 8 | [Brand] NVARCHAR (50) NOT NULL, 9 | [Size] NVARCHAR (20) NOT NULL, 10 | [Lead Time Days] INT NOT NULL, 11 | [Quantity Per Outer] INT NOT NULL, 12 | [Is Chiller Stock] BIT NOT NULL, 13 | [Barcode] NVARCHAR (50) NULL, 14 | [Tax Rate] DECIMAL (18, 3) NOT NULL, 15 | [Unit Price] DECIMAL (18, 2) NOT NULL, 16 | [Recommended Retail Price] DECIMAL (18, 2) NULL, 17 | [Typical Weight Per Unit] DECIMAL (18, 3) NOT NULL, 18 | [Photo] VARBINARY (MAX) NULL, 19 | [Valid From] DATETIME2 (7) NOT NULL, 20 | [Valid To] DATETIME2 (7) NOT NULL, 21 | [Lineage Key] INT NOT NULL, 22 | CONSTRAINT [PK_Dimension_Stock_Item] PRIMARY KEY CLUSTERED ([Stock Item Key] ASC) 23 | ); 24 | 25 | 26 | GO 27 | CREATE NONCLUSTERED INDEX [IX_Dimension_Stock_Item_WWIStockItemID] 28 | ON [Dimension].[Stock Item]([WWI Stock Item ID] ASC, [Valid From] ASC, [Valid To] ASC); 29 | 30 | 31 | GO 32 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Allows quickly locating by WWI ID', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'INDEX', @level2name = N'IX_Dimension_Stock_Item_WWIStockItemID'; 33 | 34 | 35 | GO 36 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'StockItem dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item'; 37 | 38 | 39 | GO 40 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for the stock item dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Stock Item Key'; 41 | 42 | 43 | GO 44 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Numeric ID used for reference to a stock item within the WWI database', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'WWI Stock Item ID'; 45 | 46 | 47 | GO 48 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Full name of a stock item (but not a full description)', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Stock Item'; 49 | 50 | 51 | GO 52 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Color (optional) for this stock item', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Color'; 53 | 54 | 55 | GO 56 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Usual package for selling units of this stock item', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Selling Package'; 57 | 58 | 59 | GO 60 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Usual package for selling outers of this stock item (ie cartons, boxes, etc.)', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Buying Package'; 61 | 62 | 63 | GO 64 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Brand for the stock item (if the item is branded)', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Brand'; 65 | 66 | 67 | GO 68 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Size of this item (eg: 100mm)', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Size'; 69 | 70 | 71 | GO 72 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Number of days typically taken from order to receipt of this stock item', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Lead Time Days'; 73 | 74 | 75 | GO 76 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Quantity of the stock item in an outer package', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Quantity Per Outer'; 77 | 78 | 79 | GO 80 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Does this stock item need to be in a chiller?', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Is Chiller Stock'; 81 | 82 | 83 | GO 84 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Barcode for this stock item', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Barcode'; 85 | 86 | 87 | GO 88 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Tax rate to be applied', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Tax Rate'; 89 | 90 | 91 | GO 92 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Selling price (ex-tax) for one unit of this product', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Unit Price'; 93 | 94 | 95 | GO 96 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Recommended retail price for this stock item', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Recommended Retail Price'; 97 | 98 | 99 | GO 100 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Typical weight for one unit of this product (packaged)', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Typical Weight Per Unit'; 101 | 102 | 103 | GO 104 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Photo of the product', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Photo'; 105 | 106 | 107 | GO 108 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid from this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Valid From'; 109 | 110 | 111 | GO 112 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid until this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Valid To'; 113 | 114 | 115 | GO 116 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Lineage Key for the data load for this row', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Stock Item', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 117 | 118 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Dimension/Tables/Supplier.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Dimension].[Supplier] ( 2 | [Supplier Key] INT CONSTRAINT [DF_Dimension_Supplier_Supplier_Key] DEFAULT (NEXT VALUE FOR [Sequences].[SupplierKey]) NOT NULL, 3 | [WWI Supplier ID] INT NOT NULL, 4 | [Supplier] NVARCHAR (100) NOT NULL, 5 | [Category] NVARCHAR (50) NOT NULL, 6 | [Primary Contact] NVARCHAR (50) NOT NULL, 7 | [Supplier Reference] NVARCHAR (20) NULL, 8 | [Payment Days] INT NOT NULL, 9 | [Postal Code] NVARCHAR (10) NOT NULL, 10 | [Valid From] DATETIME2 (7) NOT NULL, 11 | [Valid To] DATETIME2 (7) NOT NULL, 12 | [Lineage Key] INT NOT NULL, 13 | CONSTRAINT [PK_Dimension_Supplier] PRIMARY KEY CLUSTERED ([Supplier Key] ASC) 14 | ); 15 | 16 | 17 | GO 18 | CREATE NONCLUSTERED INDEX [IX_Dimension_Supplier_WWISupplierID] 19 | ON [Dimension].[Supplier]([WWI Supplier ID] ASC, [Valid From] ASC, [Valid To] ASC); 20 | 21 | 22 | GO 23 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Allows quickly locating by WWI ID', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'INDEX', @level2name = N'IX_Dimension_Supplier_WWISupplierID'; 24 | 25 | 26 | GO 27 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Supplier dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier'; 28 | 29 | 30 | GO 31 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for the supplier dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'COLUMN', @level2name = N'Supplier Key'; 32 | 33 | 34 | GO 35 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Numeric ID used for reference to a supplier within the WWI database', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'COLUMN', @level2name = N'WWI Supplier ID'; 36 | 37 | 38 | GO 39 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Supplier''s full name (usually a trading name)', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'COLUMN', @level2name = N'Supplier'; 40 | 41 | 42 | GO 43 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Supplier''s category', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'COLUMN', @level2name = N'Category'; 44 | 45 | 46 | GO 47 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Primary contact', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'COLUMN', @level2name = N'Primary Contact'; 48 | 49 | 50 | GO 51 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Supplier reference for our organization (might be our account number at the supplier)', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'COLUMN', @level2name = N'Supplier Reference'; 52 | 53 | 54 | GO 55 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Number of days for payment of an invoice (ie payment terms)', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'COLUMN', @level2name = N'Payment Days'; 56 | 57 | 58 | GO 59 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Delivery postal code for the supplier', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'COLUMN', @level2name = N'Postal Code'; 60 | 61 | 62 | GO 63 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid from this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'COLUMN', @level2name = N'Valid From'; 64 | 65 | 66 | GO 67 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid until this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'COLUMN', @level2name = N'Valid To'; 68 | 69 | 70 | GO 71 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Lineage Key for the data load for this row', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Supplier', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 72 | 73 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Dimension/Tables/Transaction Type.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Dimension].[Transaction Type] ( 2 | [Transaction Type Key] INT CONSTRAINT [DF_Dimension_Transaction_Type_Transaction_Type_Key] DEFAULT (NEXT VALUE FOR [Sequences].[TransactionTypeKey]) NOT NULL, 3 | [WWI Transaction Type ID] INT NOT NULL, 4 | [Transaction Type] NVARCHAR (50) NOT NULL, 5 | [Valid From] DATETIME2 (7) NOT NULL, 6 | [Valid To] DATETIME2 (7) NOT NULL, 7 | [Lineage Key] INT NOT NULL, 8 | CONSTRAINT [PK_Dimension_Transaction_Type] PRIMARY KEY CLUSTERED ([Transaction Type Key] ASC) 9 | ); 10 | 11 | 12 | GO 13 | CREATE NONCLUSTERED INDEX [IX_Dimension_Transaction_Type_WWITransactionTypeID] 14 | ON [Dimension].[Transaction Type]([WWI Transaction Type ID] ASC, [Valid From] ASC, [Valid To] ASC); 15 | 16 | 17 | GO 18 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Allows quickly locating by WWI ID', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Transaction Type', @level2type = N'INDEX', @level2name = N'IX_Dimension_Transaction_Type_WWITransactionTypeID'; 19 | 20 | 21 | GO 22 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'TransactionType dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Transaction Type'; 23 | 24 | 25 | GO 26 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for the transaction type dimension', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Transaction Type', @level2type = N'COLUMN', @level2name = N'Transaction Type Key'; 27 | 28 | 29 | GO 30 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Numeric ID used for reference to a transaction type within the WWI database', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Transaction Type', @level2type = N'COLUMN', @level2name = N'WWI Transaction Type ID'; 31 | 32 | 33 | GO 34 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Full name of the transaction type', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Transaction Type', @level2type = N'COLUMN', @level2name = N'Transaction Type'; 35 | 36 | 37 | GO 38 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid from this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Transaction Type', @level2type = N'COLUMN', @level2name = N'Valid From'; 39 | 40 | 41 | GO 42 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid until this date and time', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Transaction Type', @level2type = N'COLUMN', @level2name = N'Valid To'; 43 | 44 | 45 | GO 46 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Lineage Key for the data load for this row', @level0type = N'SCHEMA', @level0name = N'Dimension', @level1type = N'TABLE', @level1name = N'Transaction Type', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 47 | 48 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Fact/Tables/Movement.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Fact].[Movement] ( 2 | [Movement Key] BIGINT IDENTITY (1, 1) NOT NULL, 3 | [Date Key] DATE NOT NULL, 4 | [Stock Item Key] INT NOT NULL, 5 | [Customer Key] INT NULL, 6 | [Supplier Key] INT NULL, 7 | [Transaction Type Key] INT NOT NULL, 8 | [WWI Stock Item Transaction ID] INT NOT NULL, 9 | [WWI Invoice ID] INT NULL, 10 | [WWI Purchase Order ID] INT NULL, 11 | [Quantity] INT NOT NULL, 12 | [Lineage Key] INT NOT NULL, 13 | CONSTRAINT [PK_Fact_Movement] PRIMARY KEY NONCLUSTERED ([Movement Key] ASC, [Date Key] ASC) ON [PS_Date] ([Date Key]), 14 | CONSTRAINT [FK_Fact_Movement_Customer_Key_Dimension_Customer] FOREIGN KEY ([Customer Key]) REFERENCES [Dimension].[Customer] ([Customer Key]), 15 | CONSTRAINT [FK_Fact_Movement_Date_Key_Dimension_Date] FOREIGN KEY ([Date Key]) REFERENCES [Dimension].[Date] ([Date]), 16 | CONSTRAINT [FK_Fact_Movement_Stock_Item_Key_Dimension_Stock Item] FOREIGN KEY ([Stock Item Key]) REFERENCES [Dimension].[Stock Item] ([Stock Item Key]), 17 | CONSTRAINT [FK_Fact_Movement_Supplier_Key_Dimension_Supplier] FOREIGN KEY ([Supplier Key]) REFERENCES [Dimension].[Supplier] ([Supplier Key]), 18 | CONSTRAINT [FK_Fact_Movement_Transaction_Type_Key_Dimension_Transaction Type] FOREIGN KEY ([Transaction Type Key]) REFERENCES [Dimension].[Transaction Type] ([Transaction Type Key]) 19 | ); 20 | 21 | 22 | GO 23 | CREATE NONCLUSTERED INDEX [FK_Fact_Movement_Customer_Key] 24 | ON [Fact].[Movement]([Customer Key] ASC) 25 | ON [PS_Date] ([Date Key]); 26 | 27 | 28 | GO 29 | CREATE NONCLUSTERED INDEX [FK_Fact_Movement_Date_Key] 30 | ON [Fact].[Movement]([Date Key] ASC) 31 | ON [PS_Date] ([Date Key]); 32 | 33 | 34 | GO 35 | CREATE NONCLUSTERED INDEX [FK_Fact_Movement_Stock_Item_Key] 36 | ON [Fact].[Movement]([Stock Item Key] ASC) 37 | ON [PS_Date] ([Date Key]); 38 | 39 | 40 | GO 41 | CREATE NONCLUSTERED INDEX [FK_Fact_Movement_Supplier_Key] 42 | ON [Fact].[Movement]([Supplier Key] ASC) 43 | ON [PS_Date] ([Date Key]); 44 | 45 | 46 | GO 47 | CREATE NONCLUSTERED INDEX [FK_Fact_Movement_Transaction_Type_Key] 48 | ON [Fact].[Movement]([Transaction Type Key] ASC) 49 | ON [PS_Date] ([Date Key]); 50 | 51 | 52 | GO 53 | CREATE NONCLUSTERED INDEX [IX_Integration_Movement_WWI_Stock_Item_Transaction_ID] 54 | ON [Fact].[Movement]([WWI Stock Item Transaction ID] ASC) 55 | ON [PS_Date] ([Date Key]); 56 | 57 | 58 | GO 59 | CREATE CLUSTERED COLUMNSTORE INDEX [CCX_Fact_Movement] 60 | ON [Fact].[Movement] 61 | ON [PS_Date] ([Date Key]); 62 | 63 | 64 | GO 65 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Movement fact table (movements of stock items)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement'; 66 | 67 | 68 | GO 69 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for a row in the Movement fact', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement', @level2type = N'COLUMN', @level2name = N'Movement Key'; 70 | 71 | 72 | GO 73 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Transaction date', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement', @level2type = N'COLUMN', @level2name = N'Date Key'; 74 | 75 | 76 | GO 77 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Stock item for this purchase order', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement', @level2type = N'COLUMN', @level2name = N'Stock Item Key'; 78 | 79 | 80 | GO 81 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Customer (if applicable)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement', @level2type = N'COLUMN', @level2name = N'Customer Key'; 82 | 83 | 84 | GO 85 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Supplier (if applicable)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement', @level2type = N'COLUMN', @level2name = N'Supplier Key'; 86 | 87 | 88 | GO 89 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Type of transaction', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement', @level2type = N'COLUMN', @level2name = N'Transaction Type Key'; 90 | 91 | 92 | GO 93 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Stock item transaction ID in source system', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement', @level2type = N'COLUMN', @level2name = N'WWI Stock Item Transaction ID'; 94 | 95 | 96 | GO 97 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Invoice ID in source system', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement', @level2type = N'COLUMN', @level2name = N'WWI Invoice ID'; 98 | 99 | 100 | GO 101 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Purchase order ID in source system', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement', @level2type = N'COLUMN', @level2name = N'WWI Purchase Order ID'; 102 | 103 | 104 | GO 105 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Quantity of stock movement (positive is incoming stock, negative is outgoing)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement', @level2type = N'COLUMN', @level2name = N'Quantity'; 106 | 107 | 108 | GO 109 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Lineage Key for the data load for this row', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Movement', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 110 | 111 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Fact/Tables/Purchase.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Fact].[Purchase] ( 2 | [Purchase Key] BIGINT IDENTITY (1, 1) NOT NULL, 3 | [Date Key] DATE NOT NULL, 4 | [Supplier Key] INT NOT NULL, 5 | [Stock Item Key] INT NOT NULL, 6 | [WWI Purchase Order ID] INT NULL, 7 | [Ordered Outers] INT NOT NULL, 8 | [Ordered Quantity] INT NOT NULL, 9 | [Received Outers] INT NOT NULL, 10 | [Package] NVARCHAR (50) NOT NULL, 11 | [Is Order Finalized] BIT NOT NULL, 12 | [Lineage Key] INT NOT NULL, 13 | CONSTRAINT [PK_Fact_Purchase] PRIMARY KEY NONCLUSTERED ([Purchase Key] ASC, [Date Key] ASC) ON [PS_Date] ([Date Key]), 14 | CONSTRAINT [FK_Fact_Purchase_Date_Key_Dimension_Date] FOREIGN KEY ([Date Key]) REFERENCES [Dimension].[Date] ([Date]), 15 | CONSTRAINT [FK_Fact_Purchase_Stock_Item_Key_Dimension_Stock Item] FOREIGN KEY ([Stock Item Key]) REFERENCES [Dimension].[Stock Item] ([Stock Item Key]), 16 | CONSTRAINT [FK_Fact_Purchase_Supplier_Key_Dimension_Supplier] FOREIGN KEY ([Supplier Key]) REFERENCES [Dimension].[Supplier] ([Supplier Key]) 17 | ); 18 | 19 | 20 | GO 21 | CREATE NONCLUSTERED INDEX [FK_Fact_Purchase_Date_Key] 22 | ON [Fact].[Purchase]([Date Key] ASC) 23 | ON [PS_Date] ([Date Key]); 24 | 25 | 26 | GO 27 | CREATE NONCLUSTERED INDEX [FK_Fact_Purchase_Stock_Item_Key] 28 | ON [Fact].[Purchase]([Stock Item Key] ASC) 29 | ON [PS_Date] ([Date Key]); 30 | 31 | 32 | GO 33 | CREATE NONCLUSTERED INDEX [FK_Fact_Purchase_Supplier_Key] 34 | ON [Fact].[Purchase]([Supplier Key] ASC) 35 | ON [PS_Date] ([Date Key]); 36 | 37 | 38 | GO 39 | CREATE CLUSTERED COLUMNSTORE INDEX [CCX_Fact_Purchase] 40 | ON [Fact].[Purchase] 41 | ON [PS_Date] ([Date Key]); 42 | 43 | 44 | GO 45 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Purchase fact table (stock purchases from suppliers)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase'; 46 | 47 | 48 | GO 49 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for a row in the Purchase fact', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase', @level2type = N'COLUMN', @level2name = N'Purchase Key'; 50 | 51 | 52 | GO 53 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Purchase order date', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase', @level2type = N'COLUMN', @level2name = N'Date Key'; 54 | 55 | 56 | GO 57 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Supplier for this purchase order', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase', @level2type = N'COLUMN', @level2name = N'Supplier Key'; 58 | 59 | 60 | GO 61 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Stock item for this purchase order', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase', @level2type = N'COLUMN', @level2name = N'Stock Item Key'; 62 | 63 | 64 | GO 65 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Purchase order ID in source system ', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase', @level2type = N'COLUMN', @level2name = N'WWI Purchase Order ID'; 66 | 67 | 68 | GO 69 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Quantity of outers (ordering packages)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase', @level2type = N'COLUMN', @level2name = N'Ordered Outers'; 70 | 71 | 72 | GO 73 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Quantity of inners (selling packages)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase', @level2type = N'COLUMN', @level2name = N'Ordered Quantity'; 74 | 75 | 76 | GO 77 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Received outers (so far)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase', @level2type = N'COLUMN', @level2name = N'Received Outers'; 78 | 79 | 80 | GO 81 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Package ordered', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase', @level2type = N'COLUMN', @level2name = N'Package'; 82 | 83 | 84 | GO 85 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Is this purchase order now finalized?', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase', @level2type = N'COLUMN', @level2name = N'Is Order Finalized'; 86 | 87 | 88 | GO 89 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Lineage Key for the data load for this row', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Purchase', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 90 | 91 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Fact/Tables/Stock Holding.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Fact].[Stock Holding] ( 2 | [Stock Holding Key] BIGINT IDENTITY (1, 1) NOT NULL, 3 | [Stock Item Key] INT NOT NULL, 4 | [Quantity On Hand] INT NOT NULL, 5 | [Bin Location] NVARCHAR (20) NOT NULL, 6 | [Last Stocktake Quantity] INT NOT NULL, 7 | [Last Cost Price] DECIMAL (18, 2) NOT NULL, 8 | [Reorder Level] INT NOT NULL, 9 | [Target Stock Level] INT NOT NULL, 10 | [Lineage Key] INT NOT NULL, 11 | CONSTRAINT [PK_Fact_Stock_Holding] PRIMARY KEY NONCLUSTERED ([Stock Holding Key] ASC), 12 | CONSTRAINT [FK_Fact_Stock_Holding_Stock_Item_Key_Dimension_Stock Item] FOREIGN KEY ([Stock Item Key]) REFERENCES [Dimension].[Stock Item] ([Stock Item Key]) 13 | ); 14 | 15 | 16 | GO 17 | CREATE NONCLUSTERED INDEX [FK_Fact_Stock_Holding_Stock_Item_Key] 18 | ON [Fact].[Stock Holding]([Stock Item Key] ASC); 19 | 20 | 21 | GO 22 | CREATE CLUSTERED COLUMNSTORE INDEX [CCX_Fact_Stock_Holding] 23 | ON [Fact].[Stock Holding]; 24 | 25 | 26 | GO 27 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Auto-created to support a foreign key', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Stock Holding', @level2type = N'INDEX', @level2name = N'FK_Fact_Stock_Holding_Stock_Item_Key'; 28 | 29 | 30 | GO 31 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Holdings of stock items', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Stock Holding'; 32 | 33 | 34 | GO 35 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for a row in the Stock Holding fact', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Stock Holding', @level2type = N'COLUMN', @level2name = N'Stock Holding Key'; 36 | 37 | 38 | GO 39 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Stock item being held', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Stock Holding', @level2type = N'COLUMN', @level2name = N'Stock Item Key'; 40 | 41 | 42 | GO 43 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Quantity on hand', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Stock Holding', @level2type = N'COLUMN', @level2name = N'Quantity On Hand'; 44 | 45 | 46 | GO 47 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Bin location (where is this stock in the warehouse)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Stock Holding', @level2type = N'COLUMN', @level2name = N'Bin Location'; 48 | 49 | 50 | GO 51 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Quantity present at last stocktake', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Stock Holding', @level2type = N'COLUMN', @level2name = N'Last Stocktake Quantity'; 52 | 53 | 54 | GO 55 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Unit cost when the stock item was last purchased', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Stock Holding', @level2type = N'COLUMN', @level2name = N'Last Cost Price'; 56 | 57 | 58 | GO 59 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Quantity below which reordering should take place', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Stock Holding', @level2type = N'COLUMN', @level2name = N'Reorder Level'; 60 | 61 | 62 | GO 63 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Typical stock level held', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Stock Holding', @level2type = N'COLUMN', @level2name = N'Target Stock Level'; 64 | 65 | 66 | GO 67 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Lineage Key for the data load for this row', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Stock Holding', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 68 | 69 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Fact/Tables/Transaction.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Fact].[Transaction] ( 2 | [Transaction Key] BIGINT IDENTITY (1, 1) NOT NULL, 3 | [Date Key] DATE NOT NULL, 4 | [Customer Key] INT NULL, 5 | [Bill To Customer Key] INT NULL, 6 | [Supplier Key] INT NULL, 7 | [Transaction Type Key] INT NOT NULL, 8 | [Payment Method Key] INT NULL, 9 | [WWI Customer Transaction ID] INT NULL, 10 | [WWI Supplier Transaction ID] INT NULL, 11 | [WWI Invoice ID] INT NULL, 12 | [WWI Purchase Order ID] INT NULL, 13 | [Supplier Invoice Number] NVARCHAR (20) NULL, 14 | [Total Excluding Tax] DECIMAL (18, 2) NOT NULL, 15 | [Tax Amount] DECIMAL (18, 2) NOT NULL, 16 | [Total Including Tax] DECIMAL (18, 2) NOT NULL, 17 | [Outstanding Balance] DECIMAL (18, 2) NOT NULL, 18 | [Is Finalized] BIT NOT NULL, 19 | [Lineage Key] INT NOT NULL, 20 | CONSTRAINT [PK_Fact_Transaction] PRIMARY KEY NONCLUSTERED ([Transaction Key] ASC, [Date Key] ASC) ON [PS_Date] ([Date Key]), 21 | CONSTRAINT [FK_Fact_Transaction_Bill_To_Customer_Key_Dimension_Customer] FOREIGN KEY ([Bill To Customer Key]) REFERENCES [Dimension].[Customer] ([Customer Key]), 22 | CONSTRAINT [FK_Fact_Transaction_Customer_Key_Dimension_Customer] FOREIGN KEY ([Customer Key]) REFERENCES [Dimension].[Customer] ([Customer Key]), 23 | CONSTRAINT [FK_Fact_Transaction_Date_Key_Dimension_Date] FOREIGN KEY ([Date Key]) REFERENCES [Dimension].[Date] ([Date]), 24 | CONSTRAINT [FK_Fact_Transaction_Payment_Method_Key_Dimension_Payment Method] FOREIGN KEY ([Payment Method Key]) REFERENCES [Dimension].[Payment Method] ([Payment Method Key]), 25 | CONSTRAINT [FK_Fact_Transaction_Supplier_Key_Dimension_Supplier] FOREIGN KEY ([Supplier Key]) REFERENCES [Dimension].[Supplier] ([Supplier Key]), 26 | CONSTRAINT [FK_Fact_Transaction_Transaction_Type_Key_Dimension_Transaction Type] FOREIGN KEY ([Transaction Type Key]) REFERENCES [Dimension].[Transaction Type] ([Transaction Type Key]) 27 | ); 28 | 29 | 30 | GO 31 | CREATE NONCLUSTERED INDEX [FK_Fact_Transaction_Bill_To_Customer_Key] 32 | ON [Fact].[Transaction]([Bill To Customer Key] ASC) 33 | ON [PS_Date] ([Date Key]); 34 | 35 | 36 | GO 37 | CREATE NONCLUSTERED INDEX [FK_Fact_Transaction_Customer_Key] 38 | ON [Fact].[Transaction]([Customer Key] ASC) 39 | ON [PS_Date] ([Date Key]); 40 | 41 | 42 | GO 43 | CREATE NONCLUSTERED INDEX [FK_Fact_Transaction_Date_Key] 44 | ON [Fact].[Transaction]([Date Key] ASC) 45 | ON [PS_Date] ([Date Key]); 46 | 47 | 48 | GO 49 | CREATE NONCLUSTERED INDEX [FK_Fact_Transaction_Payment_Method_Key] 50 | ON [Fact].[Transaction]([Payment Method Key] ASC) 51 | ON [PS_Date] ([Date Key]); 52 | 53 | 54 | GO 55 | CREATE NONCLUSTERED INDEX [FK_Fact_Transaction_Supplier_Key] 56 | ON [Fact].[Transaction]([Supplier Key] ASC) 57 | ON [PS_Date] ([Date Key]); 58 | 59 | 60 | GO 61 | CREATE NONCLUSTERED INDEX [FK_Fact_Transaction_Transaction_Type_Key] 62 | ON [Fact].[Transaction]([Transaction Type Key] ASC) 63 | ON [PS_Date] ([Date Key]); 64 | 65 | 66 | GO 67 | CREATE CLUSTERED COLUMNSTORE INDEX [CCX_Fact_Transaction] 68 | ON [Fact].[Transaction] 69 | ON [PS_Date] ([Date Key]); 70 | 71 | 72 | GO 73 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Transaction fact table (financial transactions involving customers and supppliers)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction'; 74 | 75 | 76 | GO 77 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for a row in the Transaction fact', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Transaction Key'; 78 | 79 | 80 | GO 81 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Transaction date', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Date Key'; 82 | 83 | 84 | GO 85 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Customer (if applicable)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Customer Key'; 86 | 87 | 88 | GO 89 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Bill to customer (if applicable)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Bill To Customer Key'; 90 | 91 | 92 | GO 93 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Supplier (if applicable)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Supplier Key'; 94 | 95 | 96 | GO 97 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Type of transaction', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Transaction Type Key'; 98 | 99 | 100 | GO 101 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Payment method (if applicable)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Payment Method Key'; 102 | 103 | 104 | GO 105 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Customer transaction ID in source system', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'WWI Customer Transaction ID'; 106 | 107 | 108 | GO 109 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Supplier transaction ID in source system', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'WWI Supplier Transaction ID'; 110 | 111 | 112 | GO 113 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Invoice ID in source system', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'WWI Invoice ID'; 114 | 115 | 116 | GO 117 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Purchase order ID in source system', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'WWI Purchase Order ID'; 118 | 119 | 120 | GO 121 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Supplier invoice number (if applicable)', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Supplier Invoice Number'; 122 | 123 | 124 | GO 125 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Total amount excluding tax', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Total Excluding Tax'; 126 | 127 | 128 | GO 129 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Total amount of tax', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Tax Amount'; 130 | 131 | 132 | GO 133 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Total amount including tax', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Total Including Tax'; 134 | 135 | 136 | GO 137 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Amount still outstanding for this transaction', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Outstanding Balance'; 138 | 139 | 140 | GO 141 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Has this transaction been finalized?', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Is Finalized'; 142 | 143 | 144 | GO 145 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Lineage Key for the data load for this row', @level0type = N'SCHEMA', @level0name = N'Fact', @level1type = N'TABLE', @level1name = N'Transaction', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 146 | 147 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/GetLastETLCutoffTime.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.GetLastETLCutoffTime 3 | @TableName sysname 4 | WITH EXECUTE AS OWNER 5 | AS 6 | BEGIN 7 | SET NOCOUNT ON; 8 | SET XACT_ABORT ON; 9 | 10 | SELECT [Cutoff Time] AS CutoffTime 11 | FROM Integration.[ETL Cutoff] 12 | WHERE [Table Name] = @TableName; 13 | 14 | IF @@ROWCOUNT = 0 15 | BEGIN 16 | PRINT N'Invalid ETL table name'; 17 | THROW 51000, N'Invalid ETL table name', 1; 18 | RETURN -1; 19 | END; 20 | 21 | RETURN 0; 22 | END; 23 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/GetLineageKey.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.GetLineageKey 3 | @TableName sysname, 4 | @NewCutoffTime datetime2(7) 5 | WITH EXECUTE AS OWNER 6 | AS 7 | BEGIN 8 | SET NOCOUNT ON; 9 | SET XACT_ABORT ON; 10 | 11 | DECLARE @DataLoadStartedWhen datetime2(7) = SYSDATETIME(); 12 | 13 | INSERT Integration.Lineage 14 | ([Data Load Started], [Table Name], [Data Load Completed], 15 | [Was Successful], [Source System Cutoff Time]) 16 | OUTPUT 17 | inserted.[Lineage Key] as LineageKey 18 | VALUES 19 | (@DataLoadStartedWhen, @TableName, NULL, 20 | 0, @NewCutoffTime); 21 | 22 | RETURN 0; 23 | END; 24 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedCityData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedCityData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | DECLARE @EndOfTime datetime2(7) = '99991231 23:59:59.9999999'; 10 | 11 | BEGIN TRAN; 12 | 13 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 14 | FROM Integration.Lineage 15 | WHERE [Table Name] = N'City' 16 | AND [Data Load Completed] IS NULL 17 | ORDER BY [Lineage Key] DESC); 18 | 19 | WITH RowsToCloseOff 20 | AS 21 | ( 22 | SELECT c.[WWI City ID], MIN(c.[Valid From]) AS [Valid From] 23 | FROM Integration.City_Staging AS c 24 | GROUP BY c.[WWI City ID] 25 | ) 26 | UPDATE c 27 | SET c.[Valid To] = rtco.[Valid From] 28 | FROM Dimension.City AS c 29 | INNER JOIN RowsToCloseOff AS rtco 30 | ON c.[WWI City ID] = rtco.[WWI City ID] 31 | WHERE c.[Valid To] = @EndOfTime; 32 | 33 | INSERT Dimension.City 34 | ([WWI City ID], City, [State Province], Country, Continent, 35 | [Sales Territory], Region, Subregion, [Location], 36 | [Latest Recorded Population], [Valid From], [Valid To], 37 | [Lineage Key]) 38 | SELECT [WWI City ID], City, [State Province], Country, Continent, 39 | [Sales Territory], Region, Subregion, [Location], 40 | [Latest Recorded Population], [Valid From], [Valid To], 41 | @LineageKey 42 | FROM Integration.City_Staging; 43 | 44 | UPDATE Integration.Lineage 45 | SET [Data Load Completed] = SYSDATETIME(), 46 | [Was Successful] = 1 47 | WHERE [Lineage Key] = @LineageKey; 48 | 49 | UPDATE Integration.[ETL Cutoff] 50 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 51 | FROM Integration.Lineage 52 | WHERE [Lineage Key] = @LineageKey) 53 | FROM Integration.[ETL Cutoff] 54 | WHERE [Table Name] = N'City'; 55 | 56 | COMMIT; 57 | 58 | RETURN 0; 59 | END; 60 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedCustomerData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedCustomerData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | DECLARE @EndOfTime datetime2(7) = '99991231 23:59:59.9999999'; 10 | 11 | BEGIN TRAN; 12 | 13 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 14 | FROM Integration.Lineage 15 | WHERE [Table Name] = N'Customer' 16 | AND [Data Load Completed] IS NULL 17 | ORDER BY [Lineage Key] DESC); 18 | 19 | WITH RowsToCloseOff 20 | AS 21 | ( 22 | SELECT c.[WWI Customer ID], MIN(c.[Valid From]) AS [Valid From] 23 | FROM Integration.Customer_Staging AS c 24 | GROUP BY c.[WWI Customer ID] 25 | ) 26 | UPDATE c 27 | SET c.[Valid To] = rtco.[Valid From] 28 | FROM Dimension.Customer AS c 29 | INNER JOIN RowsToCloseOff AS rtco 30 | ON c.[WWI Customer ID] = rtco.[WWI Customer ID] 31 | WHERE c.[Valid To] = @EndOfTime; 32 | 33 | INSERT Dimension.Customer 34 | ([WWI Customer ID], Customer, [Bill To Customer], Category, 35 | [Buying Group], [Primary Contact], [Postal Code], [Valid From], [Valid To], 36 | [Lineage Key]) 37 | SELECT [WWI Customer ID], Customer, [Bill To Customer], Category, 38 | [Buying Group], [Primary Contact], [Postal Code], [Valid From], [Valid To], 39 | @LineageKey 40 | FROM Integration.Customer_Staging; 41 | 42 | UPDATE Integration.Lineage 43 | SET [Data Load Completed] = SYSDATETIME(), 44 | [Was Successful] = 1 45 | WHERE [Lineage Key] = @LineageKey; 46 | 47 | UPDATE Integration.[ETL Cutoff] 48 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 49 | FROM Integration.Lineage 50 | WHERE [Lineage Key] = @LineageKey) 51 | FROM Integration.[ETL Cutoff] 52 | WHERE [Table Name] = N'Customer'; 53 | 54 | COMMIT; 55 | 56 | RETURN 0; 57 | END; 58 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedEmployeeData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedEmployeeData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | DECLARE @EndOfTime datetime2(7) = '99991231 23:59:59.9999999'; 10 | 11 | BEGIN TRAN; 12 | 13 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 14 | FROM Integration.Lineage 15 | WHERE [Table Name] = N'Employee' 16 | AND [Data Load Completed] IS NULL 17 | ORDER BY [Lineage Key] DESC); 18 | 19 | WITH RowsToCloseOff 20 | AS 21 | ( 22 | SELECT e.[WWI Employee ID], MIN(e.[Valid From]) AS [Valid From] 23 | FROM Integration.Employee_Staging AS e 24 | GROUP BY e.[WWI Employee ID] 25 | ) 26 | UPDATE e 27 | SET e.[Valid To] = rtco.[Valid From] 28 | FROM Dimension.Employee AS e 29 | INNER JOIN RowsToCloseOff AS rtco 30 | ON e.[WWI Employee ID] = rtco.[WWI Employee ID] 31 | WHERE e.[Valid To] = @EndOfTime; 32 | 33 | INSERT Dimension.Employee 34 | ([WWI Employee ID], Employee, [Preferred Name], [Is Salesperson], Photo, [Valid From], [Valid To], [Lineage Key]) 35 | SELECT [WWI Employee ID], Employee, [Preferred Name], [Is Salesperson], Photo, [Valid From], [Valid To], 36 | @LineageKey 37 | FROM Integration.Employee_Staging; 38 | 39 | UPDATE Integration.Lineage 40 | SET [Data Load Completed] = SYSDATETIME(), 41 | [Was Successful] = 1 42 | WHERE [Lineage Key] = @LineageKey; 43 | 44 | UPDATE Integration.[ETL Cutoff] 45 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 46 | FROM Integration.Lineage 47 | WHERE [Lineage Key] = @LineageKey) 48 | FROM Integration.[ETL Cutoff] 49 | WHERE [Table Name] = N'Employee'; 50 | 51 | COMMIT; 52 | 53 | RETURN 0; 54 | END; 55 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedMovementData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedMovementData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | BEGIN TRAN; 10 | 11 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 12 | FROM Integration.Lineage 13 | WHERE [Table Name] = N'Movement' 14 | AND [Data Load Completed] IS NULL 15 | ORDER BY [Lineage Key] DESC); 16 | 17 | -- Find the dimension keys required 18 | 19 | UPDATE m 20 | SET m.[Stock Item Key] = COALESCE((SELECT TOP(1) si.[Stock Item Key] 21 | FROM Dimension.[Stock Item] AS si 22 | WHERE si.[WWI Stock Item ID] = m.[WWI Stock Item ID] 23 | AND m.[Last Modifed When] > si.[Valid From] 24 | AND m.[Last Modifed When] <= si.[Valid To] 25 | ORDER BY si.[Valid From]), 0), 26 | m.[Customer Key] = COALESCE((SELECT TOP(1) c.[Customer Key] 27 | FROM Dimension.Customer AS c 28 | WHERE c.[WWI Customer ID] = m.[WWI Customer ID] 29 | AND m.[Last Modifed When] > c.[Valid From] 30 | AND m.[Last Modifed When] <= c.[Valid To] 31 | ORDER BY c.[Valid From]), 0), 32 | m.[Supplier Key] = COALESCE((SELECT TOP(1) s.[Supplier Key] 33 | FROM Dimension.Supplier AS s 34 | WHERE s.[WWI Supplier ID] = m.[WWI Supplier ID] 35 | AND m.[Last Modifed When] > s.[Valid From] 36 | AND m.[Last Modifed When] <= s.[Valid To] 37 | ORDER BY s.[Valid From]), 0), 38 | m.[Transaction Type Key] = COALESCE((SELECT TOP(1) tt.[Transaction Type Key] 39 | FROM Dimension.[Transaction Type] AS tt 40 | WHERE tt.[WWI Transaction Type ID] = m.[WWI Transaction Type ID] 41 | AND m.[Last Modifed When] > tt.[Valid From] 42 | AND m.[Last Modifed When] <= tt.[Valid To] 43 | ORDER BY tt.[Valid From]), 0) 44 | FROM Integration.Movement_Staging AS m; 45 | 46 | -- Merge the data into the fact table 47 | 48 | MERGE Fact.Movement AS m 49 | USING Integration.Movement_Staging AS ms 50 | ON m.[WWI Stock Item Transaction ID] = ms.[WWI Stock Item Transaction ID] 51 | WHEN MATCHED THEN 52 | UPDATE SET m.[Date Key] = ms.[Date Key], 53 | m.[Stock Item Key] = ms.[Stock Item Key], 54 | m.[Customer Key] = ms.[Customer Key], 55 | m.[Supplier Key] = ms.[Supplier Key], 56 | m.[Transaction Type Key] = ms.[Transaction Type Key], 57 | m.[WWI Invoice ID] = ms.[WWI Invoice ID], 58 | m.[WWI Purchase Order ID] = ms.[WWI Purchase Order ID], 59 | m.Quantity = ms.Quantity, 60 | m.[Lineage Key] = @LineageKey 61 | WHEN NOT MATCHED THEN 62 | INSERT ([Date Key], [Stock Item Key], [Customer Key], [Supplier Key], [Transaction Type Key], 63 | [WWI Stock Item Transaction ID], [WWI Invoice ID], [WWI Purchase Order ID], Quantity, [Lineage Key]) 64 | VALUES (ms.[Date Key], ms.[Stock Item Key], ms.[Customer Key], ms.[Supplier Key], ms.[Transaction Type Key], 65 | ms.[WWI Stock Item Transaction ID], ms.[WWI Invoice ID], ms.[WWI Purchase Order ID], ms.Quantity, @LineageKey); 66 | 67 | UPDATE Integration.Lineage 68 | SET [Data Load Completed] = SYSDATETIME(), 69 | [Was Successful] = 1 70 | WHERE [Lineage Key] = @LineageKey; 71 | 72 | UPDATE Integration.[ETL Cutoff] 73 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 74 | FROM Integration.Lineage 75 | WHERE [Lineage Key] = @LineageKey) 76 | FROM Integration.[ETL Cutoff] 77 | WHERE [Table Name] = N'Movement'; 78 | 79 | COMMIT; 80 | 81 | RETURN 0; 82 | END; 83 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedOrderData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedOrderData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | BEGIN TRAN; 10 | 11 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 12 | FROM Integration.Lineage 13 | WHERE [Table Name] = N'Order' 14 | AND [Data Load Completed] IS NULL 15 | ORDER BY [Lineage Key] DESC); 16 | 17 | -- Find the dimension keys required 18 | 19 | UPDATE o 20 | SET o.[City Key] = COALESCE((SELECT TOP(1) c.[City Key] 21 | FROM Dimension.City AS c 22 | WHERE c.[WWI City ID] = o.[WWI City ID] 23 | AND o.[Last Modified When] > c.[Valid From] 24 | AND o.[Last Modified When] <= c.[Valid To] 25 | ORDER BY c.[Valid From]), 0), 26 | o.[Customer Key] = COALESCE((SELECT TOP(1) c.[Customer Key] 27 | FROM Dimension.Customer AS c 28 | WHERE c.[WWI Customer ID] = o.[WWI Customer ID] 29 | AND o.[Last Modified When] > c.[Valid From] 30 | AND o.[Last Modified When] <= c.[Valid To] 31 | ORDER BY c.[Valid From]), 0), 32 | o.[Stock Item Key] = COALESCE((SELECT TOP(1) si.[Stock Item Key] 33 | FROM Dimension.[Stock Item] AS si 34 | WHERE si.[WWI Stock Item ID] = o.[WWI Stock Item ID] 35 | AND o.[Last Modified When] > si.[Valid From] 36 | AND o.[Last Modified When] <= si.[Valid To] 37 | ORDER BY si.[Valid From]), 0), 38 | o.[Salesperson Key] = COALESCE((SELECT TOP(1) e.[Employee Key] 39 | FROM Dimension.Employee AS e 40 | WHERE e.[WWI Employee ID] = o.[WWI Salesperson ID] 41 | AND o.[Last Modified When] > e.[Valid From] 42 | AND o.[Last Modified When] <= e.[Valid To] 43 | ORDER BY e.[Valid From]), 0), 44 | o.[Picker Key] = COALESCE((SELECT TOP(1) e.[Employee Key] 45 | FROM Dimension.Employee AS e 46 | WHERE e.[WWI Employee ID] = o.[WWI Picker ID] 47 | AND o.[Last Modified When] > e.[Valid From] 48 | AND o.[Last Modified When] <= e.[Valid To] 49 | ORDER BY e.[Valid From]), 0) 50 | FROM Integration.Order_Staging AS o; 51 | 52 | -- Remove any existing entries for any of these orders 53 | 54 | DELETE o 55 | FROM Fact.[Order] AS o 56 | WHERE o.[WWI Order ID] IN (SELECT [WWI Order ID] FROM Integration.Order_Staging); 57 | 58 | -- Insert all current details for these orders 59 | 60 | INSERT Fact.[Order] 61 | ([City Key], [Customer Key], [Stock Item Key], [Order Date Key], [Picked Date Key], 62 | [Salesperson Key], [Picker Key], [WWI Order ID], [WWI Backorder ID], [Description], 63 | Package, Quantity, [Unit Price], [Tax Rate], [Total Excluding Tax], [Tax Amount], 64 | [Total Including Tax], [Lineage Key]) 65 | SELECT [City Key], [Customer Key], [Stock Item Key], [Order Date Key], [Picked Date Key], 66 | [Salesperson Key], [Picker Key], [WWI Order ID], [WWI Backorder ID], [Description], 67 | Package, Quantity, [Unit Price], [Tax Rate], [Total Excluding Tax], [Tax Amount], 68 | [Total Including Tax], @LineageKey 69 | FROM Integration.Order_Staging; 70 | 71 | UPDATE Integration.Lineage 72 | SET [Data Load Completed] = SYSDATETIME(), 73 | [Was Successful] = 1 74 | WHERE [Lineage Key] = @LineageKey; 75 | 76 | UPDATE Integration.[ETL Cutoff] 77 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 78 | FROM Integration.Lineage 79 | WHERE [Lineage Key] = @LineageKey) 80 | FROM Integration.[ETL Cutoff] 81 | WHERE [Table Name] = N'Order'; 82 | 83 | COMMIT; 84 | 85 | RETURN 0; 86 | END; 87 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedPaymentMethodData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedPaymentMethodData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | DECLARE @EndOfTime datetime2(7) = '99991231 23:59:59.9999999'; 10 | 11 | BEGIN TRAN; 12 | 13 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 14 | FROM Integration.Lineage 15 | WHERE [Table Name] = N'Payment Method' 16 | AND [Data Load Completed] IS NULL 17 | ORDER BY [Lineage Key] DESC); 18 | 19 | WITH RowsToCloseOff 20 | AS 21 | ( 22 | SELECT pm.[WWI Payment Method ID], MIN(pm.[Valid From]) AS [Valid From] 23 | FROM Integration.PaymentMethod_Staging AS pm 24 | GROUP BY pm.[WWI Payment Method ID] 25 | ) 26 | UPDATE pm 27 | SET pm.[Valid To] = rtco.[Valid From] 28 | FROM Dimension.[Payment Method] AS pm 29 | INNER JOIN RowsToCloseOff AS rtco 30 | ON pm.[WWI Payment Method ID] = rtco.[WWI Payment Method ID] 31 | WHERE pm.[Valid To] = @EndOfTime; 32 | 33 | INSERT Dimension.[Payment Method] 34 | ([WWI Payment Method ID], [Payment Method], [Valid From], [Valid To], [Lineage Key]) 35 | SELECT [WWI Payment Method ID], [Payment Method], [Valid From], [Valid To], 36 | @LineageKey 37 | FROM Integration.PaymentMethod_Staging; 38 | 39 | UPDATE Integration.Lineage 40 | SET [Data Load Completed] = SYSDATETIME(), 41 | [Was Successful] = 1 42 | WHERE [Lineage Key] = @LineageKey; 43 | 44 | UPDATE Integration.[ETL Cutoff] 45 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 46 | FROM Integration.Lineage 47 | WHERE [Lineage Key] = @LineageKey) 48 | FROM Integration.[ETL Cutoff] 49 | WHERE [Table Name] = N'Payment Method'; 50 | 51 | COMMIT; 52 | 53 | RETURN 0; 54 | END; 55 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedPurchaseData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedPurchaseData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | BEGIN TRAN; 10 | 11 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 12 | FROM Integration.Lineage 13 | WHERE [Table Name] = N'Purchase' 14 | AND [Data Load Completed] IS NULL 15 | ORDER BY [Lineage Key] DESC); 16 | 17 | -- Find the dimension keys required 18 | 19 | UPDATE p 20 | SET p.[Supplier Key] = COALESCE((SELECT TOP(1) s.[Supplier Key] 21 | FROM Dimension.Supplier AS s 22 | WHERE s.[WWI Supplier ID] = p.[WWI Supplier ID] 23 | AND p.[Last Modified When] > s.[Valid From] 24 | AND p.[Last Modified When] <= s.[Valid To] 25 | ORDER BY s.[Valid From]), 0), 26 | p.[Stock Item Key] = COALESCE((SELECT TOP(1) si.[Stock Item Key] 27 | FROM Dimension.[Stock Item] AS si 28 | WHERE si.[WWI Stock Item ID] = p.[WWI Stock Item ID] 29 | AND p.[Last Modified When] > si.[Valid From] 30 | AND p.[Last Modified When] <= si.[Valid To] 31 | ORDER BY si.[Valid From]), 0) 32 | FROM Integration.Purchase_Staging AS p; 33 | 34 | -- Remove any existing entries for any of these purchase orders 35 | 36 | DELETE p 37 | FROM Fact.Purchase AS p 38 | WHERE p.[WWI Purchase Order ID] IN (SELECT [WWI Purchase Order ID] FROM Integration.Purchase_Staging); 39 | 40 | -- Insert all current details for these purchase orders 41 | 42 | INSERT Fact.Purchase 43 | ([Date Key], [Supplier Key], [Stock Item Key], [WWI Purchase Order ID], [Ordered Outers], [Ordered Quantity], 44 | [Received Outers], Package, [Is Order Finalized], [Lineage Key]) 45 | SELECT [Date Key], [Supplier Key], [Stock Item Key], [WWI Purchase Order ID], [Ordered Outers], [Ordered Quantity], 46 | [Received Outers], Package, [Is Order Finalized], @LineageKey 47 | FROM Integration.Purchase_Staging; 48 | 49 | UPDATE Integration.Lineage 50 | SET [Data Load Completed] = SYSDATETIME(), 51 | [Was Successful] = 1 52 | WHERE [Lineage Key] = @LineageKey; 53 | 54 | UPDATE Integration.[ETL Cutoff] 55 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 56 | FROM Integration.Lineage 57 | WHERE [Lineage Key] = @LineageKey) 58 | FROM Integration.[ETL Cutoff] 59 | WHERE [Table Name] = N'Purchase'; 60 | 61 | COMMIT; 62 | 63 | RETURN 0; 64 | END; 65 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedSaleData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedSaleData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | BEGIN TRAN; 10 | 11 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 12 | FROM Integration.Lineage 13 | WHERE [Table Name] = N'Sale' 14 | AND [Data Load Completed] IS NULL 15 | ORDER BY [Lineage Key] DESC); 16 | 17 | -- Find the dimension keys required 18 | 19 | UPDATE s 20 | SET s.[City Key] = COALESCE((SELECT TOP(1) c.[City Key] 21 | FROM Dimension.City AS c 22 | WHERE c.[WWI City ID] = s.[WWI City ID] 23 | AND s.[Last Modified When] > c.[Valid From] 24 | AND s.[Last Modified When] <= c.[Valid To] 25 | ORDER BY c.[Valid From]), 0), 26 | s.[Customer Key] = COALESCE((SELECT TOP(1) c.[Customer Key] 27 | FROM Dimension.Customer AS c 28 | WHERE c.[WWI Customer ID] = s.[WWI Customer ID] 29 | AND s.[Last Modified When] > c.[Valid From] 30 | AND s.[Last Modified When] <= c.[Valid To] 31 | ORDER BY c.[Valid From]), 0), 32 | s.[Bill To Customer Key] = COALESCE((SELECT TOP(1) c.[Customer Key] 33 | FROM Dimension.Customer AS c 34 | WHERE c.[WWI Customer ID] = s.[WWI Bill To Customer ID] 35 | AND s.[Last Modified When] > c.[Valid From] 36 | AND s.[Last Modified When] <= c.[Valid To] 37 | ORDER BY c.[Valid From]), 0), 38 | s.[Stock Item Key] = COALESCE((SELECT TOP(1) si.[Stock Item Key] 39 | FROM Dimension.[Stock Item] AS si 40 | WHERE si.[WWI Stock Item ID] = s.[WWI Stock Item ID] 41 | AND s.[Last Modified When] > si.[Valid From] 42 | AND s.[Last Modified When] <= si.[Valid To] 43 | ORDER BY si.[Valid From]), 0), 44 | s.[Salesperson Key] = COALESCE((SELECT TOP(1) e.[Employee Key] 45 | FROM Dimension.Employee AS e 46 | WHERE e.[WWI Employee ID] = s.[WWI Salesperson ID] 47 | AND s.[Last Modified When] > e.[Valid From] 48 | AND s.[Last Modified When] <= e.[Valid To] 49 | ORDER BY e.[Valid From]), 0) 50 | FROM Integration.Sale_Staging AS s; 51 | 52 | -- Remove any existing entries for any of these invoices 53 | 54 | DELETE s 55 | FROM Fact.Sale AS s 56 | WHERE s.[WWI Invoice ID] IN (SELECT [WWI Invoice ID] FROM Integration.Sale_Staging); 57 | 58 | -- Insert all current details for these invoices 59 | 60 | INSERT Fact.Sale 61 | ([City Key], [Customer Key], [Bill To Customer Key], [Stock Item Key], [Invoice Date Key], [Delivery Date Key], 62 | [Salesperson Key], [WWI Invoice ID], [Description], Package, Quantity, [Unit Price], [Tax Rate], 63 | [Total Excluding Tax], [Tax Amount], Profit, [Total Including Tax], [Total Dry Items], [Total Chiller Items], [Lineage Key]) 64 | SELECT [City Key], [Customer Key], [Bill To Customer Key], [Stock Item Key], [Invoice Date Key], [Delivery Date Key], 65 | [Salesperson Key], [WWI Invoice ID], [Description], Package, Quantity, [Unit Price], [Tax Rate], 66 | [Total Excluding Tax], [Tax Amount], Profit, [Total Including Tax], [Total Dry Items], [Total Chiller Items], @LineageKey 67 | FROM Integration.Sale_Staging; 68 | 69 | UPDATE Integration.Lineage 70 | SET [Data Load Completed] = SYSDATETIME(), 71 | [Was Successful] = 1 72 | WHERE [Lineage Key] = @LineageKey; 73 | 74 | UPDATE Integration.[ETL Cutoff] 75 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 76 | FROM Integration.Lineage 77 | WHERE [Lineage Key] = @LineageKey) 78 | FROM Integration.[ETL Cutoff] 79 | WHERE [Table Name] = N'Sale'; 80 | 81 | COMMIT; 82 | 83 | RETURN 0; 84 | END; 85 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedStockHoldingData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedStockHoldingData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | BEGIN TRAN; 10 | 11 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 12 | FROM Integration.Lineage 13 | WHERE [Table Name] = N'Stock Holding' 14 | AND [Data Load Completed] IS NULL 15 | ORDER BY [Lineage Key] DESC); 16 | 17 | -- Find the dimension keys required 18 | 19 | UPDATE s 20 | SET s.[Stock Item Key] = COALESCE((SELECT TOP(1) si.[Stock Item Key] 21 | FROM Dimension.[Stock Item] AS si 22 | WHERE si.[WWI Stock Item ID] = s.[WWI Stock Item ID] 23 | ORDER BY si.[Valid To] DESC), 0) 24 | FROM Integration.StockHolding_Staging AS s; 25 | 26 | -- Remove all existing holdings 27 | 28 | TRUNCATE TABLE Fact.[Stock Holding]; 29 | 30 | -- Insert all current stock holdings 31 | 32 | INSERT Fact.[Stock Holding] 33 | ([Stock Item Key], [Quantity On Hand], [Bin Location], [Last Stocktake Quantity], 34 | [Last Cost Price], [Reorder Level], [Target Stock Level], [Lineage Key]) 35 | SELECT [Stock Item Key], [Quantity On Hand], [Bin Location], [Last Stocktake Quantity], 36 | [Last Cost Price], [Reorder Level], [Target Stock Level], @LineageKey 37 | FROM Integration.StockHolding_Staging; 38 | 39 | UPDATE Integration.Lineage 40 | SET [Data Load Completed] = SYSDATETIME(), 41 | [Was Successful] = 1 42 | WHERE [Lineage Key] = @LineageKey; 43 | 44 | UPDATE Integration.[ETL Cutoff] 45 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 46 | FROM Integration.Lineage 47 | WHERE [Lineage Key] = @LineageKey) 48 | FROM Integration.[ETL Cutoff] 49 | WHERE [Table Name] = N'Stock Holding'; 50 | 51 | COMMIT; 52 | 53 | RETURN 0; 54 | END; 55 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedStockItemData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedStockItemData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | DECLARE @EndOfTime datetime2(7) = '99991231 23:59:59.9999999'; 10 | 11 | BEGIN TRAN; 12 | 13 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 14 | FROM Integration.Lineage 15 | WHERE [Table Name] = N'Stock Item' 16 | AND [Data Load Completed] IS NULL 17 | ORDER BY [Lineage Key] DESC); 18 | 19 | WITH RowsToCloseOff 20 | AS 21 | ( 22 | SELECT s.[WWI Stock Item ID], MIN(s.[Valid From]) AS [Valid From] 23 | FROM Integration.StockItem_Staging AS s 24 | GROUP BY s.[WWI Stock Item ID] 25 | ) 26 | UPDATE s 27 | SET s.[Valid To] = rtco.[Valid From] 28 | FROM Dimension.[Stock Item] AS s 29 | INNER JOIN RowsToCloseOff AS rtco 30 | ON s.[WWI Stock Item ID] = rtco.[WWI Stock Item ID] 31 | WHERE s.[Valid To] = @EndOfTime; 32 | 33 | INSERT Dimension.[Stock Item] 34 | ([WWI Stock Item ID], [Stock Item], Color, [Selling Package], [Buying Package], 35 | Brand, Size, [Lead Time Days], [Quantity Per Outer], [Is Chiller Stock], 36 | Barcode, [Tax Rate], [Unit Price], [Recommended Retail Price], [Typical Weight Per Unit], 37 | Photo, [Valid From], [Valid To], [Lineage Key]) 38 | SELECT [WWI Stock Item ID], [Stock Item], Color, [Selling Package], [Buying Package], 39 | Brand, Size, [Lead Time Days], [Quantity Per Outer], [Is Chiller Stock], 40 | Barcode, [Tax Rate], [Unit Price], [Recommended Retail Price], [Typical Weight Per Unit], 41 | Photo, [Valid From], [Valid To], 42 | @LineageKey 43 | FROM Integration.StockItem_Staging; 44 | 45 | UPDATE Integration.Lineage 46 | SET [Data Load Completed] = SYSDATETIME(), 47 | [Was Successful] = 1 48 | WHERE [Lineage Key] = @LineageKey; 49 | 50 | UPDATE Integration.[ETL Cutoff] 51 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 52 | FROM Integration.Lineage 53 | WHERE [Lineage Key] = @LineageKey) 54 | FROM Integration.[ETL Cutoff] 55 | WHERE [Table Name] = N'Stock Item'; 56 | 57 | COMMIT; 58 | 59 | RETURN 0; 60 | END; 61 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedSupplierData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedSupplierData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | DECLARE @EndOfTime datetime2(7) = '99991231 23:59:59.9999999'; 10 | 11 | BEGIN TRAN; 12 | 13 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 14 | FROM Integration.Lineage 15 | WHERE [Table Name] = N'Supplier' 16 | AND [Data Load Completed] IS NULL 17 | ORDER BY [Lineage Key] DESC); 18 | 19 | WITH RowsToCloseOff 20 | AS 21 | ( 22 | SELECT s.[WWI Supplier ID], MIN(s.[Valid From]) AS [Valid From] 23 | FROM Integration.Supplier_Staging AS s 24 | GROUP BY s.[WWI Supplier ID] 25 | ) 26 | UPDATE s 27 | SET s.[Valid To] = rtco.[Valid From] 28 | FROM Dimension.[Supplier] AS s 29 | INNER JOIN RowsToCloseOff AS rtco 30 | ON s.[WWI Supplier ID] = rtco.[WWI Supplier ID] 31 | WHERE s.[Valid To] = @EndOfTime; 32 | 33 | INSERT Dimension.[Supplier] 34 | ([WWI Supplier ID], Supplier, Category, [Primary Contact], [Supplier Reference], 35 | [Payment Days], [Postal Code], [Valid From], [Valid To], [Lineage Key]) 36 | SELECT [WWI Supplier ID], Supplier, Category, [Primary Contact], [Supplier Reference], 37 | [Payment Days], [Postal Code], [Valid From], [Valid To], 38 | @LineageKey 39 | FROM Integration.Supplier_Staging; 40 | 41 | UPDATE Integration.Lineage 42 | SET [Data Load Completed] = SYSDATETIME(), 43 | [Was Successful] = 1 44 | WHERE [Lineage Key] = @LineageKey; 45 | 46 | UPDATE Integration.[ETL Cutoff] 47 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 48 | FROM Integration.Lineage 49 | WHERE [Lineage Key] = @LineageKey) 50 | FROM Integration.[ETL Cutoff] 51 | WHERE [Table Name] = N'Supplier'; 52 | 53 | COMMIT; 54 | 55 | RETURN 0; 56 | END; 57 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedTransactionData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedTransactionData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | BEGIN TRAN; 10 | 11 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 12 | FROM Integration.Lineage 13 | WHERE [Table Name] = N'Transaction' 14 | AND [Data Load Completed] IS NULL 15 | ORDER BY [Lineage Key] DESC); 16 | 17 | -- Find the dimension keys required 18 | 19 | UPDATE t 20 | SET t.[Customer Key] = COALESCE((SELECT TOP(1) c.[Customer Key] 21 | FROM Dimension.Customer AS c 22 | WHERE c.[WWI Customer ID] = t.[WWI Customer ID] 23 | AND t.[Last Modified When] > c.[Valid From] 24 | AND t.[Last Modified When] <= c.[Valid To] 25 | ORDER BY c.[Valid From]), 0), 26 | t.[Bill To Customer Key] = COALESCE((SELECT TOP(1) c.[Customer Key] 27 | FROM Dimension.Customer AS c 28 | WHERE c.[WWI Customer ID] = t.[WWI Bill To Customer ID] 29 | AND t.[Last Modified When] > c.[Valid From] 30 | AND t.[Last Modified When] <= c.[Valid To] 31 | ORDER BY c.[Valid From]), 0), 32 | t.[Supplier Key] = COALESCE((SELECT TOP(1) s.[Supplier Key] 33 | FROM Dimension.Supplier AS s 34 | WHERE s.[WWI Supplier ID] = t.[WWI Supplier ID] 35 | AND t.[Last Modified When] > s.[Valid From] 36 | AND t.[Last Modified When] <= s.[Valid To] 37 | ORDER BY s.[Valid From]), 0), 38 | t.[Transaction Type Key] = COALESCE((SELECT TOP(1) tt.[Transaction Type Key] 39 | FROM Dimension.[Transaction Type] AS tt 40 | WHERE tt.[WWI Transaction Type ID] = t.[WWI Transaction Type ID] 41 | AND t.[Last Modified When] > tt.[Valid From] 42 | AND t.[Last Modified When] <= tt.[Valid To] 43 | ORDER BY tt.[Valid From]), 0), 44 | t.[Payment Method Key] = COALESCE((SELECT TOP(1) pm.[Payment Method Key] 45 | FROM Dimension.[Payment Method] AS pm 46 | WHERE pm.[WWI Payment Method ID] = t.[WWI Payment Method ID] 47 | AND t.[Last Modified When] > pm.[Valid From] 48 | AND t.[Last Modified When] <= pm.[Valid To] 49 | ORDER BY pm.[Valid From]), 0) 50 | FROM Integration.Transaction_Staging AS t; 51 | 52 | -- Insert all the transactions 53 | 54 | INSERT Fact.[Transaction] 55 | ([Date Key], [Customer Key], [Bill To Customer Key], [Supplier Key], [Transaction Type Key], 56 | [Payment Method Key], [WWI Customer Transaction ID], [WWI Supplier Transaction ID], 57 | [WWI Invoice ID], [WWI Purchase Order ID], [Supplier Invoice Number], [Total Excluding Tax], 58 | [Tax Amount], [Total Including Tax], [Outstanding Balance], [Is Finalized], [Lineage Key]) 59 | SELECT [Date Key], [Customer Key], [Bill To Customer Key], [Supplier Key], [Transaction Type Key], 60 | [Payment Method Key], [WWI Customer Transaction ID], [WWI Supplier Transaction ID], 61 | [WWI Invoice ID], [WWI Purchase Order ID], [Supplier Invoice Number], [Total Excluding Tax], 62 | [Tax Amount], [Total Including Tax], [Outstanding Balance], [Is Finalized], @LineageKey 63 | FROM Integration.Transaction_Staging; 64 | 65 | UPDATE Integration.Lineage 66 | SET [Data Load Completed] = SYSDATETIME(), 67 | [Was Successful] = 1 68 | WHERE [Lineage Key] = @LineageKey; 69 | 70 | UPDATE Integration.[ETL Cutoff] 71 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 72 | FROM Integration.Lineage 73 | WHERE [Lineage Key] = @LineageKey) 74 | FROM Integration.[ETL Cutoff] 75 | WHERE [Table Name] = N'Transaction'; 76 | 77 | COMMIT; 78 | 79 | RETURN 0; 80 | END; 81 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/MigrateStagedTransactionTypeData.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE Integration.MigrateStagedTransactionTypeData 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | DECLARE @EndOfTime datetime2(7) = '99991231 23:59:59.9999999'; 10 | 11 | BEGIN TRAN; 12 | 13 | DECLARE @LineageKey int = (SELECT TOP(1) [Lineage Key] 14 | FROM Integration.Lineage 15 | WHERE [Table Name] = N'Transaction Type' 16 | AND [Data Load Completed] IS NULL 17 | ORDER BY [Lineage Key] DESC); 18 | 19 | WITH RowsToCloseOff 20 | AS 21 | ( 22 | SELECT pm.[WWI Transaction Type ID], MIN(pm.[Valid From]) AS [Valid From] 23 | FROM Integration.TransactionType_Staging AS pm 24 | GROUP BY pm.[WWI Transaction Type ID] 25 | ) 26 | UPDATE pm 27 | SET pm.[Valid To] = rtco.[Valid From] 28 | FROM Dimension.[Transaction Type] AS pm 29 | INNER JOIN RowsToCloseOff AS rtco 30 | ON pm.[WWI Transaction Type ID] = rtco.[WWI Transaction Type ID] 31 | WHERE pm.[Valid To] = @EndOfTime; 32 | 33 | INSERT Dimension.[Transaction Type] 34 | ([WWI Transaction Type ID], [Transaction Type], [Valid From], [Valid To], [Lineage Key]) 35 | SELECT [WWI Transaction Type ID], [Transaction Type], [Valid From], [Valid To], 36 | @LineageKey 37 | FROM Integration.TransactionType_Staging; 38 | 39 | UPDATE Integration.Lineage 40 | SET [Data Load Completed] = SYSDATETIME(), 41 | [Was Successful] = 1 42 | WHERE [Lineage Key] = @LineageKey; 43 | 44 | UPDATE Integration.[ETL Cutoff] 45 | SET [Cutoff Time] = (SELECT [Source System Cutoff Time] 46 | FROM Integration.Lineage 47 | WHERE [Lineage Key] = @LineageKey) 48 | FROM Integration.[ETL Cutoff] 49 | WHERE [Table Name] = N'Transaction Type'; 50 | 51 | COMMIT; 52 | 53 | RETURN 0; 54 | END; 55 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Stored Procedures/PopulateDateDimensionForYear.sql: -------------------------------------------------------------------------------- 1 | CREATE PROCEDURE Integration.PopulateDateDimensionForYear 2 | @YearNumber int 3 | WITH EXECUTE AS OWNER 4 | AS 5 | BEGIN 6 | SET NOCOUNT ON; 7 | SET XACT_ABORT ON; 8 | 9 | DECLARE @DateCounter date = DATEFROMPARTS(@YearNumber, 1, 1); 10 | 11 | BEGIN TRY; 12 | 13 | BEGIN TRAN; 14 | 15 | WHILE YEAR(@DateCounter) = @YearNumber 16 | BEGIN 17 | IF NOT EXISTS (SELECT 1 FROM Dimension.[Date] WHERE [Date] = @DateCounter) 18 | BEGIN 19 | INSERT Dimension.[Date] 20 | ( [Date] 21 | , [DateKey] 22 | , [Day Number] 23 | , [Day] 24 | , [Day of Year] 25 | , [Day of Year Number] 26 | , [Day of Week] 27 | , [Day of Week Number] 28 | , [Week of Year] 29 | , [Month] 30 | , [Short Month] 31 | , [Quarter] 32 | , [Half of Year] 33 | , [Beginning of Month] 34 | , [Beginning of Quarter] 35 | , [Beginning of Half Year] 36 | , [Beginning of Year] 37 | , [Beginning of Month Label] 38 | , [Beginning of Month Label Short] 39 | , [Beginning of Quarter Label] 40 | , [Beginning of Quarter Label Short] 41 | , [Beginning of Half Year Label] 42 | , [Beginning of Half Year Label Short] 43 | , [Beginning of Year Label] 44 | , [Beginning of Year Label Short] 45 | , [Calendar Day Label] 46 | , [Calendar Day Label Short] 47 | , [Calendar Week Number] 48 | , [Calendar Week Label] 49 | , [Calendar Month Number] 50 | , [Calendar Month Label] 51 | , [Calendar Month Year Label] 52 | , [Calendar Quarter Number] 53 | , [Calendar Quarter Label] 54 | , [Calendar Quarter Year Label] 55 | , [Calendar Half of Year Number] 56 | , [Calendar Half of Year Label] 57 | , [Calendar Year Half of Year Label] 58 | , [Calendar Year] 59 | , [Calendar Year Label] 60 | , [Fiscal Month Number] 61 | , [Fiscal Month Label] 62 | , [Fiscal Quarter Number] 63 | , [Fiscal Quarter Label] 64 | , [Fiscal Half of Year Number] 65 | , [Fiscal Half of Year Label] 66 | , [Fiscal Year] 67 | , [Fiscal Year Label] 68 | , [Date Key] 69 | , [Year Week Key] 70 | , [Year Month Key] 71 | , [Year Quarter Key] 72 | , [Year Half of Year Key] 73 | , [Year Key] 74 | , [Beginning of Month Key] 75 | , [Beginning of Quarter Key] 76 | , [Beginning of Half Year Key] 77 | , [Beginning of Year Key] 78 | , [Fiscal Year Month Key] 79 | , [Fiscal Year Quarter Key] 80 | , [Fiscal Year Half of Year Key] 81 | , [ISO Week Number] 82 | ) 83 | SELECT [Date] 84 | , [DateKey] 85 | , [Day Number] 86 | , [Day] 87 | , [Day of Year] 88 | , [Day of Year Number] 89 | , [Day of Week] 90 | , [Day of Week Number] 91 | , [Week of Year] 92 | , [Month] 93 | , [Short Month] 94 | , [Quarter] 95 | , [Half of Year] 96 | , [Beginning of Month] 97 | , [Beginning of Quarter] 98 | , [Beginning of Half of Year] 99 | , [Beginning of Year] 100 | , [Beginning of Month Label] 101 | , [Beginning of Month Label Short] 102 | , [Beginning of Quarter Label] 103 | , [Beginning of Quarter Label Short] 104 | , [Beginning of Half Year Label] 105 | , [Beginning of Half Year Label Short] 106 | , [Beginning of Year Label] 107 | , [Beginning of Year Label Short] 108 | , [Calendar Day Label] 109 | , [Calendar Day Label Short] 110 | , [Calendar Week Number] 111 | , [Calendar Week Label] 112 | , [Calendar Month Number] 113 | , [Calendar Month Label] 114 | , [Calendar Month Year Label] 115 | , [Calendar Quarter Number] 116 | , [Calendar Quarter Label] 117 | , [Calendar Quarter Year Label] 118 | , [Calendar Half of Year Number] 119 | , [Calendar Half of Year Label] 120 | , [Calendar Year Half of Year Label] 121 | , [Calendar Year] 122 | , [Calendar Year Label] 123 | , [Fiscal Month Number] 124 | , [Fiscal Month Label] 125 | , [Fiscal Quarter Number] 126 | , [Fiscal Quarter Label] 127 | , [Fiscal Half of Year Number] 128 | , [Fiscal Half of Year Label] 129 | , [Fiscal Year] 130 | , [Fiscal Year Label] 131 | , [Date Key] 132 | , [Year Week Key] 133 | , [Year Month Key] 134 | , [Year Quarter Key] 135 | , [Year Half of Year Key] 136 | , [Year Key] 137 | , [Beginning of Month Key] 138 | , [Beginning of Quarter Key] 139 | , [Beginning of Half of Year Key] 140 | , [Beginning of Year Key] 141 | , [Fiscal Year Month Key] 142 | , [Fiscal Year Quarter Key] 143 | , [Fiscal Year Half of Year Key] 144 | , [ISO Week Number] 145 | FROM Integration.GenerateDateDimensionColumns(@DateCounter); 146 | END; 147 | SET @DateCounter = DATEADD(day, 1, @DateCounter); 148 | END; 149 | 150 | COMMIT; 151 | END TRY 152 | BEGIN CATCH 153 | IF XACT_STATE() <> 0 ROLLBACK; 154 | PRINT N'Unable to populate dates for the year'; 155 | THROW; 156 | RETURN -1; 157 | END CATCH; 158 | 159 | RETURN 0; 160 | END; 161 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/City_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[City_Staging] ( 2 | [City Staging Key] INT IDENTITY (1, 1) NOT NULL, 3 | [WWI City ID] INT NOT NULL, 4 | [City] NVARCHAR (50) NOT NULL, 5 | [State Province] NVARCHAR (50) NOT NULL, 6 | [Country] NVARCHAR (60) NOT NULL, 7 | [Continent] NVARCHAR (30) NOT NULL, 8 | [Sales Territory] NVARCHAR (50) NOT NULL, 9 | [Region] NVARCHAR (30) NOT NULL, 10 | [Subregion] NVARCHAR (30) NOT NULL, 11 | [Location] [sys].[geography] NULL, 12 | [Latest Recorded Population] BIGINT NOT NULL, 13 | [Valid From] DATETIME2 (7) NOT NULL, 14 | [Valid To] DATETIME2 (7) NOT NULL, 15 | CONSTRAINT [PK_Integration_City_Staging] PRIMARY KEY CLUSTERED ([City Staging Key] ASC) 16 | ); 17 | 18 | 19 | GO 20 | CREATE NONCLUSTERED INDEX [IX_Integration_City_Staging_WWI_City_ID] 21 | ON [Integration].[City_Staging]([WWI City ID] ASC); 22 | 23 | 24 | GO 25 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Allows quickly locating by WWI City Key', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'INDEX', @level2name = N'IX_Integration_City_Staging_WWI_City_ID'; 26 | 27 | 28 | GO 29 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'City staging table', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging'; 30 | 31 | 32 | GO 33 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Row ID within the staging table', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'City Staging Key'; 34 | 35 | 36 | GO 37 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Numeric ID used for reference to a city within the WWI database', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'WWI City ID'; 38 | 39 | 40 | GO 41 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Formal name of the city', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'City'; 42 | 43 | 44 | GO 45 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'State or province for this city', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'State Province'; 46 | 47 | 48 | GO 49 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Country name', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'Country'; 50 | 51 | 52 | GO 53 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Continent that this city is on', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'Continent'; 54 | 55 | 56 | GO 57 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Sales territory for this StateProvince', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'Sales Territory'; 58 | 59 | 60 | GO 61 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Name of the region', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'Region'; 62 | 63 | 64 | GO 65 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Name of the subregion', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'Subregion'; 66 | 67 | 68 | GO 69 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Geographic location of the city', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'Location'; 70 | 71 | 72 | GO 73 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Latest available population for the City', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'Latest Recorded Population'; 74 | 75 | 76 | GO 77 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid from this date and time', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'Valid From'; 78 | 79 | 80 | GO 81 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Valid until this date and time', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'City_Staging', @level2type = N'COLUMN', @level2name = N'Valid To'; 82 | 83 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/Customer_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[Customer_Staging] ( 2 | [Customer Staging Key] INT IDENTITY (1, 1) NOT NULL, 3 | [WWI Customer ID] INT NOT NULL, 4 | [Customer] NVARCHAR (100) NOT NULL, 5 | [Bill To Customer] NVARCHAR (100) NOT NULL, 6 | [Category] NVARCHAR (50) NOT NULL, 7 | [Buying Group] NVARCHAR (50) NOT NULL, 8 | [Primary Contact] NVARCHAR (50) NOT NULL, 9 | [Postal Code] NVARCHAR (10) NOT NULL, 10 | [Valid From] DATETIME2 (7) NOT NULL, 11 | [Valid To] DATETIME2 (7) NOT NULL, 12 | CONSTRAINT [PK_Integration_Customer_Staging] PRIMARY KEY NONCLUSTERED ([Customer Staging Key] ASC) 13 | ) 14 | ; 15 | 16 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/ETL Cutoff.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[ETL Cutoff] ( 2 | [Table Name] [sysname] NOT NULL, 3 | [Cutoff Time] DATETIME2 (7) NOT NULL, 4 | CONSTRAINT [PK_Integration_ETL_Cutoff] PRIMARY KEY CLUSTERED ([Table Name] ASC) 5 | ); 6 | 7 | 8 | GO 9 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'ETL Cutoff Times', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'ETL Cutoff'; 10 | 11 | 12 | GO 13 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Table name', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'ETL Cutoff', @level2type = N'COLUMN', @level2name = N'Table Name'; 14 | 15 | 16 | GO 17 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Time up to which data has been loaded', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'ETL Cutoff', @level2type = N'COLUMN', @level2name = N'Cutoff Time'; 18 | 19 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/Employee_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[Employee_Staging] ( 2 | [Employee Staging Key] INT IDENTITY (1, 1) NOT NULL, 3 | [WWI Employee ID] INT NOT NULL, 4 | [Employee] NVARCHAR (50) NOT NULL, 5 | [Preferred Name] NVARCHAR (50) NOT NULL, 6 | [Is Salesperson] BIT NOT NULL, 7 | [Photo] VARBINARY (MAX) NULL, 8 | [Valid From] DATETIME2 (7) NOT NULL, 9 | [Valid To] DATETIME2 (7) NOT NULL, 10 | CONSTRAINT [PK_Integration_Employee_Staging] PRIMARY KEY NONCLUSTERED ([Employee Staging Key] ASC) 11 | ) 12 | ; 13 | 14 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/Lineage.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[Lineage] ( 2 | [Lineage Key] INT CONSTRAINT [DF_Integration_Lineage_Lineage_Key] DEFAULT (NEXT VALUE FOR [Sequences].[LineageKey]) NOT NULL, 3 | [Data Load Started] DATETIME2 (7) NOT NULL, 4 | [Table Name] [sysname] NOT NULL, 5 | [Data Load Completed] DATETIME2 (7) NULL, 6 | [Was Successful] BIT NOT NULL, 7 | [Source System Cutoff Time] DATETIME2 (7) NOT NULL, 8 | CONSTRAINT [PK_Integration_Lineage] PRIMARY KEY CLUSTERED ([Lineage Key] ASC) 9 | ); 10 | 11 | 12 | GO 13 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Details of data load attempts', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'Lineage'; 14 | 15 | 16 | GO 17 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'DW key for lineage data', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'Lineage', @level2type = N'COLUMN', @level2name = N'Lineage Key'; 18 | 19 | 20 | GO 21 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Time when the data load attempt began', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'Lineage', @level2type = N'COLUMN', @level2name = N'Data Load Started'; 22 | 23 | 24 | GO 25 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Name of the table for this data load event', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'Lineage', @level2type = N'COLUMN', @level2name = N'Table Name'; 26 | 27 | 28 | GO 29 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Time when the data load attempt completed (successfully or not)', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'Lineage', @level2type = N'COLUMN', @level2name = N'Data Load Completed'; 30 | 31 | 32 | GO 33 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Was the attempt successful?', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'Lineage', @level2type = N'COLUMN', @level2name = N'Was Successful'; 34 | 35 | 36 | GO 37 | EXECUTE sp_addextendedproperty @name = N'Description', @value = 'Time that rows from the source system were loaded up until', @level0type = N'SCHEMA', @level0name = N'Integration', @level1type = N'TABLE', @level1name = N'Lineage', @level2type = N'COLUMN', @level2name = N'Source System Cutoff Time'; 38 | 39 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/Movement_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[Movement_Staging] ( 2 | [Movement Staging Key] BIGINT IDENTITY (1, 1) NOT NULL, 3 | [Date Key] DATE NULL, 4 | [Stock Item Key] INT NULL, 5 | [Customer Key] INT NULL, 6 | [Supplier Key] INT NULL, 7 | [Transaction Type Key] INT NULL, 8 | [WWI Stock Item Transaction ID] INT NULL, 9 | [WWI Invoice ID] INT NULL, 10 | [WWI Purchase Order ID] INT NULL, 11 | [Quantity] INT NULL, 12 | [WWI Stock Item ID] INT NULL, 13 | [WWI Customer ID] INT NULL, 14 | [WWI Supplier ID] INT NULL, 15 | [WWI Transaction Type ID] INT NULL, 16 | [Last Modifed When] DATETIME2 (7) NULL, 17 | CONSTRAINT [PK_Integration_Movement_Staging] PRIMARY KEY NONCLUSTERED ([Movement Staging Key] ASC) 18 | ) 19 | ; 20 | 21 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/Order_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[Order_Staging] ( 2 | [Order Staging Key] BIGINT IDENTITY (1, 1) NOT NULL, 3 | [City Key] INT NULL, 4 | [Customer Key] INT NULL, 5 | [Stock Item Key] INT NULL, 6 | [Order Date Key] DATE NULL, 7 | [Picked Date Key] DATE NULL, 8 | [Salesperson Key] INT NULL, 9 | [Picker Key] INT NULL, 10 | [WWI Order ID] INT NULL, 11 | [WWI Backorder ID] INT NULL, 12 | [Description] NVARCHAR (100) NULL, 13 | [Package] NVARCHAR (50) NULL, 14 | [Quantity] INT NULL, 15 | [Unit Price] DECIMAL (18, 2) NULL, 16 | [Tax Rate] DECIMAL (18, 3) NULL, 17 | [Total Excluding Tax] DECIMAL (18, 2) NULL, 18 | [Tax Amount] DECIMAL (18, 2) NULL, 19 | [Total Including Tax] DECIMAL (18, 2) NULL, 20 | [Lineage Key] INT NULL, 21 | [WWI City ID] INT NULL, 22 | [WWI Customer ID] INT NULL, 23 | [WWI Stock Item ID] INT NULL, 24 | [WWI Salesperson ID] INT NULL, 25 | [WWI Picker ID] INT NULL, 26 | [Last Modified When] DATETIME2 (7) NULL, 27 | CONSTRAINT [PK_Integration_Order_Staging] PRIMARY KEY NONCLUSTERED ([Order Staging Key] ASC) 28 | ) 29 | ; 30 | 31 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/PaymentMethod_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[PaymentMethod_Staging] ( 2 | [Payment Method Staging Key] INT IDENTITY (1, 1) NOT NULL, 3 | [WWI Payment Method ID] INT NOT NULL, 4 | [Payment Method] NVARCHAR (50) NOT NULL, 5 | [Valid From] DATETIME2 (7) NOT NULL, 6 | [Valid To] DATETIME2 (7) NOT NULL, 7 | CONSTRAINT [PK_Integration_Payment_Method_Staging] PRIMARY KEY NONCLUSTERED ([Payment Method Staging Key] ASC) 8 | ) 9 | ; 10 | 11 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/Purchase_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[Purchase_Staging] ( 2 | [Purchase Staging Key] BIGINT IDENTITY (1, 1) NOT NULL, 3 | [Date Key] DATE NULL, 4 | [Supplier Key] INT NULL, 5 | [Stock Item Key] INT NULL, 6 | [WWI Purchase Order ID] INT NULL, 7 | [Ordered Outers] INT NULL, 8 | [Ordered Quantity] INT NULL, 9 | [Received Outers] INT NULL, 10 | [Package] NVARCHAR (50) NULL, 11 | [Is Order Finalized] BIT NULL, 12 | [WWI Supplier ID] INT NULL, 13 | [WWI Stock Item ID] INT NULL, 14 | [Last Modified When] DATETIME2 (7) NULL, 15 | CONSTRAINT [PK_Integration_Purchase_Staging] PRIMARY KEY NONCLUSTERED ([Purchase Staging Key] ASC) 16 | ) 17 | ; 18 | 19 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/Sale_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[Sale_Staging] ( 2 | [Sale Staging Key] BIGINT IDENTITY (1, 1) NOT NULL, 3 | [City Key] INT NULL, 4 | [Customer Key] INT NULL, 5 | [Bill To Customer Key] INT NULL, 6 | [Stock Item Key] INT NULL, 7 | [Invoice Date Key] DATE NULL, 8 | [Delivery Date Key] DATE NULL, 9 | [Salesperson Key] INT NULL, 10 | [WWI Invoice ID] INT NULL, 11 | [Description] NVARCHAR (100) NULL, 12 | [Package] NVARCHAR (50) NULL, 13 | [Quantity] INT NULL, 14 | [Unit Price] DECIMAL (18, 2) NULL, 15 | [Tax Rate] DECIMAL (18, 3) NULL, 16 | [Total Excluding Tax] DECIMAL (18, 2) NULL, 17 | [Tax Amount] DECIMAL (18, 2) NULL, 18 | [Profit] DECIMAL (18, 2) NULL, 19 | [Total Including Tax] DECIMAL (18, 2) NULL, 20 | [Total Dry Items] INT NULL, 21 | [Total Chiller Items] INT NULL, 22 | [WWI City ID] INT NULL, 23 | [WWI Customer ID] INT NULL, 24 | [WWI Bill To Customer ID] INT NULL, 25 | [WWI Stock Item ID] INT NULL, 26 | [WWI Salesperson ID] INT NULL, 27 | [Last Modified When] DATETIME2 (7) NULL, 28 | CONSTRAINT [PK_Integration_Sale_Staging] PRIMARY KEY NONCLUSTERED ([Sale Staging Key] ASC) 29 | ) 30 | ; 31 | 32 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/StockHolding_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[StockHolding_Staging] ( 2 | [Stock Holding Staging Key] BIGINT IDENTITY (1, 1) NOT NULL, 3 | [Stock Item Key] INT NULL, 4 | [Quantity On Hand] INT NULL, 5 | [Bin Location] NVARCHAR (20) NULL, 6 | [Last Stocktake Quantity] INT NULL, 7 | [Last Cost Price] DECIMAL (18, 2) NULL, 8 | [Reorder Level] INT NULL, 9 | [Target Stock Level] INT NULL, 10 | [WWI Stock Item ID] INT NULL, 11 | CONSTRAINT [PK_Integration_Stock_Holding_Staging] PRIMARY KEY NONCLUSTERED ([Stock Holding Staging Key] ASC) 12 | ) 13 | ; 14 | 15 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/StockItem_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[StockItem_Staging] ( 2 | [Stock Item Staging Key] INT IDENTITY (1, 1) NOT NULL, 3 | [WWI Stock Item ID] INT NOT NULL, 4 | [Stock Item] NVARCHAR (100) NOT NULL, 5 | [Color] NVARCHAR (20) NOT NULL, 6 | [Selling Package] NVARCHAR (50) NOT NULL, 7 | [Buying Package] NVARCHAR (50) NOT NULL, 8 | [Brand] NVARCHAR (50) NOT NULL, 9 | [Size] NVARCHAR (20) NOT NULL, 10 | [Lead Time Days] INT NOT NULL, 11 | [Quantity Per Outer] INT NOT NULL, 12 | [Is Chiller Stock] BIT NOT NULL, 13 | [Barcode] NVARCHAR (50) NULL, 14 | [Tax Rate] DECIMAL (18, 3) NOT NULL, 15 | [Unit Price] DECIMAL (18, 2) NOT NULL, 16 | [Recommended Retail Price] DECIMAL (18, 2) NULL, 17 | [Typical Weight Per Unit] DECIMAL (18, 3) NOT NULL, 18 | [Photo] VARBINARY (MAX) NULL, 19 | [Valid From] DATETIME2 (7) NOT NULL, 20 | [Valid To] DATETIME2 (7) NOT NULL, 21 | CONSTRAINT [PK_Integration_Stock_Item_Staging] PRIMARY KEY NONCLUSTERED ([Stock Item Staging Key] ASC) 22 | ) 23 | ; 24 | 25 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/Supplier_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[Supplier_Staging] ( 2 | [Supplier Staging Key] INT IDENTITY (1, 1) NOT NULL, 3 | [WWI Supplier ID] INT NOT NULL, 4 | [Supplier] NVARCHAR (100) NOT NULL, 5 | [Category] NVARCHAR (50) NOT NULL, 6 | [Primary Contact] NVARCHAR (50) NOT NULL, 7 | [Supplier Reference] NVARCHAR (20) NULL, 8 | [Payment Days] INT NOT NULL, 9 | [Postal Code] NVARCHAR (10) NOT NULL, 10 | [Valid From] DATETIME2 (7) NOT NULL, 11 | [Valid To] DATETIME2 (7) NOT NULL, 12 | CONSTRAINT [PK_Integration_Supplier_Staging] PRIMARY KEY NONCLUSTERED ([Supplier Staging Key] ASC) 13 | ) 14 | ; 15 | 16 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/TransactionType_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[TransactionType_Staging] ( 2 | [Transaction Type Staging Key] INT IDENTITY (1, 1) NOT NULL, 3 | [WWI Transaction Type ID] INT NOT NULL, 4 | [Transaction Type] NVARCHAR (50) NOT NULL, 5 | [Valid From] DATETIME2 (7) NOT NULL, 6 | [Valid To] DATETIME2 (7) NOT NULL, 7 | CONSTRAINT [PK_Integration_Transaction_Type_Staging] PRIMARY KEY NONCLUSTERED ([Transaction Type Staging Key] ASC) 8 | ) 9 | ; 10 | 11 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Integration/Tables/Transaction_Staging.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Integration].[Transaction_Staging] ( 2 | [Transaction Staging Key] BIGINT IDENTITY (1, 1) NOT NULL, 3 | [Date Key] DATE NULL, 4 | [Customer Key] INT NULL, 5 | [Bill To Customer Key] INT NULL, 6 | [Supplier Key] INT NULL, 7 | [Transaction Type Key] INT NULL, 8 | [Payment Method Key] INT NULL, 9 | [WWI Customer Transaction ID] INT NULL, 10 | [WWI Supplier Transaction ID] INT NULL, 11 | [WWI Invoice ID] INT NULL, 12 | [WWI Purchase Order ID] INT NULL, 13 | [Supplier Invoice Number] NVARCHAR (20) NULL, 14 | [Total Excluding Tax] DECIMAL (18, 2) NULL, 15 | [Tax Amount] DECIMAL (18, 2) NULL, 16 | [Total Including Tax] DECIMAL (18, 2) NULL, 17 | [Outstanding Balance] DECIMAL (18, 2) NULL, 18 | [Is Finalized] BIT NULL, 19 | [WWI Customer ID] INT NULL, 20 | [WWI Bill To Customer ID] INT NULL, 21 | [WWI Supplier ID] INT NULL, 22 | [WWI Transaction Type ID] INT NULL, 23 | [WWI Payment Method ID] INT NULL, 24 | [Last Modified When] DATETIME2 (7) NULL, 25 | CONSTRAINT [PK_Integration_Transaction_Staging] PRIMARY KEY NONCLUSTERED ([Transaction Staging Key] ASC) 26 | ) 27 | ; 28 | 29 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/PostDeploymentScripts/AddUsers.sql: -------------------------------------------------------------------------------- 1 | if user_id('ETLUser') is null 2 | begin 3 | create user ETLUser with password = '$(ETLUserPassword)'; 4 | alter role db_owner add member ETLUser 5 | end 6 | go 7 | 8 | if user_id('AppUser') is null 9 | begin 10 | create user AppUser with password = '$(AppUserPassword)'; 11 | end 12 | go 13 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Security/Application.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA [Application] 2 | AUTHORIZATION [dbo]; 3 | 4 | 5 | GO 6 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Application configuration code', @level0type = N'SCHEMA', @level0name = N'Application'; 7 | 8 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Security/Dimension.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA [Dimension] 2 | AUTHORIZATION [dbo]; 3 | 4 | 5 | GO 6 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Dimensional model dimension tables', @level0type = N'SCHEMA', @level0name = N'Dimension'; 7 | 8 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Security/Fact.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA [Fact] 2 | AUTHORIZATION [dbo]; 3 | 4 | 5 | GO 6 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Dimensional model fact tables', @level0type = N'SCHEMA', @level0name = N'Fact'; 7 | 8 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Security/Integration.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA [Integration] 2 | AUTHORIZATION [dbo]; 3 | 4 | 5 | GO 6 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Objects needed for ETL integration', @level0type = N'SCHEMA', @level0name = N'Integration'; 7 | 8 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Security/PowerBI.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA [PowerBI] 2 | AUTHORIZATION [dbo]; 3 | 4 | 5 | GO 6 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Views and stored procedures that provide the only access for the Power BI dashboard system', @level0type = N'SCHEMA', @level0name = N'PowerBI'; 7 | 8 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Security/Reports.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA [Reports] 2 | AUTHORIZATION [dbo]; 3 | 4 | 5 | GO 6 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Views and stored procedures that provide the only access for the reporting system', @level0type = N'SCHEMA', @level0name = N'Reports'; 7 | 8 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Security/Sequences.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA [Sequences] 2 | AUTHORIZATION [dbo]; 3 | 4 | 5 | GO 6 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Holds sequences used by all tables in the application', @level0type = N'SCHEMA', @level0name = N'Sequences'; 7 | 8 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Security/Website.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA [Website] 2 | AUTHORIZATION [dbo]; 3 | 4 | 5 | GO 6 | EXECUTE sp_addextendedproperty @name = N'Description', @value = N'Views and stored procedures that provide the only access for the application website', @level0type = N'SCHEMA', @level0name = N'Website'; 7 | 8 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Sequences/Sequences/CityKey.sql: -------------------------------------------------------------------------------- 1 | CREATE SEQUENCE [Sequences].[CityKey] 2 | AS INT 3 | START WITH 1 4 | INCREMENT BY 1; 5 | 6 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Sequences/Sequences/CustomerKey.sql: -------------------------------------------------------------------------------- 1 | CREATE SEQUENCE [Sequences].[CustomerKey] 2 | AS INT 3 | START WITH 1 4 | INCREMENT BY 1; 5 | 6 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Sequences/Sequences/EmployeeKey.sql: -------------------------------------------------------------------------------- 1 | CREATE SEQUENCE [Sequences].[EmployeeKey] 2 | AS INT 3 | START WITH 1 4 | INCREMENT BY 1; 5 | 6 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Sequences/Sequences/LineageKey.sql: -------------------------------------------------------------------------------- 1 | CREATE SEQUENCE [Sequences].[LineageKey] 2 | AS INT 3 | START WITH 1 4 | INCREMENT BY 1; 5 | 6 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Sequences/Sequences/PaymentMethodKey.sql: -------------------------------------------------------------------------------- 1 | CREATE SEQUENCE [Sequences].[PaymentMethodKey] 2 | AS INT 3 | START WITH 1 4 | INCREMENT BY 1; 5 | 6 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Sequences/Sequences/StockItemKey.sql: -------------------------------------------------------------------------------- 1 | CREATE SEQUENCE [Sequences].[StockItemKey] 2 | AS INT 3 | START WITH 1 4 | INCREMENT BY 1; 5 | 6 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Sequences/Sequences/SupplierKey.sql: -------------------------------------------------------------------------------- 1 | CREATE SEQUENCE [Sequences].[SupplierKey] 2 | AS INT 3 | START WITH 1 4 | INCREMENT BY 1; 5 | 6 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Sequences/Sequences/TransactionTypeKey.sql: -------------------------------------------------------------------------------- 1 | CREATE SEQUENCE [Sequences].[TransactionTypeKey] 2 | AS INT 3 | START WITH 1 4 | INCREMENT BY 1; 5 | 6 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Storage/PF_Date.sql: -------------------------------------------------------------------------------- 1 | CREATE PARTITION FUNCTION [PF_Date](DATE) 2 | AS RANGE RIGHT 3 | FOR VALUES ('01/01/2012 00:00:00', '01/01/2013 00:00:00', '01/01/2014 00:00:00', '01/01/2015 00:00:00', '01/01/2016 00:00:00', '01/01/2017 00:00:00'); 4 | 5 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/Storage/PS_Date.sql: -------------------------------------------------------------------------------- 1 | CREATE PARTITION SCHEME [PS_Date] 2 | AS PARTITION [PF_Date] 3 | ALL TO ([PRIMARY]); 4 | -------------------------------------------------------------------------------- /atc-adf-sql-demo/sql/wwi-dw-ssdt/dbo/Tables/SampleVersion.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [dbo].[SampleVersion] 2 | ( 3 | MajorSampleVersion INT NOT NULL, 4 | MinorSampleVersion INT NOT NULL, 5 | MinSQLServerBuild NVARCHAR(25) NOT NULL, 6 | [RowCount] INT NOT NULL DEFAULT (1), 7 | CONSTRAINT uq_SampleVersion_RowCount 8 | UNIQUE ([RowCount]), 9 | CONSTRAINT chk_SampleVersion_Cardinality 10 | CHECK ([RowCount]= 1) 11 | ) 12 | 13 | -------------------------------------------------------------------------------- /azure-pipelines/deploy-sqlproj.yml: -------------------------------------------------------------------------------- 1 | # .NET Desktop 2 | # Build and run tests for .NET Desktop or Windows classic desktop solutions. 3 | # Add steps that publish symbols, save build artifacts, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net 5 | 6 | 7 | # Starter pipeline 8 | # Start with a minimal pipeline that you can customize to build and deploy your code. 9 | # Add steps that build, run tests, deploy, and more: 10 | # https://aka.ms/yaml 11 | 12 | pr: 13 | - master 14 | 15 | variables: 16 | - group: 'Secrets' 17 | - name: solution 18 | value: '**/*.sln' 19 | - name: buildPlatform 20 | value: 'Any CPU' 21 | - name: buildConfiguration 22 | value: 'Release' 23 | 24 | stages: 25 | - stage: CreateDB 26 | jobs: 27 | - job: CreateDB 28 | pool: 29 | vmImage: 'ubuntu-latest' 30 | steps: 31 | - task: AzureCLI@1 32 | inputs: 33 | azureSubscription: 'sqldevopsdemosub-test' 34 | scriptLocation: 'inlineScript' 35 | inlineScript: 'az sql db create -g $(resourceGroupName) -s $(azureSqlServerResourceName) -n $(azureSqlDBName)' 36 | 37 | - stage: BuildDACPAC 38 | jobs: 39 | - job: BuildDACPAC 40 | pool: 'Azure self-hosted' 41 | steps: 42 | - task: VSBuild@1 43 | inputs: 44 | solution: '$(solution)' 45 | platform: '$(buildPlatform)' 46 | configuration: '$(buildConfiguration)' 47 | - task: PublishBuildArtifacts@1 48 | inputs: 49 | PathtoPublish: '$(Build.SourcesDirectory)' 50 | ArtifactName: 'sqlproj_artifacts_$(System.JobAttempt)' 51 | publishLocation: 'Container' 52 | 53 | - stage: DeployDB 54 | jobs: 55 | - deployment: NeedApprovalforDBDeploy 56 | environment: Production 57 | - job: DeployDACPAC 58 | pool: 'Azure self-hosted' 59 | steps: 60 | - task: DownloadBuildArtifacts@0 61 | inputs: 62 | buildType: 'current' 63 | downloadType: 'single' 64 | artifactName: 'sqlproj_artifacts_$(System.JobAttempt)' 65 | downloadPath: '$(System.ArtifactsDirectory)' 66 | - task: SqlAzureDacpacDeployment@1 67 | displayName: 'Deploy Azure SQL DB' 68 | inputs: 69 | azureSubscription: '$(azureSubscription)' 70 | ServerName: '$(azureSqlServerName)' 71 | DatabaseName: '$(azureSqlDBName)' 72 | SqlUsername: '$(azureSqlUser)' 73 | SqlPassword: '$(azureSqlPassword)' 74 | DacpacFile: '$(System.ArtifactsDirectory)/sqlproj_artifacts_$(System.JobAttempt)/fitnessdb-ssdt/bin/Release/fitnessdb-ssdt.dacpac' 75 | DeleteFirewallRule: false 76 | AdditionalArguments: '/v:SQLPassword="$(webappSqlPassword)"' 77 | -------------------------------------------------------------------------------- /azure-pipelines/test-azcli.yml: -------------------------------------------------------------------------------- 1 | # Starter pipeline 2 | # Start with a minimal pipeline that you can customize to build and deploy your code. 3 | # Add steps that build, run tests, deploy, and more: 4 | # https://aka.ms/yaml 5 | 6 | trigger: 7 | - master 8 | 9 | stages: 10 | - stage: run_on_ubuntu 11 | jobs: 12 | - job: UbuntuJob 13 | pool: 14 | vmImage: 'ubuntu-latest' 15 | steps: 16 | - task: AzureCLI@1 17 | inputs: 18 | azureSubscription: 'sqldevopsdemosub-test' 19 | scriptLocation: 'inlineScript' 20 | inlineScript: 'az group list' 21 | 22 | - stage: run_on_windows 23 | jobs: 24 | - job: WindowsJob 25 | pool: 26 | vmImage: 'windows-latest' 27 | steps: 28 | - task: AzurePowerShell@4 29 | inputs: 30 | azureSubscription: 'sqldevopsdemosub-test' 31 | scriptType: 'InlineScript' 32 | inline: 'Get-AzResourceGroup' 33 | azurePowerShellVersion: latestVersion 34 | -------------------------------------------------------------------------------- /fitnessdb-datagen/Program.cs: -------------------------------------------------------------------------------- 1 | namespace fitnessdb_datagen 2 | { 3 | using Bogus; 4 | using Bogus.Extensions; 5 | using CountryData.Bogus; 6 | using CsvHelper; 7 | using FastMember; 8 | using System; 9 | using System.Data.SqlClient; 10 | using System.Globalization; 11 | using System.IO; 12 | 13 | class Program 14 | { 15 | static void Main(string[] args) 16 | { 17 | var testFaker = new Faker(); 18 | var fakeRecords = new Faker() 19 | .StrictMode(true) 20 | .RuleFor(x => x.Id, f => f.Random.Int()) 21 | .RuleFor(x => x.RecordedOn, f => f.Date.Past()) 22 | .RuleFor(x => x.Type, f => f.Random.String2(50)) 23 | .RuleFor(x => x.Steps, f => f.Random.Int()) 24 | .RuleFor(x => x.Distance, f => f.Random.Int()) 25 | .RuleFor(x => x.Duration, f => f.Random.Int()) 26 | .RuleFor(x => x.Calories, f => f.Random.Int()) 27 | .RuleFor(x => x.PostProcessedOn, f => f.Date.Past()) 28 | .RuleFor(x => x.AdjustedSteps, f => f.Random.Int()) 29 | .RuleFor(x => x.AdjustedDistance, f => f.Random.Int()) 30 | ; 31 | 32 | var output = fakeRecords.GenerateBetween(10, 20); 33 | using (var writer = new StreamWriter(Console.OpenStandardOutput())) 34 | using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) 35 | { 36 | csv.WriteRecords(output); 37 | } 38 | } 39 | } 40 | 41 | public class FitnessRecord 42 | { 43 | public int Id { get; set; } // [Id] [int] NOT NULL, 44 | public DateTime RecordedOn { get; set; } // [RecordedOn] [datetimeoffset](7) NOT NULL, 45 | public string Type { get; set; } // [Type] [varchar](50) NOT NULL, 46 | public int Steps { get; set; } // [Steps] [int] NOT NULL, 47 | public int Distance { get; set; } // [Distance] [int] NOT NULL, 48 | public int Duration { get; set; } // [Duration] [int] NOT NULL, 49 | public int Calories { get; set; } // [Calories] [int] NOT NULL, 50 | public DateTime PostProcessedOn { get; set; } // [PostProcessedOn] [datetimeoffset](7) NULL, 51 | public int AdjustedSteps { get; set; } // [AdjustedSteps] [int] NULL, 52 | public int AdjustedDistance { get; set; } // [AdjustedDistance] [decimal](9, 6) NULL, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /fitnessdb-datagen/fitnessdb-datagen.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | fitnessdb_datagen 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /fitnessdb-datagen/fitnessdb-datagen.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30204.135 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "fitnessdb-datagen", "fitnessdb-datagen.csproj", "{18044CFC-08DE-4BE3-A897-FCFDC1108CAF}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {18044CFC-08DE-4BE3-A897-FCFDC1108CAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {18044CFC-08DE-4BE3-A897-FCFDC1108CAF}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {18044CFC-08DE-4BE3-A897-FCFDC1108CAF}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {18044CFC-08DE-4BE3-A897-FCFDC1108CAF}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {D3A2B88D-2157-4C21-BC7A-62770DE8CCCA} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /fitnessdb-dbup/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DbUp; 3 | 4 | namespace database_migration 5 | { 6 | class Program 7 | { 8 | static int Main(string[] args) 9 | { 10 | var connectionString = Environment.GetEnvironmentVariable("ConnectionString"); 11 | 12 | var upgrader = 13 | DeployChanges.To 14 | .SqlDatabase(connectionString) 15 | .WithScriptsFromFileSystem("./sql") 16 | .WithVariable("sqlPassword", Environment.GetEnvironmentVariable("SQLPassword")) 17 | .LogToConsole() 18 | .Build(); 19 | 20 | var result = upgrader.PerformUpgrade(); 21 | 22 | if (!result.Successful) 23 | { 24 | Console.ForegroundColor = ConsoleColor.Red; 25 | Console.WriteLine(result.Error); 26 | Console.ResetColor(); 27 | #if DEBUG 28 | Console.ReadLine(); 29 | #endif 30 | return -1; 31 | } 32 | 33 | Console.ForegroundColor = ConsoleColor.Green; 34 | Console.WriteLine("Success!"); 35 | Console.ResetColor(); 36 | return 0; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /fitnessdb-dbup/database-migration.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | database_migration 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /fitnessdb-dbup/sql/01-change-tracking-setup.sql: -------------------------------------------------------------------------------- 1 | if user_id('DotNetWebApp') is null begin 2 | create user DotNetWebApp with password = '$sqlPassword$'; 3 | end 4 | go 5 | 6 | if schema_id('web') is null begin 7 | execute('create schema web') 8 | end 9 | go 10 | 11 | grant execute on schema::web to DotNetWebApp 12 | go 13 | 14 | if not exists(select * from sys.sequences where [name] = 'Ids') 15 | begin 16 | create sequence dbo.Ids 17 | as int 18 | start with 1; 19 | end 20 | go 21 | 22 | drop table if exists dbo.TrainingSession; 23 | create table dbo.TrainingSession 24 | ( 25 | [Id] int primary key not null default(next value for dbo.Ids), 26 | [RecordedOn] datetimeoffset not null, 27 | [Type] varchar(50) not null, 28 | [Steps] int not null, 29 | [Distance] int not null, --Meters 30 | [Duration] int not null, --Seconds 31 | [Calories] int not null, 32 | [PostProcessedOn] datetimeoffset null, 33 | [AdjustedSteps] int null, 34 | [AdjustedDistance] decimal(9,6) null 35 | ); 36 | go 37 | 38 | if not exists(select * from sys.change_tracking_databases where database_id = db_id()) 39 | begin 40 | alter database fitnessdb 41 | set change_tracking = on 42 | (change_retention = 30 days, auto_cleanup = on) 43 | end 44 | go 45 | 46 | if not exists(select * from sys.change_tracking_tables where [object_id]=object_id('dbo.TrainingSession')) 47 | begin 48 | alter table dbo.TrainingSession 49 | enable change_tracking 50 | end 51 | go 52 | -------------------------------------------------------------------------------- /fitnessdb-dbup/sql/02-stored-procedure.sql: -------------------------------------------------------------------------------- 1 | create or alter procedure web.get_trainingsessionsync 2 | @json nvarchar(max) 3 | as 4 | 5 | declare @fromVersion int = json_value(@json, '$.fromVersion') 6 | 7 | set xact_abort on 8 | set transaction isolation level snapshot; 9 | begin tran 10 | declare @reason int 11 | 12 | declare @curVer int = change_tracking_current_version(); 13 | declare @minVer int = change_tracking_min_valid_version(object_id('dbo.TrainingSession')); 14 | 15 | if (@fromVersion = 0) begin 16 | set @reason = 0 -- First Sync 17 | end else if (@fromVersion < @minVer) begin 18 | set @fromVersion = 0 19 | set @reason = 1 -- fromVersion too old. New full sync needed 20 | end 21 | 22 | if (@fromVersion = 0) 23 | begin 24 | select 25 | @curVer as 'Metadata.Sync.Version', 26 | 'Full' as 'Metadata.Sync.Type', 27 | @reason as 'Metadata.Sync.ReasonCode', 28 | [Data] = json_query((select Id, RecordedOn, [Type], Steps, Distance from dbo.TrainingSession for json auto)) 29 | for 30 | json path, without_array_wrapper 31 | end else begin 32 | select 33 | @curVer as 'Metadata.Sync.Version', 34 | 'Diff' as 'Metadata.Sync.Type', 35 | [Data] = json_query(( 36 | select 37 | ct.SYS_CHANGE_OPERATION as '$operation', 38 | ct.Id, 39 | ts.RecordedOn, 40 | ts.[Type], 41 | ts.Steps, 42 | ts.Distance, 43 | ts.PostProcessedOn, 44 | ts.AdjustedSteps, 45 | ts.AdjustedDistance 46 | from 47 | dbo.TrainingSession as ts 48 | right outer join 49 | changetable(changes dbo.TrainingSession, @fromVersion) as ct on ct.[Id] = ts.[id] 50 | for 51 | json path 52 | )) 53 | for 54 | json path, without_array_wrapper 55 | end 56 | 57 | commit tran -------------------------------------------------------------------------------- /fitnessdb-dbup/sql/03-data.sql: -------------------------------------------------------------------------------- 1 | insert into dbo.TrainingSession 2 | (RecordedOn, [Type], Steps, Distance, Duration, Calories) 3 | values 4 | ('20191028 17:27:23 -08:00', 'Run', 3784, 5123, 32*60+3, 526), 5 | ('20191027 17:54:48 -08:00', 'Run', 0, 4981, 32*60+37, 480) 6 | go 7 | 8 | insert into dbo.TrainingSession 9 | (RecordedOn, [Type], Steps, Distance, Duration, Calories) 10 | values 11 | ('20191026 18:24:32 -08:00', 'Run', 4866, 4562, 30*60+18, 475) 12 | go 13 | 14 | update 15 | dbo.TrainingSession 16 | set 17 | Steps = 3450 18 | where 19 | Id = 10 20 | -------------------------------------------------------------------------------- /fitnessdb-ssdt/01-change-tracking-setup.sql: -------------------------------------------------------------------------------- 1 | create schema web 2 | go 3 | 4 | create sequence dbo.Ids 5 | as int 6 | start with 1; 7 | go 8 | 9 | create table dbo.TrainingSession 10 | ( 11 | [Id] int primary key not null default(next value for dbo.Ids), 12 | [RecordedOn] datetimeoffset NOT NULL, 13 | [Type] varchar(50) NOT NULL, 14 | [Steps] int NOT NULL, 15 | [Distance] int NOT NULL, --Meters 16 | [Duration] int NOT NULL, --Seconds 17 | [Calories] int NOT NULL, 18 | [PostProcessedOn] datetimeoffset null, 19 | [AdjustedSteps] int null, 20 | [AdjustedDistance] decimal(9,6) null 21 | ); 22 | go 23 | 24 | alter table dbo.TrainingSession 25 | enable change_tracking 26 | go 27 | -------------------------------------------------------------------------------- /fitnessdb-ssdt/02-stored-procedure.sql: -------------------------------------------------------------------------------- 1 | create procedure web.get_trainingsessionsync 2 | @json nvarchar(max) 3 | as 4 | begin 5 | declare @fromVersion int = json_value(@json, '$.fromVersion') 6 | 7 | set xact_abort on 8 | set transaction isolation level snapshot; 9 | begin tran 10 | declare @reason int 11 | 12 | declare @curVer int = change_tracking_current_version(); 13 | declare @minVer int = change_tracking_min_valid_version(object_id('dbo.TrainingSession')); 14 | 15 | if (@fromVersion = 0) begin 16 | set @reason = 0 -- First Sync 17 | end else if (@fromVersion < @minVer) begin 18 | set @fromVersion = 0 19 | set @reason = 1 -- fromVersion too old. New full sync needed 20 | end 21 | 22 | if (@fromVersion = 0) 23 | begin 24 | select 25 | @curVer as 'Metadata.Sync.Version', 26 | 'Full' as 'Metadata.Sync.Type', 27 | @reason as 'Metadata.Sync.ReasonCode', 28 | [Data] = json_query((select Id, RecordedOn, [Type], Steps, Distance from dbo.TrainingSession for json auto)) 29 | for 30 | json path, without_array_wrapper 31 | end else begin 32 | select 33 | @curVer as 'Metadata.Sync.Version', 34 | 'Diff' as 'Metadata.Sync.Type', 35 | [Data] = json_query(( 36 | select 37 | ct.SYS_CHANGE_OPERATION as '$operation', 38 | ct.Id, 39 | ts.RecordedOn, 40 | ts.[Type], 41 | ts.Steps, 42 | ts.Distance, 43 | ts.PostProcessedOn, 44 | ts.AdjustedSteps, 45 | ts.AdjustedDistance 46 | from 47 | dbo.TrainingSession as ts 48 | right outer join 49 | changetable(changes dbo.TrainingSession, @fromVersion) as ct on ct.[Id] = ts.[Id] 50 | for 51 | json path 52 | )) 53 | for 54 | json path, without_array_wrapper 55 | end 56 | 57 | commit tran 58 | end 59 | go 60 | -------------------------------------------------------------------------------- /fitnessdb-ssdt/03-data.sql: -------------------------------------------------------------------------------- 1 | -- Setup sample data only if table is empty 2 | if NOT EXISTS (SELECT * FROM dbo.TrainingSession) 3 | BEGIN 4 | insert into dbo.TrainingSession 5 | (RecordedOn, [Type], Steps, Distance, Duration, Calories) 6 | values 7 | ('20191028 17:27:23 -08:00', 'Run', 3784, 5123, 32*60+3, 526), 8 | ('20191027 17:54:48 -08:00', 'Run', 0, 4981, 32*60+37, 480) 9 | 10 | insert into dbo.TrainingSession 11 | (RecordedOn, [Type], Steps, Distance, Duration, Calories) 12 | values 13 | ('20191026 18:24:32 -08:00', 'Run', 4866, 4562, 30*60+18, 475) 14 | 15 | update 16 | dbo.TrainingSession 17 | set 18 | Steps = 3450 19 | where 20 | Id = 10 21 | END; 22 | 23 | -- Setup users 24 | if user_id('DotNetWebApp') is null begin 25 | create user DotNetWebApp with password = '$(SQLPassword)'; 26 | grant connect to DotNetWebApp; 27 | end 28 | go 29 | 30 | grant execute on schema::web to DotNetWebApp 31 | go 32 | -------------------------------------------------------------------------------- /fitnessdb-ssdt/fitnessdb-ssdt.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30114.105 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "fitnessdb-ssdt", "fitnessdb-ssdt.sqlproj", "{ECAFBDA9-AE01-41E9-BA58-1A507DE6CB85}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {ECAFBDA9-AE01-41E9-BA58-1A507DE6CB85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {ECAFBDA9-AE01-41E9-BA58-1A507DE6CB85}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {ECAFBDA9-AE01-41E9-BA58-1A507DE6CB85}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {ECAFBDA9-AE01-41E9-BA58-1A507DE6CB85}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {ECAFBDA9-AE01-41E9-BA58-1A507DE6CB85}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {ECAFBDA9-AE01-41E9-BA58-1A507DE6CB85}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ExtensibilityGlobals) = postSolution 25 | SolutionGuid = {CD64AC41-0214-4DCD-868A-2A5C1A1EB772} 26 | EndGlobalSection 27 | EndGlobal 28 | -------------------------------------------------------------------------------- /fitnessdb-ssdt/fitnessdb-ssdt.sqlproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | fitnessdb_ssdt 7 | 2.0 8 | 4.1 9 | {ecafbda9-ae01-41e9-ba58-1a507de6cb85} 10 | Microsoft.Data.Tools.Schema.Sql.SqlAzureV12DatabaseSchemaProvider 11 | Database 12 | 13 | 14 | fitnessdb_ssdt 15 | fitnessdb_ssdt 16 | 1033, CI 17 | BySchemaAndSchemaType 18 | True 19 | v4.5 20 | CS 21 | Properties 22 | False 23 | True 24 | True 25 | True 26 | 30 27 | True 28 | 29 | 30 | bin\Release\ 31 | $(MSBuildProjectName).sql 32 | False 33 | pdbonly 34 | true 35 | false 36 | true 37 | prompt 38 | 4 39 | 40 | 41 | bin\Debug\ 42 | $(MSBuildProjectName).sql 43 | false 44 | true 45 | full 46 | false 47 | true 48 | true 49 | prompt 50 | 4 51 | 52 | 53 | 11.0 54 | 55 | True 56 | 11.0 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | $(SqlCmdVar__1) 73 | 74 | 75 | -------------------------------------------------------------------------------- /rest-api-app/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | 352 | # Custom Files 353 | env.ps1 354 | env.sh 355 | appsettings.Development.json 356 | .env -------------------------------------------------------------------------------- /rest-api-app/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /rest-api-app/Controllers/ControllerQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.Extensions.Logging; 7 | using System.Text.Json; 8 | using System.Data; 9 | using Microsoft.Data.SqlClient; 10 | using Dapper; 11 | using Microsoft.Extensions.Configuration; 12 | 13 | namespace AzureSamples.AzureSQL.Controllers 14 | { 15 | public class ControllerQuery : ControllerBase 16 | { 17 | protected readonly ILogger _logger; 18 | private readonly IConfiguration _config; 19 | 20 | public ControllerQuery(IConfiguration config, ILogger logger) 21 | { 22 | _logger = logger; 23 | _config = config; 24 | } 25 | 26 | protected async Task Query(string verb, Type entity, int? id = null, JsonElement payload = default(JsonElement)) 27 | { 28 | JsonDocument result = null; 29 | 30 | if (!(new string[] {"get", "put", "patch", "delete"}).Contains(verb.ToLower())) 31 | { 32 | throw new ArgumentException($"verb '{verb}' not supported", nameof(verb)); 33 | } 34 | 35 | string entityName = entity.Name.Replace("Controller", string.Empty).ToLower(); 36 | string procedure = $"web.{verb}_{entityName}"; 37 | _logger.LogDebug($"Executing {procedure}"); 38 | 39 | using(var conn = new SqlConnection(_config.GetConnectionString("DefaultConnection"))) { 40 | DynamicParameters parameters = new DynamicParameters(); 41 | 42 | if (payload.ValueKind != default(JsonValueKind)) 43 | { 44 | var json = JsonSerializer.Serialize(payload); 45 | parameters.Add("Json", json); 46 | } 47 | 48 | if (id.HasValue) 49 | parameters.Add("Id", id.Value); 50 | 51 | var qr = await conn.ExecuteScalarAsync( 52 | sql: procedure, 53 | param: parameters, 54 | commandType: CommandType.StoredProcedure 55 | ); 56 | 57 | if (qr != null) 58 | result = JsonDocument.Parse(qr); 59 | }; 60 | 61 | if (result == null) 62 | result = JsonDocument.Parse("[]"); 63 | 64 | return result.RootElement; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /rest-api-app/Controllers/TrainingSessionSyncController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.Extensions.Logging; 7 | using System.Text.Json; 8 | using Microsoft.Extensions.Configuration; 9 | 10 | namespace AzureSamples.AzureSQL.Controllers 11 | { 12 | [ApiController] 13 | [Route("trainingsession/sync")] 14 | public class TrainingSessionSyncController : ControllerQuery 15 | { 16 | public TrainingSessionSyncController(IConfiguration config, ILogger logger): 17 | base(config, logger) {} 18 | 19 | public async Task Get() 20 | { 21 | var clientId = HttpContext.Request.Headers["ClientId"].FirstOrDefault(); 22 | var fromVersion = Int32.Parse(HttpContext.Request.Headers["FromVersion"].FirstOrDefault() ?? "0"); 23 | 24 | var payload = new { 25 | clientId = clientId, 26 | fromVersion = fromVersion 27 | }; 28 | 29 | var jp = JsonDocument.Parse(JsonSerializer.Serialize(payload)); 30 | 31 | this._logger.LogInformation($"clientId {clientId}, fromVersion {fromVersion}"); 32 | 33 | return await this.Query("get", this.GetType(), payload: jp.RootElement); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /rest-api-app/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /rest-api-app/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace AzureSamples.AzureSQL 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => 22 | { 23 | webBuilder.UseStartup(); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rest-api-app/SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /rest-api-app/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.AspNetCore.HttpsPolicy; 8 | using Microsoft.AspNetCore.Mvc; 9 | using Microsoft.Extensions.Configuration; 10 | using Microsoft.Extensions.DependencyInjection; 11 | using Microsoft.Extensions.Hosting; 12 | using Microsoft.Extensions.Logging; 13 | 14 | namespace AzureSamples.AzureSQL 15 | { 16 | public class Startup 17 | { 18 | public Startup(IConfiguration configuration) 19 | { 20 | Configuration = configuration; 21 | } 22 | 23 | public IConfiguration Configuration { get; } 24 | 25 | // This method gets called by the runtime. Use this method to add services to the container. 26 | public void ConfigureServices(IServiceCollection services) 27 | { 28 | services.AddControllers(); 29 | } 30 | 31 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 32 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 33 | { 34 | if (env.IsDevelopment()) 35 | { 36 | app.UseDeveloperExceptionPage(); 37 | } 38 | 39 | app.UseHttpsRedirection(); 40 | 41 | app.UseRouting(); 42 | 43 | app.UseAuthorization(); 44 | 45 | app.UseEndpoints(endpoints => 46 | { 47 | endpoints.MapControllers(); 48 | }); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /rest-api-app/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | "ConnectionStrings": { 11 | "DefaultConnection": "<>" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /rest-api-app/azure-deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # Load values from .env variable 5 | FILE=".env" 6 | if [[ -f $FILE ]]; then 7 | export $(egrep . $FILE | xargs -n1) 8 | else 9 | cat << EOF > .env 10 | ResourceGroup="" 11 | AppName="" 12 | Location="" 13 | ConnectionStrings__DefaultConnection="" 14 | EOF 15 | echo "Enviroment file not detected."; 16 | echo "Please configure values for your environment in the created .env file"; 17 | echo "and run the script again."; 18 | exit 1; 19 | fi 20 | 21 | # Change this if you are using your own github repository 22 | gitSource="https://github.com/Azure-Samples/azure-sql-db-sync-api-change-tracking.git" 23 | 24 | # Make sure connection string variable is set 25 | if [[ -z "${ConnectionStrings__DefaultConnection:-}" ]]; then 26 | echo "Please make sure Azure SQL connection string is set in .env file"; 27 | exit 1; 28 | fi 29 | 30 | echo "Creating Resource Group..."; 31 | az group create \ 32 | -n $ResourceGroup \ 33 | -l $Location 34 | 35 | echo "Creating Application Service Plan..."; 36 | az appservice plan create \ 37 | -g $ResourceGroup \ 38 | -n "linux-plan" \ 39 | --sku B1 \ 40 | --is-linux 41 | 42 | echo "Creating Web Application..."; 43 | az webapp create \ 44 | -g $ResourceGroup \ 45 | -n $AppName \ 46 | --plan "linux-plan" \ 47 | --runtime "DOTNETCORE|3.0" \ 48 | --deployment-source-url $gitSource \ 49 | --deployment-source-branch master 50 | 51 | echo "Configuring Connection String..."; 52 | az webapp config connection-string set \ 53 | -g $ResourceGroup \ 54 | -n $AppName \ 55 | --settings DefaultConnection=$ConnectionStrings__DefaultConnection \ 56 | --connection-string-type=SQLAzure 57 | 58 | echo "Done." -------------------------------------------------------------------------------- /rest-api-app/azure-sql-db-sync-ct-api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.0 5 | AzureSamples.AzureSQL 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /sql-add-temps/04-add-temperature.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE dbo.TrainingSession 2 | ADD Temperature DECIMAL(9,3) NULL -------------------------------------------------------------------------------- /sql-add-temps/05-stored-proc-update.sql: -------------------------------------------------------------------------------- 1 | create or alter procedure web.get_trainingsessionsync 2 | @json nvarchar(max) 3 | as 4 | 5 | declare @fromVersion int = json_value(@json, '$.fromVersion') 6 | 7 | set xact_abort on 8 | set transaction isolation level snapshot; 9 | begin tran 10 | declare @reason int 11 | 12 | declare @curVer int = change_tracking_current_version(); 13 | declare @minVer int = change_tracking_min_valid_version(object_id('dbo.TrainingSession')); 14 | 15 | if (@fromVersion = 0) begin 16 | set @reason = 0 -- First Sync 17 | end else if (@fromVersion < @minVer) begin 18 | set @fromVersion = 0 19 | set @reason = 1 -- fromVersion too old. New full sync needed 20 | end 21 | 22 | if (@fromVersion = 0) 23 | begin 24 | select 25 | @curVer as 'Metadata.Sync.Version', 26 | 'Full' as 'Metadata.Sync.Type', 27 | @reason as 'Metadata.Sync.ReasonCode', 28 | [Data] = json_query((select Id, RecordedOn, [Type], Steps, Distance, Temperature from dbo.TrainingSession for json auto)) 29 | for 30 | json path, without_array_wrapper 31 | end else begin 32 | select 33 | @curVer as 'Metadata.Sync.Version', 34 | 'Diff' as 'Metadata.Sync.Type', 35 | [Data] = json_query(( 36 | select 37 | ct.SYS_CHANGE_OPERATION as '$operation', 38 | ct.Id, 39 | ts.RecordedOn, 40 | ts.[Type], 41 | ts.Steps, 42 | ts.Distance, 43 | ts.PostProcessedOn, 44 | ts.AdjustedSteps, 45 | ts.AdjustedDistance, 46 | ts.Temperature 47 | from 48 | dbo.TrainingSession as ts 49 | right outer join 50 | changetable(changes dbo.TrainingSession, @fromVersion) as ct on ct.[Id] = ts.[id] 51 | for 52 | json path 53 | )) 54 | for 55 | json path, without_array_wrapper 56 | end 57 | 58 | commit tran -------------------------------------------------------------------------------- /sql-add-temps/06-temps-data.sql: -------------------------------------------------------------------------------- 1 | insert into dbo.TrainingSession 2 | (RecordedOn, [Type], Steps, Distance, Duration, Calories, Temperature) 3 | values 4 | ('20200530 07:24:32 +08:00', 'Run', 4866, 4562, 30*60+18, 475, 60) 5 | go 6 | --------------------------------------------------------------------------------