s3.wp.wsu.edu€¦  · web view'regarding the updates, here after saving the labor record...

14
Saving Data to a Database, Updating Summary Table and a Peek at Some Analytics © Featherman 'This version of the program is step 2 of the development task. Step 1 was to create a table of data in a SQL Server database for the transaction data, the individual records of shifts worked. A second table is also made to store the running totals. The columns of the two SQL Server tables are displayed in the documentation of this program. 'This program demonstrates two methodologies to produce a compiled report of total labor by labor category. '1. Here a summary table is updated after each labor record is recorded and saved. So the overall procedure is 'a) add a row to a transaction table 'b) update one row in a summary table ' saving a transaction record then updating a summary table is common in scenarios such as maintaining current values for inventory and banking account. '2. Another way to produce a compiled report is to use SQL GROUP BY() and PIVOT() queries. In this methodology you do not have a summary table that gets updated after each transaction record is saved. Rather when you want a compiled report (gridview of summary data) you compile the data at that time. This SQL analytics query methodology is outside the scope of the class and not on any exam, however is shown here to expand your understanding of how transction systems and analytics are leveraged. 'So this program shows both methodologies. You are required to learn only the first. The analytics section below is just an FYI. 'This program again saves rows of transaction data to a SQL Server table (PayrollRecords), and then takes the labor hours & grosspay numbers and uses them to update a second summary level SQL Server table (PayrollTotals) after each labor transaction. Use this two table approach (detail records and summary levels) in your final project. Actually in your final project you should be updating many different tables after a transaction. for example after a sales transaction record is saved, you may want to also update the inventory table, customers table, orders table and accounting records as well. Similarly after a production run the inventory levels should increase and machine and employee and workgroup labor performance updated. 'Regarding the updates, here after saving the labor record (record of an employee completing a shift) for an electrician, the running totals for the labor category electricians is updated. You can run this program to see the updated data. This type of update is at the heart of business programming for transactions and to reflect changes in status. 1

Upload: nguyennhi

Post on 23-Aug-2019

213 views

Category:

Documents


0 download

TRANSCRIPT

Saving Data to a Database, Updating Summary Table and a Peek at Some Analytics© – Featherman

'This version of the program is step 2 of the development task. Step 1 was to create a table of data in a SQL Server database for the transaction data, the individual records of shifts worked. A second table is also made to store the running totals. The columns of the two SQL Server tables are displayed in the documentation of this program.

'This program demonstrates two methodologies to produce a compiled report of total labor by labor category.

'1. Here a summary table is updated after each labor record is recorded and saved. So the overall procedure is 'a) add a row to a transaction table'b) update one row in a summary table

' saving a transaction record then updating a summary table is common in scenarios such as maintaining current values for inventory and banking account.

'2. Another way to produce a compiled report is to use SQL GROUP BY() and PIVOT() queries. In this methodology you do not have a summary table that gets updated after each transaction record is saved. Rather when you want a compiled report (gridview of summary data) you compile the data at that time. This SQL analytics query methodology is outside the scope of the class and not on any exam, however is shown here to expand your understanding of how transction systems and analytics are leveraged.

'So this program shows both methodologies. You are required to learn only the first. The analytics section below is just an FYI.

'This program again saves rows of transaction data to a SQL Server table (PayrollRecords), and then takes the labor hours & grosspay numbers and uses them to update a second summary level SQL Server table (PayrollTotals) after each labor transaction. Use this two table approach (detail records and summary levels) in your final project. Actually in your final project you should be updating many different tables after a transaction. for example after a sales transaction record is saved, you may want to also update the inventory table, customers table, orders table and accounting records as well.

Similarly after a production run the inventory levels should increase and machine and employee and workgroup labor performance updated.

'Regarding the updates, here after saving the labor record (record of an employee completing a shift) for an electrician, the running totals for the labor category electricians is updated. You can run this program to see the updated data. This type of update is at the heart of business programming for transactions and to reflect changes in status.

'This program would be helpful to construction manager or project manager (you could also swap out the labor categories and think of another scenario). A likely extension to this project is to have different projects and total the labor for different projects. You could also extend the project management approach and create a budget for a project and the total cost of each labor grade budgeted for the project. You could compare actual to budget and give a project manager a status program such as comparing actual spent to budgeted amount, and you could also add a column that showed how much of the job is completed. You could then be able to tell a manager something like "$7,000 has been spent on electricians so far. This is half the budget for electricians and the job is only 30% completed, why is that?" The hope is that problems like these can be discovered quickly enough so that corrective action is possible. The manager could perhaps renegotiate the contract to

1

receive more budget, somehow speed up the work, shift work to part-timers, or change the job. Status reports allow managers to make course corrections (like steering a ship) to reduce problems and improve operations. So reports shown here are foundational to your MIS learning and to business management.

Here is the table that this program savea data to

2

This program also updates a summary level database table named payrollTotals

Imports System.DataImports System.Data.SqlClient

Partial Class PayrollwithTimespan3 Inherits System.Web.UI.Page

'This app saves the rows of transaction data (the labor records), and updates running summary totals in SQL Server tables stored in the cloud somewhere over the rainbow (Pullman, WA). So this webpage is connecting to two database tables to save data and also generate some management status reports. The connectionstring beloe looks different than published for read-only data retrieval. Because this webpage insert/updates data on a secure server, the connection information is hidden. When performing homework assignments, connect to your own database using your own userID and password.

Public Shared con As New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("conAnalyticsSecure").ConnectionString)

'This program adds a row to the following in-memory datatable, which also serves as the source of data to save the data back to the SQL Server database Public Shared gdtPayrollRecords As New DataTable

'The dataAdapter (DA) created next has several uses in this project.

'1) when the program starts up we use the DA's .fillschema method to retrieve the schema from the database. This schema is passed into the datatable when the program starts, to failitate data entry. So in the procedure to add a new row to the datatable and collect the webpage entered data into the columns for the blank row, that new row already knows the columns and their names, datatypes, restrictions and default values!! This facilitates data accuracy.

'2) We use the DA's .UPDATE method to add the new row of data back to the SQL Server database table. The commandbuilder is the unsung hero here, it is a helper object that generates insert statements for the data adapter to run, so that the actual code to save a row of data is simplified to dataAdapter.Update(datatable). 3 words. The simplicity of this code has been apreciated by students for years. Note: we will use a SQLCommand to perform updates and deletes.

3

'3) After the new row of data is added the red sql statement retrieves the most recent 5 labor records so that they can be displayed to the program user, giving them an indication that their data entry was successful. This SQL SELECT statement is as simple as they can be. An easy improvement would be to shorten the names of the column headers to improve the fit of the gridview to the webpage. That functionality shown later.

Public Shared daLaborRecords As New SqlDataAdapter("SELECT Top 5 * FROM featherman.PayrollRecords ORDER BY LaborID desc", con) Public Shared cbLaborRecords As New SqlCommandBuilder(daLaborRecords)

#Region "Page inititalization"

Private Sub PayrollwithTimespan3_Init(sender As Object, e As EventArgs) Handles Me.Init

'This is a very important line of code, that passes the schema of a SQL Server database table into an in-memory data table. The work of creating the columns of the datatable, and adding other properties is removed.

daLaborRecords.FillSchema(gdtPayrollRecords, SchemaType.Mapped)

'The dataAdapter objects that we create can with the help of the SQLcommandbuilder, perform data inserts into a SQL database (local, or cloud) pretty easily. In order for the new row of data to accept data from teh webpage and to be inserted to the data table then saved back to the SQL Server database, we have to pass the schema of the SQL database table into a data table inside the ASP.NET web page.

'Being part of the system set-up this mapping of data structure from a database to a local in-memory webpage needs to occur when the webpage first starts up. By pulling the database table schema (including data types, restrictions, etc.) into the local webpage, the webpage can then push back the data row of the correct format and data type. Here a lot of quality control in data entry is thankfully enforced. The reports coming out of a business transaction system are garbage if the data entering the system is garbage and erroneous. While Excel allows sloppy data entry, databases can be set up tp enforce data quality with 99.999% accuracy the goal. The correct data from the web form must be supplied to the correct columns of the datatable.

'The famed dataAdapter.update(datatable souce of the data updates) command is just a few words. It can be just 3 words because the schema was passed into the webpage to enforce the data integrity, and also the commandbuilder object auto-generates SQL INSERT command for the row of data. Data adapters very reliably save webpage data back to nice, secure SQL databases.

End Sub#End Region

#Region "Save labor record" 'this version of the timecard keeping system saves the rows of data permanently inside a database on a cloud database server. The database table can store an unlimited number of rows. Becuase each row has data stored uniformaly and accurately, the analytics process can be semi-automated.

Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

4

'variables used in payroll calculations Dim decgrosspay, decPayrate As Decimal Dim dtLabordate As Date Dim ts As TimeSpan

'clear out the last labor record gdtPayrollRecords.Rows.Clear()

'this datarow knows the column schema information and is used to add a new row of labor data that the data Adapter will use to save the record back to the database. This is the blank row that will store columns of data and record each shift worked. This is a one row horizontal array similar to a row in Excel. This procedure fills the empty columns of the new row with data from the controls on the web page. The data Adapter object can take the row of data and save it to a cloud database, as long as the data is formatted well and is of the right datatypes for each column. Dim dr As DataRow = gdtPayrollRecords.NewRow

'now some error checking for each data entry control on the webpage If txtStart.Text = Nothing OrElse txtEnd.Text = Nothing OrElse txtDate.Text = Nothing Then txtOutput.Visible = True txtOutput.Text = "Check entries for time and date" Exit Sub End If

If rblLaborgrades.SelectedIndex = -1 Then txtOutput.Visible = True txtOutput.Text = "Select a labor type" Exit Sub Else ' we will pull different values from the form into the columns of the new row called dr (datarow) dr("LaborCategory") = rblLaborgrades.SelectedItem.Text decPayrate = rblLaborgrades.SelectedValue 'pull the pay rate into a local variable End If

If rblHRCategory.SelectedIndex = -1 Then txtOutput.Visible = True txtOutput.Text = "Select an HR category" Exit Sub Else 'if a HR category was selected then assign it to a column in the new row dr("HRCategory") = rblHRCategory.SelectedItem.Text End If

'Select today in the calendar if no selection was made or a date in the future is selected dtLabordate = DateTime.Parse(txtDate.Text) If dtLabordate = Nothing OrElse dtLabordate > Today() Then dtLabordate = Today() dr("LaborDate") = dtLabordate.Date

5

'In accordance with federal law in the USA the construction firm pays overtime. Labor hours worked on Saturday earn time and 1/2, and the Sunday labor rate per hour is double the weekly rate. It would be useful to produce an automated exception report to identify employees that habitually work Sunday then call in sick Monday or Tuesday.

'The Weekday function is an example of a very useful built-in time/date function (similar to DATEPART in SQL). Here we calculate the payrate depending on day of week and we also write a value to a column of the new row of data. This is a good example of writing a different value to a column for a new row of data depending on certain important criteria. This use of select case can solve a lot of problems.

Select Case Weekday(DateTime.Parse(txtDate.Text)) Case 1 'Sunday decPayrate *= 2 'double the payrate for Sundays dr("Day") = "SunnyDay" Case 2 To 6 'weekday dr("Day") = "Weekday" Case 7 'saturday 'the payrate is time and 1/2 for Sundays decPayrate *= 1.5 dr("Day") = "Saturnday" End Select

dr("Payrate") = decPayrate 'place the value that was just calculated into a column of the new row

'Timespan is an amazingly useful datatype that can be instantiated like any other variable. Timespan is used to hold the result of some date comparison. Such as the number of hours (or days) difference between two times (or dates). Here we create an instance of timespan with the name ts. We have to pull the date out of the textbox using datetime.parse(textbox.text). Once you hae the results of the calculation in a timespan variable then you can format the output into # mintutes, weeks, months, days, etc. very easily such as you see below. ts.totaldays can output the number of hours with partial hours included (ie 8.5 hours, not rounded up or down).

ts = DateTime.Parse(txtEnd.Text) - DateTime.Parse(txtStart.Text) dr("Hours") = ts.TotalHours'results of a timespan calculation makes this next line of code very simple. Multiply the number of hours worked times the labor rate, and store the value into a column of the datarow so that it can be saved into the transactions table later.

decgrosspay = ts.TotalHours * decPayrate dr("GrossPay") = decgrosspay

'the business employees part-time, full-time and 1099 (seasonal) workers. HR and project managers when bidding jobs use the metric that the medical/dental/retirement/doggie daycare/spa benefits add an additional 40% to the typical shift pay. HR provides a modest benefit for the 1099 workers. 1099 workers can access medical benefits at a local clinic. To cover this expense they add a 15% addendum to the fross pay calculation for the shift. The grosspay plus additional 15% or 40% create the 'fully burdoned' cost for the shift. This 'fully burdoned cost' is used by project managers and accountants to cost out projects.

Select Case rblHRCategory.SelectedIndex Case 0 'part-time employee

6

dr("FullyBurdoned") = dr("GrossPay") Case 1 ' full-time employee dr("FullyBurdoned") = dr("GrossPay") * 1.4 Case 2 '1099 employee dr("FullyBurdoned") = dr("GrossPay") * 1.15 End Select

'now that the columns of the new row are populated with values, we can now add that row to the datatable. gdtPayrollRecords.Rows.Add(dr)

Try 'this is the line of code that runs the SQL statement that can insert the new row of labor data. Thanks commandbuilder! that was easy! daLaborRecords.Update(gdtPayrollRecords)

'Here we run the procedure that updates one row in a summary database table Call UpdateTotals()

'next we need to display the 5 recent rows of data, so we clear out the recently added row of data. gdtPayrollRecords.Rows.Clear()

'Now that the data row was saved to the database, run red the SQL SELECT statement to get the records from the labor records table daLaborRecords.Fill(gdtPayrollRecords)

'use a gridview control to display the data that was retrieved into the datatable GridView2.DataSource = gdtPayrollRecords GridView2.DataBind() Catch ex As Exception txtOutput.Visible = True txtOutput.Text = ex.Message End Try

txtOutput.Visible = False

End Sub#End RegionProtected Sub UpdateTotals()

'This query updates one row of data. the labor category that the shift was recorded for (ie Electrician) has four columns updated. One column gets incremented by 1, and then3 columns of data are increased using the value passed in from 3 parameters (@p1, @p2, @p3); ONLY for the labor category passed in by parameter @p4 (the labor category value selected in the radiobuttonlist).

'The syntax is UPDATE tablename set column 1 = @p1, column 2= @p2, etc. WHERE the row # is specified. You would typically update only 1 row.

7

Dim cmdUpdateLaborTotals As New SqlCommand("UPDATE [featherman].[PayrollTotals] SET NumberRecords +=1, TotalHours += @p1, GrossPay += @p2, FullyBurdoned += @p3 WHERE LaborCategory = @p4", con)

'The above SQL command (used to run SQL update and deletes) can be created before the values of the parameter are set (presumably after the user input is verified and processed). Below is how the the values from the webform (currently either in controls on the form or in columns of a datarow) are passed into the parameters for the SQL update statement. When the SQL update statement is run, the values are passed from the webpage into the SQL statement and used to make changes in the back-end database table. This process may seem tedious but enforces security and protects against SQL injection attacks.

'so a SQL UPDATE SET statement (it's red because it is text) is run against the SQL Server database (made by MSFT) using a SQLCommand (an ADO.NET object). Next we create the parameters that the SQL command will use. The data values are already neatly in the new row of the data table so we can access them there.

With cmdUpdateLaborTotals.Parameters .Clear() .AddWithValue("@p1", gdtPayrollRecords.Rows(0).Item("Hours")) .AddWithValue("@p2", gdtPayrollRecords.Rows(0).Item("GrossPay")) .AddWithValue("@p3", gdtPayrollRecords.Rows(0).Item("FullyBurdoned")) .AddWithValue("@p4", gdtPayrollRecords.Rows(0).Item("LaborCategory")) End With

Try 'updates and deletes are performed with a SQLcommand, not dataAdapter. The main difference is that we have to manually open and close the connection.

If con.State = ConnectionState.Closed Then con.Open()

'the next line of code reads execute the SQL Statement over the connection to the database and do not return any dataset cmdUpdateLaborTotals.ExecuteNonQuery()

'now that the summary table is updated with the UPDATE SET SQL statement, now call (invoke) another procedure fetching a new copy of the updated totals into the webpage. It is useful to break functionality into segments (such as shown here) that can be combined. Putting all the lines of code into one procedure can sure be messy! Call FetchLaborTotals()

Catch ex As Exception txtOutput.Visible = True txtOutput.Text = ex.Message Finally con.Close() 'again SQL commands need to have their connections excplicitly opened and closed. End Try

End Sub

8

Protected Sub FetchLaborTotals() 'open a connection to the database and fetch the current results of the SUMMARY table into a datatable in your webpage, displaying the results in a gridview control on view #2. We run the red SQL command shown in red. After the summary table is updated, display the table in a gridview.

Dim daFetchTotals As New SqlDataAdapter("SELECT * FROM PayrollTotals", con) Dim dtLaborTotals As New DataTable

Try daFetchTotals.Fill(dtLaborTotals) GridView5.DataSource = dtLaborTotals GridView5.DataBind()

Catch ex As Exception txtOutput.Text = ex.Message End Try End Sub

#Region "Analytics - you can ignore this section for now, and go forward to the next topic that gets you closer to completing your final project" Protected Sub PerformAnalytics()

'Three SQL analytics queries are performed against a SQL database. Each query retrieves a compiled dataset that is stored in these data tables.

Dim dtLaborgradeTotals, dtLGHRCatTotals, dtYear As New DataTable

'when the program user clicks on the second link button, view # 2 will display and this procedure runs SQL queries that retrieve two datasets from a cloud-based SQL Server database. Dataadapters are created and used to run SQL statements that perform the analytics(shown in red). The retrieved datasets are assigned to datatables, and then displayed in gridviews. This information is shown here to show a realistic usage of SQL inside a webpage, and to demonstrate the common integration of ASP.NET\SQL and SQL Server databases. You do not need to learn this functionality for an introductory programming class. Rather you can connect to the database and use a pivot table to provide the same analytics. You can also perhaps use Tableau or PowerBI. In each case the software is running SQL in the background, and providing the same results.

'Challenge! Use an Excel pivot table to verify the results shown on your screen. An example is shown below. You can connect to the featherman.PayrollRecords table in the featherman_analytics cloud database on cb-ot-devst03.ad.wsu.edu (user ID = mfstudent, pwd = BIanalyst). If you can use a pivot table then you can see how useful it is to connect a pivot table to a database.

'The first query is an example of a standard SQL GROUP BY() statenment where one column (FullyBurdoned) is summed based on values in a dimension (labor category). Much more on how these SQL queries work in the link below - look for module #2 and #4 'https://faculty.business.wsu.edu/featherman/feathermans-coding-adventures-series/

9

'The code performs a Count, Average and Sum for each value of a dimension field named LaborCategory (ie part-time, full-time, 1099.). These totals that are calculated are shown for each labor category. The SUM() provides the similar functionalty inside a GROUP BY() above or PIVOT() below, however the SUM result is cut into subgroups (the columns) in teh PIVOT cross-tabulation query.

Dim daGroupData As New SqlDataAdapter("SELECT [LaborCategory] as [Category], COUNT([LaborID]) as [#Shifts], FORMAT(AVG([FullyBurdoned]), 'N0') as [Avg. Shift Expense], FORMAT(SUM([FullyBurdoned]), 'N0') As [Total Expense] From [featherman].[PayrollRecords] Group BY [LaborCategory]", con)

'In the next query the data is cross-tabulated, there are rows of data that are cut into columns that provide totals for Part-time, full-time and 1099 workers.

Dim daPivotData As New SqlDataAdapter("SELECT * FROM (SELECT [LaborCategory] as [Category], [HRCategory], [FullyBurdoned] FROM [featherman].[PayrollRecords] ) AS BaseDataTable PIVOT (SUM([FullyBurdoned]) FOR [HRCategory] IN ([Part-time], [Full-time], [1099])) AS PivotTable", con)

'This is another example of a SQL pivot query (essentially the same concept and functionality as an Excel pivot table) that can build a table one row for each value of a dimension, such as here the 4 LaborCategories. After generating the rows next the query generates 12 columns of summary data for each row. Notice the word after the key term PIVOT? The word sum lets you know that totalling is going to occur by the combination of month and labor grade. So here 48 calculations are made to complete the table. The labor is summarized by month and labor category. You can also perform this calendar functionality with an Excel pivot table, if you have a column that extracts the month out of the labor date column.

Dim daPivotYearData As New SqlDataAdapter("SELECT * FROM (SELECT [LaborCategory] as [Category], DATENAME(MONTH,[LaborDate]) AS [MonthName], [FullyBurdoned] FROM [featherman].[PayrollRecords]) AS BaseDataTable PIVOT (SUM([FullyBurdoned]) FOR [MonthName] IN (January, February, March, April, May, June, July, August, September, October, November, December)) AS PivotTable", con)

'anytime you query a database, there is a good chance that your code is wrong, or the password is wrong, or the database is only available within a VPN, the server is down, etc. So with so many chances for failure, you need to put the code inside a TRY CATCH block. The sensitive code goes in the TRY section, then you CATCH the errors (useful for debugging) without the web page crashing.

Try daGroupData.Fill(dtLaborgradeTotals) ' this line runs the first SQL statement over the connection to the cloud database, and returns a dataset of compiled numers that is assigned to the datatable. The # of rows returned is based on the cardinality (# of different values) in the dimension specified (here LaborCategory).

daPivotData.Fill(dtLGHRCatTotals) ' this line runs the second SQL statement over the connection to the cloud database, and returns a dataset of compiled numers that is assigned to the datatable. We get again the same number of rows as before but now have used the pivot operation to generate columns.

daPivotYearData.Fill(dtYear) 'this line runs the third red SQL query, and demonstrates again the usefulness of learning SQL programming.

GridView1.DataSource = dtLaborgradeTotals 'tell each gridview control which table of data to display

10

GridView3.DataSource = dtLGHRCatTotals GridView4.DataSource = dtYear

GridView1.DataBind() 'use gridview controls to display the retrieved data that is now in the datatables GridView3.DataBind() GridView4.DataBind()

Catch ex As Exception txtOutput.Visible = True txtOutput.Text = ex.Message End Try

End Sub#End Region

#Region "Utilities" 'switch between views Protected Sub LinkButton1_Click(sender As Object, e As EventArgs) Handles LinkButton1.Click MultiView1.ActiveViewIndex = 0 End Sub

Protected Sub LinkButton2_Click(sender As Object, e As EventArgs) Handles LinkButton2.Click MultiView1.ActiveViewIndex = 1 Call PerformAnalytics() End Sub

Protected Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click 'here we can clear the form for further data entry rblLaborgrades.SelectedIndex = -1 rblHRCategory.SelectedIndex = -1 txtStart.Text = Nothing txtEnd.Text = Nothing txtDate.Text = Nothing txtOutput.Visible = False txtOutput.Text = Nothing End Sub#End Region

End Class

11