This action might not be possible to undo. Are you sure you want to continue?
The MSDS Database application makes use of a MySQL database on [server name] called chemicals. chemicals consists of three tables; “material”, “supplier”, and “oeco_pn”. material “material” contains the “meat” of the MSDS database. It is basically just basic information that can be found in each particular MSDS and metadata concerning it. id – “id” is a unique number we assigned to each material when it was added to chemicals. The initial set of records that went into “material” came from an excel spreadsheet maintained by Tim Ruhl. His MSDS numbers contained numbers and sometimes letters, making them difficult to sort and compare. We decided to implement “id” as a numbers-only unique identifier. msds_num – The “msds_num” field holds a material’s old MSDS number from the old excel sheet. In records introduced after the spreadsheet records, “msds_num” matches “id”. msds_date – Most MSDS’s contain the date on which they became valid this is usually labeled “date prepared”, “effective date”, or perhaps most commonly “revision date". This is not to be confused with “printed date” or “supersedes date”. name – This is the name of the material. When the material is known by more than one name (e.g. 1, 3Phenylenediamine and MPDA) the additional name(s) is/are added to this field in parentheses or separated by commas. This field occasionally also contains the manufacturer’s catalog number or MSDS number. supplier – This field contains the foreign key to a record in the supplier table. health, fire, and react – These three numbers reflect the level of risk in their respective categories. They come from one of two possible sources: Hazardous Materials Identification System (HMIS) or National Fire Protection Association. Whenever HMIS numbers were available, we used those. However, sometimes only NFPA numbers were available, so in many cases those are the numbers you see. Each HMIS number was often equal to its NFPA counterpart. Since no standard exists for storing information in an MSDS, we had to get each of these numbers from each MSDS by hand. updated_date – This is generated dynamically every time a record is updated or added. remarks – This is an optional field for anything we may have left out. It can store up to 255 characters. material create script: DROP TABLE IF EXISTS `chemicals`.`material`; CREATE TABLE `chemicals`.`material` ( `id` int(11) NOT NULL auto_increment, `msds_num` varchar(7) default NULL, `msds_date` date default NULL, `name` varchar(120) default NULL, `supplier` int(11) default NULL, `health` enum('?','0','1','2','3','4') default NULL, `fire` enum('?','0','1','2','3','4') default NULL, `react` enum('?','0','1','2','3','4') default NULL, `updated_date` datetime default NULL, `remarks` tinytext, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
supplier “supplier” was implemented during the collection of the digital MSDS’s as a means of eliminating redundancy. During this phase, it was found that multiple names were someti mes in use for individual suppliers (e.g. “Chemionics Corporation” and “Chemionics®”) or certain suppliers actually referred to the same company (e.g. “Loctite Corporation” and “Henkel Corporation”). To address this, we rolled certain suppliers into one-another and opted to present users with a list of existing suppliers before offering them the opportunity to enter a new (potentially redundant) supplier name. “supplier” basically contains this list. Furthermore, during the MSDS collection process, we gathe red contact info in this table from every supplier with whom we resorted to using email. supplier create script: DROP TABLE IF EXISTS `chemicals`.`supplier`; CREATE TABLE `chemicals`.`supplier` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) default NULL, `contact_first_name` varchar(50) default NULL, `contact_last_name` varchar(50) default NULL, `email` varchar(50) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; oeco_pn It came to our attention early on that some materials had more than one part number. “oeco_pn” allowed us to store multiple part numbers for each material while keeping the database in normal form (each piece of information is stored in as few places as possible). It’s basically just a cross-reference of materials and their corresponding PNs. Without this convention, storing two PNs for one material requires that we store 18 pieces of information with significant redundancy: from material table:
391 391 '330' '330' '2006-01-23' '2006-01-23' 'Dow Corning® 732 Mul ti-Purpose Sealant Clea r' 'Dow Corning® 732 Mul ti-Purpose Sealant Clea r' 61 61 '2' '2' '1' '1' '0' '0' 451-00108-00 1430-1200-1000
Instead we store 14: from material table:
391 '330' '2006-01-23' 'Dow Corning® 732 Mul ti-Purpose Sealant Clea r' 385 386 391 391 '451-00108-00' '1430-1200-1000' 61 '2' '1' '0'
from oeco_pn table:
oeco_pn create script: DROP TABLE IF EXISTS `chemicals`.`oeco_pn`; CREATE TABLE `chemicals`.`oeco_pn` ( `id` int(11) NOT NULL auto_increment, `m_id` varchar(7) NOT NULL, `oeco_pn` varchar(20) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
The intranet site at [Intranet Web Address] provides the means of interacting with the MSDS database. It has two modes, a general mode for searching the database and accessing digital MSDS’s and an administrative mode for adding and updating material records. The intranet site was developed using Eclipse, with a plugin called “CFEclipse” as well as MySQL Query Browser. Early on in the development of the site, heavy use was made of the book “Getting Started Building ColdFusion MX Applications”. General Mode When the user is not logged in, the intranet site operates as a basic search for browsing and accessing MSDS’s stored in [Network Folder Path]]. The start page, index.cfm provides a form through which the user builds a query of the tables in chemicals. The query itself is in getrecords.cfc which is invoked in searchresult.cfm after getting the form data from index.cfm and before the results themselves are displayed. Each of the five search fields in index.cfm adds an optional “AND” clause to the default “WHERE” clause, “WHERE 0=0”. Thus, if no search criteria are entered, a click of the “Search” button will render a complete listing of materials in the database. Here is the whole initial search query:
SELECT material.id as id, material.msds_num as msds_num, material.name as name, material.health as health, material.fire as fire, material.react as react, material.msds_date as msds_date, supplier.name as supplier_name, supplier.id as supplier_id FROM material, supplier WHERE #PreserveSingleQuotes(WhereClause)# AND #PreserveSingleQuotes(PNClause)# AND material.supplier = supplier.id GROUP BY name
The “WHERE” clause and the first “AND” clause are generated according to the values in the search form and inserted dynamically into the query before it is run. The PN search clause was separated from the other ones because the implementation of the “oeco_pn” table require d that the PN search make use of a subquery:
and material.id IN ( select m_id from oeco_pnwhere oeco_pn LIKE '[user input]')
In addition, an optional ORDER BY clause gets generated if the variable “sortClause” contains a sort criterion:
<cfif len(sortClause)>ORDER BY #sortClause#</cfif>
“sortClause” gets a value when the user clicks one of the column headers in searchresult.cfm, thus reloading the page with new sort order. The default order for search results is by MSDS number. Known in chemicals as “id” (NOT msds_num), the MSDS number is a unique number we assigned to each material when it was added to chemicals. The above snippet shows an example where ColdFusion tags are used. ColdFusion is an application server and software development framework that is used in every page of the MSDS intranet site. The
ColdFusion server interprets special CFML tags, querying the database via a JDBC connection and generates the dynamic elements of the page, before it is returned to the user as HTML. The information for the JDBC connection is as follows: Connection String: Login: Password: In searchresult.cfm, each material found to match the search criteria is displayed in its own column along with its MSDS number, its OECO PN(s) if one or more exist, and its health, fire, and safety ratings. In addition, if a digital copy (in PDF format) of the MSDS is present, a PDF icon appears in the row. The material name and the icon link directly to the material’s MSDS itself. Conversely, if no PDF is available, the name is not a link and the PDF icon does not appear. To determine whether or not there is a digital MSDS for each material returned by the search query, searchresult.cfm loops through the following series of CFML tags for each of the materials:
<cfset thisPath = ExpandPath("*.*")> <cfset thisDirectory = GetDirectoryFromPath(thisPath) & '\datasheets\'> <cfset yourfile = 'datasheets/#id#.pdf'>
When the ColdFusion server processes these tags, it substitutes the name of the returned material for each successive iteration of the loop in the place of “#id#”. For example, if a search returns MSDS number 328 the ColdFusion server stores the string “http://intranet.private.oeco.com/msds/datasheets/328.pdf” in the variable “yourfile”. Then, when it goes to display the result for MSDS number 328 in the search results, it evaluates some other tags that tell it to make the name a link and to display the PDF icon if http://intranet.private.oeco.com/msds/datasheets/328.pdf exists:
<cfif FileExists(ExpandPath(yourfile))> <a href="#yourfile#" target="_blank">#name#</a> <cfelse> #name# </cfif> ...
<td <cfif MaterialResult.currentrow MOD 2 EQ 0>class="odd"</cfif>> <cfif FileExists(ExpandPath(yourfile))> <a href="#yourfile#" target="_blank"><img src="..\images\icon_pdf.gif"> </cfif> </td>
This system of course requires that we follow the convention of naming each MSDS file after is MSDS number. Administrative Mode The administrative mode is initiated by clicking a link in the upper right-hand corner of the page that reads “Administrative Login” and typing in an administrative password. When this is done successfully, the user is notified and directed back to the start page.
The search is performed and the results are displayed the same way in administrative mode as in general mode, but the name link for each result now points to materialdetail.cfm, a page that contains a detailed view of the material’s records. materialdetail.cfm obtains records dynamically by accepting an MSDS number as an variable that is passed to it from searchresult.cfm through the URL as a string, ID=[number]: http://intranet.private.oeco.com/msds/materialdetail.cfm?ID=504 materialdetail.cfm passes this along to displaymaterialdetail.cfc and getrecords.cfc which use it in a number of queries and return the results to materialdetail.cfm for display. Clicking the “edit” button in materialdetail.cfm takes the user to maintenanceaction.cfm which determines that the edit button has been clicked and thus redirects the user to materialedit.cfm. materialedit.cfm obtains the material information from the URL like materialdetail.cfm, but it displays it in form elements that can be changed and sent to the database to update it. This is done by clicking “Save”. The SQL to update the material database (chemicals) is:
<cfif isDefined("existingID")> REPLACE <cfelse> INSERT </cfif> INTO material ( id, msds_num, msds_date, name, supplier, updated_date, remarks <cfif Form.health IS NOT ""> , health </cfif> <cfif Form.fire IS NOT ""> , fire </cfif> <cfif Form.react IS NOT ""> , react </cfif> ) VALUES ( '#Form.msds_num#', '#Form.msds_num#', '#Form.msds_date#', '#Form.name#', '#supplierID#', #CreateODBCDatetime(Now())#, '#Form.remarks#' <cfif Form.health IS NOT ""> , '#Form.health#' </cfif> <cfif Form.fire IS NOT ""> , '#Form.fire#' </cfif> <cfif Form.react IS NOT ""> , '#Form.react#' </cfif>)
You’ll notice that the safety ratings, “health”, “fire”, and “react”, are only updated on the condition that they are not blank. This is because it is not always known what the safety ratings are, and the database will not accept an empty string in a column containing values of the data type “enum”. In addition to editing an existing record, materialdetail.cfm gives you the option of adding a new record. Like with the “Edit” button, the “Add” button is evaluated by maintenanceaction.cfm and the user is directed to materialedit.cfm, but when “Add” is clicked an ID string is not appended to the URL. Instead, materialedit.cfm queries the database to determine what the next unused ID is in the database and places it in the “MSDS Number” field of the edit form, leaving the rest blank. Thus, when the user fills out the form and clicks “Save”, a new record is added to the database with an ID that doesn’t belong to a record that already exists. Also included in the Add/Edit form is an upload box for actual MSDS’s. For unknown reasons pertaining to the way permissions are handle and the way the ISA server talks to the ColdFusion server, we have so far been unable to make this upload box work. Instead, we have opted to add MSDS files by hand to the datasheet folder on server. This is accomplished in two easy steps. 1. Rename the file to match the MSDS’s ID number in the database. For example, if you are uploading MSDS number 792, the file will should be renamed 792.pdf (The file must, of course, already be a PDF. If it is not, convert is to PDF format before renaming it. 2. Place the file in [Network Folder Path]. Once you have successfully renamed and uploaded the file, a PDF icon should appear next to it in searchresult.cfm when it is returned by a search query. When you upload an MSDS, always remember to update the material’s date field with the date of the new MSDS.
During the process of training every OECO associate to use the MSDS application (in general mode), I developed a comprehensive set of notes regarding the practical use of the app. It is called “msds presentation notes.doc” and it can be found in the same folder as this one. For an overview of the inner workings of ColdFusion, visit http://www.adobe.com/examples/cfgettingstarted/experience/index_content.cfm