<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Microsoft Access with SQL Server Blog</title>
	
	<link>http://accessexperts.net/blog</link>
	<description>773.809.5456</description>
	<lastBuildDate>Tue, 29 May 2012 13:59:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/accessexperts/feedburner" /><feedburner:info uri="accessexperts/feedburner" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>accessexperts/feedburner</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>If your client sees you as a cost center you already lost…</title>
		<link>http://feedproxy.google.com/~r/accessexperts/feedburner/~3/lxBd7z3fQqE/</link>
		<comments>http://accessexperts.net/blog/2012/05/15/if-your-client-sees-you-as-a-cost-center-you-already-lost/#comments</comments>
		<pubDate>Tue, 15 May 2012 15:00:39 +0000</pubDate>
		<dc:creator>Juan Soto</dc:creator>
				<category><![CDATA[Access Help]]></category>

		<guid isPermaLink="false">http://accessexperts.net/blog/?p=1473</guid>
		<description><![CDATA[Access can do great things, on a short time frame and with a smaller budget than other technologies. If your client can&#8217;t see the benefits of your work it&#8217;s your responsibility to step up and show them how your work output should be considered as part of a profit center. Here&#8217;s how: &#8211; Perform a [...]]]></description>
			<content:encoded><![CDATA[<p>Access can do great things, on a short time frame and with a smaller budget than other technologies. If your client can&#8217;t see the benefits of your work it&#8217;s your responsibility to step up and show them how your work output should be considered as part of a profit center. Here&#8217;s how:</p>
<p>&#8211; Perform a payback analysis<br />
Nothing shows you&#8217;re value more then a ROI analysis of your work. If you did your due diligence during the discovery phase you should have a good grasp of the business problem you&#8217;re solving, now dig deeper and determine how much money you will save your client with a great Access solution.</p>
<p>&#8211; Can&#8217;t quantify savings? How about improved customer service? Productivity? Ability to expand?<br />
Don&#8217;t short sell yourself if the ROI is difficult to come by, sometimes it&#8217;s hard to come up with an analysis that will show bottom line dollars, if that&#8217;s the case then aim for the intangibles: Does your app improve customer service? Can the firm do more with the same amount of people? Will the database prepare the company for growth going forward?</p>
<p>&#8211; Avoid the &#8220;L&#8221; word<br />
It pains me to say it, but some executives I&#8217;ve worked with have mentioned &#8220;Layoffs&#8221; when seeing the improvements our firm can bring them. I prefer the &#8220;doing more with the same amount of people&#8221; analogy myself. You always want buy-in from the team helping you at your client, so avoid terms that will produce anxiety.</p>
<p>&#8211; Think of your work as a Profit Center<br />
Many times it&#8217;s very easy to quantify savings&#8230;and so I always use the word &#8220;Investment&#8221; when referring to the cost of our work: &#8220;Your investment for this project will be&#8230;&#8221; is a line you will see at the end of my proposals.</p>
<p>Always view yourself in the right light and close more deals for your practice, get started today!</p>
<img src="http://feeds.feedburner.com/~r/accessexperts/feedburner/~4/lxBd7z3fQqE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://accessexperts.net/blog/2012/05/15/if-your-client-sees-you-as-a-cost-center-you-already-lost/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://accessexperts.net/blog/2012/05/15/if-your-client-sees-you-as-a-cost-center-you-already-lost/</feedburner:origLink></item>
		<item>
		<title>Subquery and the Scalar Query</title>
		<link>http://feedproxy.google.com/~r/accessexperts/feedburner/~3/O9FJQA-Q0C0/</link>
		<comments>http://accessexperts.net/blog/2012/05/07/subquery-and-the-scalar-query/#comments</comments>
		<pubDate>Mon, 07 May 2012 03:13:39 +0000</pubDate>
		<dc:creator>Juan Soto</dc:creator>
				<category><![CDATA[Access Help]]></category>

		<guid isPermaLink="false">http://accessexperts.net/blog/?p=1450</guid>
		<description><![CDATA[Today&#8217;s guest post come&#8217;s from Mark Davis, a Access MVP. You can learn more about him at http://www.linkedin.com/in/markgerarddavis The concept of a subquery itself is fairly straightforward: have a query within a query. However, there are various applications of the subquery. Most frequently, a subquery is used in a filtering context: SELECT a FROM n WHERE [...]]]></description>
			<content:encoded><![CDATA[<p><em>Today&#8217;s guest post come&#8217;s from Mark Davis, a Access MVP. You can learn more about him at <a href="http://www.linkedin.com/in/markgerarddavis" target="_blank">http://www.linkedin.com/in/markgerarddavis</a></em></p>
<p>The concept of a subquery itself is fairly straightforward: have a query within a query. However, there are various applications of the subquery. Most frequently, a subquery is used in a filtering context:</p>
<pre>SELECT a FROM n WHERE a NOT IN (SELECT a FROM x)</pre>
<p>However, this is only the tip of the iceberg of their usefulness. Subqueries can also be used to create a ‘temporary view’ within your query construct. Let me give an example. Suppose that we have a table, tblTimeClock, consisting of an employee ID, a dateWorked column, and a timeLogged column of type double. When an employee clocks out for a day, their id and the total time they worked for the day is logged here. Now, we want to retrieve for a given day the employees that worked, how long each employee worked, and the total hours all employees logged for the day. Without subqueries, we can do one or the other, but not both. To retrieve the time each employee worked for the day, we would write something like:</p>
<pre>SELECT employeeID, Sum(timeLogged) AS totEmpTime
 FROM tblTimeClock
 WHERE dateWorked=#11/13/2009#
 GROUP BY employeeID</pre>
<p>This would return us the time logged by each employee. Now, to get the total time logged, we could do . . .</p>
<pre>SELECT employeeID, Sum(timeLogged) AS totEmpTime, tTime.totTime
 FROM tblTimeClock,
 [SELECT Sum(timeLogged) AS totTime
 FROM tblTimeClock
 WHERE dateWorked=#11/13/2009#].
AS tTime
WHERE dateWorked=#11/13/2009#
GROUP BY employeeID</pre>
<p>As the subquery only returns one value, it is a scalar subquery. That subquery is aliased as a table, and can be treated as such by referencing its alias, and then the desired column name.</p>
<p>NOTE: Pay attention to the period after the closing bracket. Omitting this period will cause Access (JET &#8211; not yet fully tested in ACE) to not properly recognize the subquery. Also, there can be no brackets within the defining brackets, as this will cause the query to fail. So this means the field names in the table(s) must contain no spaces.</p>
<p>In a more complex but practical example, say we want to retrieve all dry chemical lots produced in November 2009, and their moistures, if available. Building a query as such:</p>
<pre><em><span style="font-family: Consolas;">SELECT Lot.Lot_Number, rptQuality.cValu
FROM LOT LEFT JOIN rptQuality ON Lot.Lot_Number = rptQuality.lotnum
WHERE rptQuality.rstid=10 AND Lot.Lot_Completion_Date&gt;=#11/1/2009 12:0:0 AM# AND Lot.Lot_Completion_Date&lt;=#11/30/2009 11:59:59 PM# AND Lot.Hydro=’d’</span></em></pre>
<p>&nbsp;</p>
<p>Will only return to us the lot numbers and moistures of those lots that have been tested, regardless of the left join.  This is because we are filtering our result set by a value of that in the left-joined table (rstid=10), so we will only retrieve those lots that actually have moistures.  However, there may be several dozen lots that have been produced but not yet tested, and we do not want to exclude these lots from our query.  An appropriate solution is outlined below using a non-scalar subquery:</p>
<pre><em><em><span style="font-family: Consolas;">SELECT Lot.Lot_Number, rptQual.cValu
FROM LOT LEFT JOIN [SELECT rptQuality.lotnum, rptQuality.cValu FROM rptQuality WHERE rptQuality.rstid=10]. AS rptQual ON Lot.Lot_Number = rptQual.lotnum
WHERE Lot.Lot_Completion_Date&gt;=#11/1/2009 12:0:0 AM# AND Lot.Lot_Completion_Date&lt;=#11/30/2009 11:59:59 PM# AND Lot.Hydro=’d’</span></em></em></pre>
<p>&nbsp;</p>
<p>This query pre-filters our results down to just those lots with moisture values. Then, the left join is applied. With no additional filters on the left-joined table, our query will correctly return ALL produced dry lots in November, and show any relevant moistures.</p>
<p>Subqueries used in this manner may be treated exactly like any other table or query, where one can aggregate data and perform any other transformations as necessary.</p>
<p>With Access 97 (newer versions untested), there are some limitations to the subquery. First, a subquery cannot be nested within a subquery. In extremely complex cases, you will have to either store the results of one of the subqueries in the back-end .mdb as a view or temp table, or figure out a way to create the complex join syntax to make it work properly. Also, Access 97 does not like the use of [] to encapsulate relative field references. I.E. [SELECT [Lot_Number] FROM Lot]. AS LtNum will error Access in a heartbeat. You MUST use absolute field references as such: [SELECT Lot.Lot_Number FROM Lot]. AS LtNum. To summarize you cannot use [ or ] within your subquery, or Access will produce errors. Meaning, the field names in the table(s) must contain no spaces.</p>
<p>For more information on subqueries and scalar subqueries, please visit the following resource(s):<br />
<a href="http://www.blueclaw-db.com/accessquerysql/scalar_subquery.htm">http://www.blueclaw-db.com/accessquerysql/scalar_subquery.htm</a></p>
<img src="http://feeds.feedburner.com/~r/accessexperts/feedburner/~4/O9FJQA-Q0C0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://accessexperts.net/blog/2012/05/07/subquery-and-the-scalar-query/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://accessexperts.net/blog/2012/05/07/subquery-and-the-scalar-query/</feedburner:origLink></item>
		<item>
		<title>PAUG Live Blogging</title>
		<link>http://feedproxy.google.com/~r/accessexperts/feedburner/~3/W9SEj4zWe6Q/</link>
		<comments>http://accessexperts.net/blog/2012/05/07/paug-live-blogging/#comments</comments>
		<pubDate>Sun, 06 May 2012 19:09:22 +0000</pubDate>
		<dc:creator>Juan Soto</dc:creator>
				<category><![CDATA[Access Help]]></category>

		<guid isPermaLink="false">http://accessexperts.net/blog/?p=1455</guid>
		<description><![CDATA[This week I&#8217;m at Paug&#8217;s Access conference in gorgeous Silverfalls, Oregon. I&#8217;ll be live blogging here so come back here often for frequent updates over the weekend. It&#8217;s sold out &#8211; again Yet again this year&#8217;s conference was sold out, not because there&#8217;s a ton of people here but there is a low threshold of [...]]]></description>
			<content:encoded><![CDATA[<p>This week I&#8217;m at <a href="http://paug.com/Conference.asp" target="_blank">Paug&#8217;s</a> Access conference in gorgeous Silverfalls, Oregon. I&#8217;ll be live blogging here so come back here often for frequent updates over the weekend.</p>
<p><strong>It&#8217;s sold out &#8211; again</strong></p>
<p>Yet again this year&#8217;s conference was sold out, not because there&#8217;s a ton of people here but there is a low threshold of attendees due to the facilities. It lends itself to a small gathering of less than 100 people and a great atmosphere of sharing. Each year I book earlier so I don&#8217;t miss out. In addition, we had people from Brussels Belgian and Australia this year, which I think is a testament to the value of the conference.</p>
<p><strong>Great Mix of People</strong></p>
<p>I don&#8217;t have exact numbers but it seams that this year we have more independent consultants, but we still have a good mix of programmers, non-programmers, government and private enterprise people.</p>
<p><strong>Day 1 &#8211; Walk your heart out</strong></p>
<p>I enjoy coming in early and taking the walk around the Southern falls and being one with nature for a few hours. This year I arrived 30 mins late and had to do it alone, but I enjoy coming here and seeing and hearing the roar of the water as the mountain caps melt. I will post photos and videos when I get back home, simply stunning. Word to the wise: Bring hiking shoes and be prepared to hike a couple of miles going downhill and uphill. My sedentary programming job doesn&#8217;t prepare me for these hikes, but I love doing it.</p>
<p><a href="http://www.appsplus.com/" target="_blank">F. Scott Barker</a> - Automating Applications from Access.</p>
<p>Scott&#8217;s a great presenter, he kept us roaring with laughter, which is a great sign of a wonderful presenter, and had something for both the beginners and pros in the room. Scott established what would be the norm throughout the conference - speak up and let&#8217;s make this interactive. We took it to heart and peppered him with questions and observations.</p>
<p>Break &#8211; veggies! Thanks John!</p>
<p><a href="http://www.fmsinc.com/" target="_blank">Luke Chung</a> &#8211; Taking over an Access Application</p>
<p>Luke blew it out of the water with the most comprehensive discussion on this topic I&#8217;v ever seen. He had 1.5 hours and did not stop for a breather, going through 50 slides of great info complemented with tips and personal experience.</p>
<p>Dinner &#8211; Beef Brisquette</p>
<p><a href="http://www.jstreettech.com/" target="_blank">Armen Stein</a> &#8211; Round Table &#8211; Business/Consultant Roundtable Best Pratices</p>
<p>Armen did a great job hosting a wonderful session where we discussed many aspects of having a practice. We discussed a wide range of topics: quotes, estimating, handling clients, you name it. Worth the price of coming out here just for this.</p>
<p>End of Day 1 &#8211; Social at Blueberry</p>
<p>We all ended up at one of the buildings here and talked late into the night at the social, catching up with old friends and talking IT, sports, etc. plus smoking my stogie and drinking my fav beer.</p>
<p>Day 2 &#8211; Ryan McMinn &#8211; Access 15 Overview and where Access is headedd</p>
<p>Nothing new for me here, saw the same things I saw at MVP conference and still can&#8217;t talk about it till the pre-release is out. Lots if interest and questions from the audience on this topic.</p>
<p>Armen Stein &#8211; Experiences in Microsoft Cloud</p>
<p>I&#8217;m not a fanboy of Microsoft&#8217;s cloud resources but Armen made a great case for the move. He mentioned how using Lync he can be on a conference call and have it switch to the phone and not miss a beat. The economics are so cheap that if you&#8217;re not using Exchange with Outlook you really don&#8217;t have an excuse to make the switch.</p>
<p>F. Scott Barker &#8211; Using API Libraries in Access</p>
<p>Learned something new today: you can use API calls to create network drives, both interactively or behind the scenes. Also, always use the API vs File Dialog ActiveX object since the API version works every time. Note to self: Don&#8217;t change working demo code to try out suggestions from audience members, never leads to a good result. Scott touches most of the usual APIs we commonly use: Zip and Unzipping, user names, file dialogs, etc.</p>
<p>Alison Barter &#8211; Upsizing Access to SQL Server</p>
<p>This topic is near and dear to my heart, so I was looking forward to Alison&#8217;s presentation. She did a thorough review of upsizing Access.</p>
<p>Round Table with Ryan</p>
<p>Everyone peppered Ryan with questions on the future of Access: No VBA is NOT going away. Don&#8217;t know when Office 15 is coming out. There is no Developer certifications for Microsoft Access.</p>
<p>End of Day 2</p>
<p>&nbsp;</p>
<img src="http://feeds.feedburner.com/~r/accessexperts/feedburner/~4/W9SEj4zWe6Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://accessexperts.net/blog/2012/05/07/paug-live-blogging/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://accessexperts.net/blog/2012/05/07/paug-live-blogging/</feedburner:origLink></item>
		<item>
		<title>Using Recursion in your Access database</title>
		<link>http://feedproxy.google.com/~r/accessexperts/feedburner/~3/nhNrzr671yA/</link>
		<comments>http://accessexperts.net/blog/2012/05/03/using-recursion-in-your-access-database/#comments</comments>
		<pubDate>Wed, 02 May 2012 19:12:06 +0000</pubDate>
		<dc:creator>Juan Soto</dc:creator>
				<category><![CDATA[Access Help]]></category>

		<guid isPermaLink="false">http://accessexperts.net/blog/?p=1448</guid>
		<description><![CDATA[Today&#8217;s guest post come&#8217;s from Mark Davis, a Access MVP. You can learn more about him at http://www.linkedin.com/in/markgerarddavis At its simplest definition, recursion is a function that is applied to itself, or a function that is called by itself.  Here is a basic example, taken from mathematics, of a factorial.  5! is expressed as 5x4x3x2x1, [...]]]></description>
			<content:encoded><![CDATA[<p><em>Today&#8217;s guest post come&#8217;s from Mark Davis, a Access MVP. You can learn more about him at <a href="http://www.linkedin.com/in/markgerarddavis" target="_blank">http://www.linkedin.com/in/markgerarddavis</a></em></p>
<p>At its simplest definition, recursion is a function that is applied to itself, or a function that is called by itself.  Here is a basic example, taken from mathematics, of a factorial.  5! is expressed as 5x4x3x2x1, or 120.  To compute a factorial for the number n, the following simple function could be utilized:</p>
<pre>Public Function factorial(n as Integer) AS Integer
            If n &lt;= 1 then
                        Factorial = 1
            Else
                        Factorial = n * factorial(n-1)
            End if
End Function</pre>
<p>The logic for this function is as follows: We will use 3 as our n parameter value.  Upon first call, we have 3*factorial(2).  Factorial(2) is 2*Factorial(1).  Factorial(1) is 1.  We therefore have 3*2*1, or 6.</p>
<p>Recursion within the scope of say, a laboratory information management system, is used to build complex formulas, which are based on other formulas.  For example, if we have a formula for Copper Dry Basis that is CuWt*(1-Moist), where CuWt is a formula that is (CuPost-CuTare)/CuWt, and we try to parse out say, a Copper Dry Basis formula, first the parsing function is called.  The first element it sees might be a CuWt formula.  The parsing function is again called, this time with the formula id for CuWt.  (CuPost-CuTare)/CuWt as a string is returned (with relevant values, of course).  The original call to the parsing function is now active again, and we continue processing the additional elements, ‘*)1-‘, Moist, and ‘)’ .</p>
<p>These recursions are built into the formula models, allowing ultimate flexibility when building formulas.  Though we could technically have the formula model exist without recursion, it would make the creation and application of some formulas near impossible to enter in the correct syntax.  As an example, the verbose display of the Error % formula for one process could easily be 1527 characters long, including all the appropriate bracketing and operands.  For the manager to be expected to correctly program that formula would be absurd.  Because of recursion, the formula can be simplified to it’s very base form, a percentage difference formula, which is only 64 characters in length.</p>
<p>A special note for consideration is that there must always be a final point of termination for recursive functions.  For the sake of this discussion, that point of termination is when there are no longer any elements to process for the current formula, specifically elements of the ‘formula’ type.  In our above factorial example, we halt processing when we get to the integer 1, as defined by the mathematical definition of a factorial.  Not providing a final point of termination results in a similar scenario to an infinite loop, causing memory leaks and a whole bunch of bad stuff that you really don’t want to deal with.  As a matter of practicality, a mathematical formula cannot be based on itself.  So, the formula for Copper Dry Basis cannot be based on the formula for Copper Dry Basis.  When editing formula compositions by hand (you should NOT do this and instead should use the formula builder &#8211; a separate form and base table used to construct the formulas).</p>
<p>For more information on the concept of recursion, as well as programming examples, please see the following resources:</p>
<p><a href="http://en.wikipedia.org/wiki/Recursion#Recursion_in_computer_science">http://en.wikipedia.org/wiki/Recursion#Recursion_in_computer_science</a></p>
<p><a href="http://erwnerve.tripod.com/prog/recursion/magic.htm">http://erwnerve.tripod.com/prog/recursion/magic.htm</a> (geared toward java, but can be adapted easily)</p>
<img src="http://feeds.feedburner.com/~r/accessexperts/feedburner/~4/nhNrzr671yA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://accessexperts.net/blog/2012/05/03/using-recursion-in-your-access-database/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://accessexperts.net/blog/2012/05/03/using-recursion-in-your-access-database/</feedburner:origLink></item>
		<item>
		<title>Part 4: Switching from Production to Beta backends in SQL Server with ease.</title>
		<link>http://feedproxy.google.com/~r/accessexperts/feedburner/~3/HlSOyRR8f2U/</link>
		<comments>http://accessexperts.net/blog/2012/04/23/part-4-switching-from-production-to-beta-backends-in-sql-server-with-ease/#comments</comments>
		<pubDate>Sun, 22 Apr 2012 20:03:51 +0000</pubDate>
		<dc:creator>Juan Soto</dc:creator>
				<category><![CDATA[Access Help]]></category>

		<guid isPermaLink="false">http://accessexperts.net/blog/?p=1438</guid>
		<description><![CDATA[Author note: This is the final post on a four post series on DSN-less tables in Access. You can review part one here. Take a look at part 2 here. See part 3 here. How can you test changes in the cloud with your Beta users? Once you&#8217;ve rolled out your Access masterpiece using SQL Server in [...]]]></description>
			<content:encoded><![CDATA[<p><em>Author note: This is the final post on a four post series on DSN-less tables in Access.</em></p>
<p><em>You can review part one <a href="http://accessexperts.net/blog/2012/03/27/dsn-less-tables-a-better-way/">here</a>.</em></p>
<p><em>Take a look at part 2 <a title="Part 2: Linking tables using a SQL Server table" href="http://accessexperts.net/blog/2012/04/04/part-2-linking-tables-using-a-sql-server-table/">here.</a></em></p>
<p><em>See part 3 <a title="Part 3: Destroy your linked tables on exit" href="http://accessexperts.net/blog/2012/04/17/part-3-destroy-your-linked-tables-on-exit/">here.</a></em></p>
<p><strong>How can you test changes in the cloud with your Beta users?</strong></p>
<p>Once you&#8217;ve rolled out your Access masterpiece using SQL Server in the cloud, your client&#8217;s will love your work so much they are going to request additional changes. (Hint: If you don&#8217;t get upgrade requests then it wasn&#8217;t a masterpiece to begin with). It&#8217;s easy to test changes on a local SQL Server database, but more often than not you will need to have a select group of your app users try the changes before rolling them out to everyone, and that means testing using the cloud.</p>
<p><strong>Use a SQL Server Beta database to test changes before going live</strong></p>
<p>SQL Server makes it easy to create a Beta database, just copy the live database or restore a full backup and give it a different name. Typically, we give ours the same name with &#8220;Beta&#8221; suffix. We usually use the production server as our Beta server in order to test the system under real world conditions but you don&#8217;t have to. Once you have a Beta database up and running use the code below to easily switch from Beta to production and back.</p>
<p><strong>How to change to Beta: Just rename your Access file</strong></p>
<p>In our apps, to switch to our SQL Server Beta database we just add the word Beta to our Access file. Having to rename the file and not change any code makes life easier and allows us to experiment with data without impacting operations and ensures that both beta and production are functionally identical. Our client also uses the technique for training new users on the system.</p>
<pre>Public Function BetaTesting() As Boolean
10 If CurrentProject.Name = <a href="http://accessexperts.net/blog/2011/01/12/multi-session-global-variables/" target="_blank">ReadGV</a>("ProjectFileName", 1) Then
20    BetaTesting = False
30    <a href="http://accessexperts.net/blog/2010/09/16/maximize-the-user-of-tempvars-in-access-2007-and-2010/" target="_blank">TempVars</a>.Add "BetaTesting", False
 'Change from Beta to production?
40    If InStr(1, CurrentDb.TableDefs(ReadGV("BetaTableTest", strText)).Connect, ReadGV("BetaCatalog", strText)) &gt; 0 Then
 'Relink to production database
50       ChangeAppTitle ReadGV("ProjectTitle", strText)
60       <a href="http://accessexperts.net/blog/2012/04/04/part-2-linking-tables-using-a-sql-server-table/" target="_blank">RelinkAllTablesADOX</a>
70   End If
80 Else
90    BetaTesting = True
100   TempVars.Add "BetaTesting", True
110   ChangeAppTitle "++++++++ BETA " &amp; ReadGV("ProjectTitle", strText) &amp; " BETA +++++++++"
120   If InStr(1, CurrentDb.TableDefs(ReadGV("BetaTableTest", strText)).Connect, ReadGV("BetaCatalog", strText)) &lt; 1 Then
 'Relink to Beta database
130      <a href="http://accessexperts.net/blog/2012/04/04/part-2-linking-tables-using-a-sql-server-table/" target="_blank">RelinkAllTablesADOX</a>
140   End If
150 End If
End Function</pre>
<p>In line 10 we test if the current file name is the production version stored in our <a href="http://accessexperts.net/blog/2011/01/12/multi-session-global-variables/" target="_blank">tblProgramOptions</a> table, otherwise we are dealing with a Beta version of the system. (Click ReadGV to see a post on using ReadGV).</p>
<p>If it&#8217;s a production database then in line 30 we set a global variable for use later in the app. In line 40 we test if the table links are pointing to Beta and if so relink all tables to the production database in line 60.</p>
<p>If it&#8217;s a Beta database then in line 90 we define a global variable, change the app title and relink all tables to the Beta database in line 130. (Click on <a href="http://accessexperts.net/blog/2012/04/04/part-2-linking-tables-using-a-sql-server-table/">RelinkAllTablesADOX </a>to view a post on how to relink all of your tables.)</p>
<p>Since we name our SQL Server database by just adding Beta to the name we can use the following lines in RelinkAllTablesADOX to switch to Beta.</p>
<pre>If TempVars!IsBeta Then
 strCatalog =  conCatalog &amp;  "Beta"
 Else
 strCatalog = conCatalog
 End If</pre>
<p>&nbsp;</p>
<p>*UPDATE* Code for ChangeAppTitle follows:</p>
<pre>Public Sub ChangeAppTitle(strTitle As String)
 Dim proTitle As Property

 On Error Resume Next
 With CurrentDb
  Set proTitle = .CreateProperty("AppTitle", dbText, strTitle)
  Call .Properties.Append(proTitle)
  .Properties("AppTitle").Value = strTitle
 End With
 Call Application.RefreshTitleBar
End Sub</pre>
<p>&nbsp;</p>
<p><strong>Series Conclusion</strong></p>
<p>I hope all of these posts will help you take advantage of DSN-less tables in your app, let me know in the comments if you do use the code and how it&#8217;s helped you.</p>
<img src="http://feeds.feedburner.com/~r/accessexperts/feedburner/~4/HlSOyRR8f2U" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://accessexperts.net/blog/2012/04/23/part-4-switching-from-production-to-beta-backends-in-sql-server-with-ease/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://accessexperts.net/blog/2012/04/23/part-4-switching-from-production-to-beta-backends-in-sql-server-with-ease/</feedburner:origLink></item>
		<item>
		<title>Part 3: Destroy your linked tables on exit</title>
		<link>http://feedproxy.google.com/~r/accessexperts/feedburner/~3/T-wCXQ8ChR4/</link>
		<comments>http://accessexperts.net/blog/2012/04/17/part-3-destroy-your-linked-tables-on-exit/#comments</comments>
		<pubDate>Mon, 16 Apr 2012 21:20:56 +0000</pubDate>
		<dc:creator>Juan Soto</dc:creator>
				<category><![CDATA[Access Help]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://accessexperts.net/blog/?p=1430</guid>
		<description><![CDATA[Author note: This is part 3 of a series on DSN-less tables in Access. You can review part one here. Part 2 here. Part 4 here. In part three of this series I&#8217;m going to give you the code to delete all of your linked tables once the app closes. Deleting your links makes your app secure [...]]]></description>
			<content:encoded><![CDATA[<p><em>Author note: This is part 3 of a series on DSN-less tables in Access. </em></p>
<p><em>You can review part one <a href="http://accessexperts.net/blog/2012/03/27/dsn-less-tables-a-better-way/">here</a>. P</em><em>art 2 <a title="Part 2: Linking tables using a SQL Server table" href="http://accessexperts.net/blog/2012/04/04/part-2-linking-tables-using-a-sql-server-table/">here.</a> Part 4 <a title="Part 4: Switching from Production to Beta backends in SQL Server with ease." href="http://accessexperts.net/blog/2012/04/23/part-4-switching-from-production-to-beta-backends-in-sql-server-with-ease/">here.</a></em></p>
<p>In part three of this series I&#8217;m going to give you the code to delete all of your linked tables once the app closes. Deleting your links makes your app secure since both the user&#8217;s name and password are stored with the linked tables. It may not be much of an issue on a local area network, but if your app is using SQL Server in the cloud it can be a security issue.</p>
<p><strong>Where to place your code?</strong></p>
<p>At our shop we have a main form that launches on every app, so we place the following code on the form&#8217;s close event:</p>
<pre>Private Sub Form_Close()
   'delete any tables where connection property has ODBC in it
   Dim tdf As DAO.TableDef
StartAgain:
 For Each tdf In CurrentDb.TableDefs
    If InStr(1, tdf.Connect, "ODBC") &gt; 0 Then
       DoCmd.DeleteObject acTable, tdf.Name
       GoTo StartAgain
    End If
 Next tdf
 Set tdf = Nothing
End Sub</pre>
<p>&nbsp;</p>
<p>Notice the use of the label &#8220;StartAgain&#8221; when you delete a table it changes the tabledef collection and you need to start over in order to refresh it, otherwise the code will error out.</p>
<p>Next Week: Changing from Production to Beta database by just changing the Access file name.</p>
<img src="http://feeds.feedburner.com/~r/accessexperts/feedburner/~4/T-wCXQ8ChR4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://accessexperts.net/blog/2012/04/17/part-3-destroy-your-linked-tables-on-exit/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://accessexperts.net/blog/2012/04/17/part-3-destroy-your-linked-tables-on-exit/</feedburner:origLink></item>
		<item>
		<title>Part 2: Linking tables using a SQL Server table</title>
		<link>http://feedproxy.google.com/~r/accessexperts/feedburner/~3/fNJGwz-UfvI/</link>
		<comments>http://accessexperts.net/blog/2012/04/04/part-2-linking-tables-using-a-sql-server-table/#comments</comments>
		<pubDate>Wed, 04 Apr 2012 03:00:34 +0000</pubDate>
		<dc:creator>Juan Soto</dc:creator>
				<category><![CDATA[Access Help]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://accessexperts.net/blog/?p=1415</guid>
		<description><![CDATA[Author note: This is part 2 of a series on DSN-less tables in Access. You can review part one here. Part three here. Part four here. In last week&#8217;s post I talked about using a single table in your SQL Server database to easily manage security, in today&#8217;s post I&#8217;m going to take it one step further and [...]]]></description>
			<content:encoded><![CDATA[<p><em>Author note: This is part 2 of a series on DSN-less tables in Access.</em></p>
<p><em>You can review part one <a href="http://accessexperts.net/blog/2012/03/27/dsn-less-tables-a-better-way/">here</a>. P</em><em>art three <a title="Part 3: Destroy your linked tables on exit" href="http://accessexperts.net/blog/2012/04/17/part-3-destroy-your-linked-tables-on-exit/">here.</a> Part four <a title="Part 4: Switching from Production to Beta backends in SQL Server with ease." href="http://accessexperts.net/blog/2012/04/23/part-4-switching-from-production-to-beta-backends-in-sql-server-with-ease/">here.</a></em></p>
<p>In last week&#8217;s post I talked about using a single table in your SQL Server database to easily manage security, in today&#8217;s post I&#8217;m going to take it one step further and use that same table to create all the necessary links needed for your app on startup.</p>
<p><strong>Use ADODB to loop through table and create links</strong><br />
The technique uses an ADODB recordset to loop through all the records in tblTablePermissions and create the links on startup. We store the user&#8217;s name and password with the link, so we use a custom login form to store the user&#8217;s name and password for the session, which are then used to create the links.</p>
<p><strong>Step 1: Trap user&#8217;s login info and test to see if they can connect with SQL Server</strong><br />
Here&#8217;s the code we use when the user clicks the login button on our login form:</p>
<pre>Private Sub cmdLogin()
If IsNull(Me.txtUserID) Or IsNull(Me.txtPassword) Then
 MsgBox "You must supply both your user name and password", vbInformation, "Can't Login"
 Exit Sub
End If
'Store login credentials in memory
TempVars.Add "UserID", Me.txtUserID.Value
TempVars.Add "Password", Me.txtPassword.Value
If InStr(1, CurrentProject.Name, "Beta") &gt; 0 Then
   TempVars.Add "IsBeta", True
Else
   TempVars.Add "IsBeta", False
End If
If Not OpenMyConnection Then
 MsgBox "Connection to SQL Server failed, please verify your user name and/or password", vbInformation, "Login Failed"
 Exit Sub
End If

RelinkAllTablesADOX
End Sub</pre>
<p>&nbsp;</p>
<p><strong>Change between Beta and Production Databases</strong><br />
By including the name &#8220;Beta&#8221; in the project name the code will point to the Beta database instead of the production one. I&#8217;ll be elaborating more on this later in the series.</p>
<p><strong>OpenMyConnection</strong></p>
<p>Notice the use of OpenMyConnection, which I use in my<a href="http://accessexperts.net/blog/2011/01/21/easy-adodb-recordsets-and-commands-in-access/"> Easy ADODB </a>methods. Here is the definition of the function:</p>
<pre>Public Function OpenMyConnection() As Boolean
 On Error GoTo OpenMyConnection_Error

10 If con.State = adStateOpen Then
20 con.Close
30 End If
40 con.ConnectionString = conConnection &amp; "User ID =" &amp; TempVars!UserID &amp; ";Password=" &amp; TempVars!Password
50 con.Open
60 If Not con.State = adStateOpen Then
70 OpenMyConnection = False
80 Else
90 OpenMyConnection = True
100 End If
On Error GoTo 0
 Exit Function
OpenMyConnection_Error:
MsgBox "Error " &amp; Err.Number &amp; " Line " &amp; Erl &amp; " (" &amp; Err.Description &amp; ") in procedure OpenMyConnection of Module mdlConnect"
End Function</pre>
<p>&nbsp;</p>
<p><strong>RelinkAllTablesADOX Procedure</strong><br />
This procedure is where the fireworks go off:</p>
<pre>Function RelinkAllTablesADOX() As Boolean
 Dim cat As Object
 Dim tbl As Object
 Dim fLink As Boolean
 Dim strSQL As String
 Dim strTableName As String
 Dim strField As String
 Dim strDriver As String
 Dim strLocalTableName As String
 Dim rs As ADODB.Recordset
 Dim strCatalog As String
 Const conCatalog As String = "DataBE"
 Const conServer As String = "ServerName"
 On Error GoTo HandleErr
 Set cat = CreateObject("ADOX.Catalog")
 cat.ActiveConnection = CurrentProject.Connection
 strDriver = "SQL Server"

 For Each tbl In cat.Tables
 With tbl
 ' Delete any linked tables
   If .Type = "PASS-THROUGH" Then
     CurrentDb.TableDefs.Delete .Name
   End If
 End With
 Next tbl

30 strSQL = "Select * from tblTablePermissions Where DontLink = 0"
 <a href="http://accessexperts.net/blog/2011/01/21/easy-adodb-recordsets-and-commands-in-access/" target="_blank">OpenMyRecordset</a> rs, strSQL
If TempVars!IsBeta Then
 strCatalog =  conCatalog &amp;  "Beta"
 Else
 strCatalog = conCatalog
 End If
With rs
 Do While .EOF = False
 strTableName = !Table_Name
35 If IsNull(!Access_Name) Then
 strLocalTableName = strTableName
 Else
 strLocalTableName = !Access_Name
 End If
40 fLink = AttachDSNLessTable(strLocalTableName, strTableName, conServer, strCatalog, strDriver, _
 TempVars!UserID, TempVars!Password)

50 'Is it a view? If so check if index needed
 If Left(strTableName, 2) = "vw" And fLink Then
 strField = Nz(DLookup("KeyField", "tblLinkViews", "[View] = '" &amp; strTableName &amp; "'"), "")
 If Not strField = "" Then
 strSQL = "Create Index IX_" &amp; strField &amp; " On " &amp; strLocalTableName &amp; " (" &amp; strField &amp; ") WITH PRIMARY"
 CurrentDb.Execute strSQL
 End If
 End If
 .MoveNext
 Loop
 End With
 RelinkAllTablesADOX = fLink
ExitHere:
 Set cat = Nothing
 Exit Function
HandleErr:
 RelinkAllTablesADOX = False
 If Not fLink Then
 'MsgBox "Linking failed, please contact tech support.", vbInformation, "Error Linking Table"
 Resume ExitHere
 End If
 MsgBox _
 Prompt:=Err &amp; ": " &amp; Err.Description, _
 Title:="Error in RelinkAllTablesADOX"
 Resume ExitHere
End Function</pre>
<p><strong>Only link tables where DontLink = 0<br />
</strong>Notice in Line 30 above we only link tables that have DontLink set t False. You may wonder why we even bother placing a table in tblTablePermissions when it&#8217;s not used in Access as a linked table? Remember in my first post we use it for setting security of all tables, and if there is ever a need to use ADODB and go directly to the table in SQL Server via our Access code or pass-through query then we need that table listed in tblTablePermissions.</p>
<p><strong>Does view need index?<br />
</strong>In line 50 above the code checks if the table being linked is a view, and if so, creates the index in Access using a local table called tblLinkViews. You could probably do away with this concept in your code and just add another column to tblTablePermissions called ViewIndex, then just use !ViewIndex in the code above to read the SQL syntax into strSQL.</p>
<p><strong>Rename SQL Server Table?</strong><br />
Notice in line 35 above the system will actually use a different name for the Access table if so specified. This technique can come in handy when your dealing with a legacy app and wish to use names in SQL Server that better suit you but can&#8217;t be used in Access due to legacy code.</p>
<p><strong>AttachDSNLess Table Code</strong><br />
The above procedure calls this sub to actually do the linking:</p>
<pre>'Note: Code adapted from <a href="http://support.microsoft.com/kb/892490">http://support.microsoft.com/kb/892490</a>
Function AttachDSNLessTable(stLocalTableName As String, stRemoteTableName As String, stServer As String, stDatabase As String, strDriver As String, _
 Optional stUserName As String, Optional stPassword As String) As Boolean
10 On Error GoTo AttachDSNLessTable_Err
 Dim td As TableDef
 Dim stConnect As String

20 If stLocalTableName = "" Then
30 stLocalTableName = stRemoteTableName
40 End If
50 Application.Echo True, "Linking table " &amp; stLocalTableName
 'Stop
 '//WARNING: This will save the username and the password with the linked table information.
60 stConnect = "ODBC;DRIVER=" &amp; strDriver &amp; ";SERVER=" &amp; stServer &amp; ";DATABASE=" &amp; stDatabase &amp; ";UID=" &amp; stUserName &amp; ";PWD=" &amp; stPassword

70 Set td = CurrentDb.CreateTableDef(stLocalTableName, dbAttachSavePWD, stRemoteTableName, stConnect)
80 CurrentDb.TableDefs.Append td
90 AttachDSNLessTable = True
100 Exit Function
AttachDSNLessTable_Err:
110 If Err.Number = 3265 Or Err.Number = 3011 Then
 'Table does not exist, continue anyway
120 Resume Next
130 End If
140 AttachDSNLessTable = False
150 Stop
160 MsgBox "AttachDSNLessTable encountered an unexpected error: " &amp; Err.Description
End Function</pre>
<p>&nbsp;</p>
<p>In my next post I&#8217;ll discuss how to destroy the links when you exit the application.</p>
<img src="http://feeds.feedburner.com/~r/accessexperts/feedburner/~4/fNJGwz-UfvI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://accessexperts.net/blog/2012/04/04/part-2-linking-tables-using-a-sql-server-table/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://accessexperts.net/blog/2012/04/04/part-2-linking-tables-using-a-sql-server-table/</feedburner:origLink></item>
		<item>
		<title>DSN-less tables; a better way…</title>
		<link>http://feedproxy.google.com/~r/accessexperts/feedburner/~3/psuemqMBcl8/</link>
		<comments>http://accessexperts.net/blog/2012/03/27/dsn-less-tables-a-better-way/#comments</comments>
		<pubDate>Tue, 27 Mar 2012 03:04:34 +0000</pubDate>
		<dc:creator>Juan Soto</dc:creator>
				<category><![CDATA[Access Help]]></category>
		<category><![CDATA[SQL Server]]></category>

		<guid isPermaLink="false">http://accessexperts.net/blog/?p=471</guid>
		<description><![CDATA[Author note: This is part 1 of a series on DSN-less tables in Access. You can review part two here. Take a look at part three here and part four here. In my first post on this topic, I sent you to Doug Steele&#8217;s great article on how to do DSN-less table connections. Today I&#8217;m starting a new series [...]]]></description>
			<content:encoded><![CDATA[<p><em>Author note: This is part 1 of a series on DSN-less tables in Access.</em></p>
<p><em>You can review part two <a title="Part 2: Linking tables using a SQL Server table" href="http://accessexperts.net/blog/2012/04/04/part-2-linking-tables-using-a-sql-server-table/">here</a>. </em><em>Take a look at part three <a title="Part 3: Destroy your linked tables on exit" href="http://accessexperts.net/blog/2012/04/17/part-3-destroy-your-linked-tables-on-exit/">here</a> and part four <a title="Part 4: Switching from Production to Beta backends in SQL Server with ease." href="http://accessexperts.net/blog/2012/04/23/part-4-switching-from-production-to-beta-backends-in-sql-server-with-ease/">here.</a></em></p>
<p>In my first <a title="DSN-less Connections and AD Security" href="http://accessexperts.net/blog/2011/04/11/dsn-less-connections-and-ad-security/">post</a> on this topic, I sent you to Doug Steele&#8217;s great article on how to do DSN-less table connections. Today I&#8217;m starting a new series of post on this topic that will cover the following:</p>
<ul>
<li>Using a SQL Server table to drive the process of creating DSN-less tables in Access. As an added benefit we will use the same table to setup security for tables.</li>
<li>Code in Access that will cycle through the SQL Server table and create the links.</li>
<li>Code in Access to destroy the links before exciting the application.</li>
<li>Switching between Beta and production servers with ease.</li>
</ul>
<p><strong>Why Destroy The Links?<br />
</strong>Our firm always uses DSN-less tables; by avoiding a DSN at each workstation at the client site, we simplify our deployment. It works well in a corporate environment since we use a trusted connection, meaning your Windows password and username are not included in the table link. If you grab the application and put it on another workstation that user&#8217;s credentials are used instead, not the original users.</p>
<p>But if the application is using SQL Server over the web, (data in the cloud), we&#8217;re  using SQL Server security, where we prefer to control the login process using an Access form as opposed to letting Access handle it with a cryptic message. Once the user is authenticated through our code, we proceed to link all of the tables using a single SQL Server table, which saves the username and password with the table links behind the scenes. We destroy the links when the user exits the app so that it can&#8217;t be used by unauthorized users.</p>
<blockquote><p>It takes time to recreate all of the links on startup, so managing user expectations is essential. In general, people don&#8217;t mind waiting a little bit on program startup, in particular if it&#8217;s good for securing their data</p></blockquote>
<p><strong>Don&#8217;t rely on your table being there&#8230;</strong><br />
One benefit of this approach is not worrying if the user, (or the programmer), deletes a linked table while using the app. The system will simply recreate the link again on startup.</p>
<p><strong>One table to rule them all: <a href="http://accessexperts.net/blog/wp-content/uploads/2012/03/tblTablePermissions.txt" target="_blank">tblTablePermissions</a><br />
</strong><a href="http://accessexperts.net/blog/wp-content/uploads/2012/03/tblTablePermissions.txt" target="_blank">tblTablePermissions </a>in SQL Server has a dual purpose: set permissions for all other SQL Server tables and drive the linking process in Access.</p>
<p>One of the best features of SQL Server is its ability to secure data, but it can be a chore to maintain and a hassle to setup, the more tables your app has the longer it can take to manually setup security. With <a href="http://accessexperts.net/blog/wp-content/uploads/2012/03/tblTablePermissions.txt" target="_blank">tblTablePermissions</a> and usp_RunPermissions we can easily add a table or view to the database and quickly redo our security schema by running <a href="http://accessexperts.net/blog/wp-content/uploads/2012/03/usp_RunPermissions.txt" target="_blank">usp_RunPermissions</a>.</p>
<p><strong>Three security roles: Admins, Employees and Clients</strong></p>
<p>The app where I designed this technique had three roles in SQL Server:</p>
<ul>
<li>Admin: Members in this role get all rights to every table listed in tblTablePermissions</li>
<li>Employee: Read rights to all tables and selective rights based on which columns are set to True in UpdateEmployee, DeleteEmployee or InsertEmployee.</li>
<li>Client: The app I designed with this security schema also had clients logging in to mostly view data and only modify certain tables, such as tblNotes. For the majority of tables they get read on nothing at all.</li>
</ul>
<div><strong>Setting up security is a breeze&#8230;</strong></div>
<div>Just add all your table names to <a href="http://accessexperts.net/blog/wp-content/uploads/2012/03/tblTablePermissions.txt" target="_blank">tblTablePermissions </a>and set any columns to True as needed. Then run <a href="http://accessexperts.net/blog/wp-content/uploads/2012/03/usp_RunPermissions.txt" target="_blank">usp_RunPermissions</a>, which in turn will execute three other procedures: <a href="http://accessexperts.net/blog/wp-content/uploads/2012/03/usp_GrantAdmin.txt" target="_blank">usp_GrantAdmin</a>, <a href="http://accessexperts.net/blog/wp-content/uploads/2012/03/usp_GrantEmployee.txt" target="_blank">usp_GrantEmployee </a>and <a href="http://accessexperts.net/blog/wp-content/uploads/2012/03/usp_GrantClient.txt" target="_blank">usp_GrantClient</a>. Each of them will setup security on each table based on which column is set to True. Note: Change each procedure as needed to the role name you have in your SQL Server database. In my database they were Admin, Employee and Client but yours may differ.</div>
<div></div>
<div>Don&#8217;t forget to setup read only on tblTablePermissions for all user groups.</div>
<div></div>
<p>Next week : Code in Access to read tblTablePermissions and setup table links!</p>
<img src="http://feeds.feedburner.com/~r/accessexperts/feedburner/~4/psuemqMBcl8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://accessexperts.net/blog/2012/03/27/dsn-less-tables-a-better-way/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://accessexperts.net/blog/2012/03/27/dsn-less-tables-a-better-way/</feedburner:origLink></item>
		<item>
		<title>Why using unbound forms are a bad idea</title>
		<link>http://feedproxy.google.com/~r/accessexperts/feedburner/~3/F-NNGS2sxSE/</link>
		<comments>http://accessexperts.net/blog/2012/03/13/why-using-unbound-forms-are-a-bad-idea/#comments</comments>
		<pubDate>Tue, 13 Mar 2012 14:26:42 +0000</pubDate>
		<dc:creator>Juan Soto</dc:creator>
				<category><![CDATA[Access Help]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://accessexperts.net/blog/?p=1355</guid>
		<description><![CDATA[Many of you know that I&#8217;m a big fan of Access with SQL Server, and if you&#8217;re a frequent blog reader you will also know it&#8217;s not easy to optimize the relationship between them, it takes work but it&#8217;s very rewarding when they&#8217;re working great.  Some developers however go to the extreme and use unbound [...]]]></description>
			<content:encoded><![CDATA[<p>Many of you know that I&#8217;m a big fan of Access with SQL Server, and if you&#8217;re a frequent blog reader you will also know it&#8217;s not easy to <a href="http://accessexperts.net/blog/2011/01/26/optimize-sql-server-with-access-on-a-wan/" target="_blank">optimize</a> the relationship between them, it takes <a href="http://accessexperts.net/blog/2010/07/24/tips-for-designing-sql-server-tables-for-microsoft-access-2/" target="_blank">work</a> but it&#8217;s very rewarding when they&#8217;re working great.  Some developers however go to the extreme and use unbound forms, is it worth it?</p>
<p><strong>To bind or not to bind, that is the question</strong></p>
<p>Unbound forms are forms with no data source, whereas bound forms have one and it&#8217;s the default way to bind your form to your tables or queries. Having a data source is the normal way you create Access forms,  but it can cause problems no matter how careful you can be:</p>
<ul>
<li>Record Locks &#8211; Have you ever had an app grind to a halt because someone left for lunch while editing a record?</li>
<li>Slow performance in opening a form: A poorly designed form can be bring your app to it&#8217;s knees.</li>
<li>Lost Data &#8211; Stop me if you&#8217;ve heard this one: &#8220;You and another user are editing the same record, you can either copy to the clipboard or discard your changes&#8221;</li>
</ul>
<div>Unbound forms avoid all of the hassles mentioned above:</div>
<div>
<ul>
<li>Quick loading of data since you only retrieve data the user needs to see in that moment.</li>
<li>No locks placed on your tables</li>
<li>You can parse the data through all kinds of business rules before posting back to your database.</li>
</ul>
</div>
<p><strong>Wow, that sounds awesome! What&#8217;s not to like?</strong></p>
<p>Unbound forms require a LOT of code to work. You basically must take over the tasks Access will normally handle: retrieve data from your database and store it locally, load the data into your forms fields, wait until user saves, discards or edits data, save said data back to your database. In short, you have just increased your workload tenfold, for a small increase in performance, if any.</p>
<p><strong>Tips for using bound forms:</strong></p>
<p>Rather than using unbound forms, here are some tips to optimize bound forms you can use to avoid issues:</p>
<ul>
<li><strong>Maximize the user of views and stored procedures.</strong> Ask yourself every time you want Access to do something if it can be done by the server better and faster.</li>
<li><strong>Never display data the user has not asked for.</strong> For example, always use the where clause of the DoCmd.OpenForm and DoCmd.OpenReport to display the exact record(s) needed by the user.</li>
<li><strong><a href="http://accessexperts.net/blog/2012/01/10/create-temp-tables-in-access-from-sql-server-tables/" target="_blank">Use temporary tables as much as you can.</a></strong> They are great for speeding up your app and provide some of the benefits of unbound forms. Example: Avoid mixing local tables with SQL Server tables and instead download the SQL Server data into one or more temp tables.</li>
<li><strong>Use infrequently updated lookup tables in the frontend and not on SQL Server.</strong> For example, the list of 50 states and territories should be a native table in your FE. Have a duplicate copy on  your server for views you may create for your app.</li>
<li><a href="http://accessexperts.net/blog/2011/01/21/easy-adodb-recordsets-and-commands-in-access/" target="_blank">Maximize the use of ADODB.</a> If you haven&#8217;t learned how to use ADODB you are really missing out on the best method to communicate with SQL Server from Access.  For example, instead of using DAO and action queries on linked tables, send the action query to SQL Server, which can do it far faster in almost all cases. Ben has in exceptional cases, even <a href="http://support.microsoft.com/kb/281998" target="_blank">bound forms to ADO recordsets,</a> which offers full native functionality and is still easier than doing it unbound. However, it has some <a href="http://www.utteraccess.com/wiki/index.php/Using_ADO" target="_blank">caveats</a> that you should be aware of if you go this route.</li>
<li><a href="http://accessexperts.net/blog/2010/12/03/great-links-to-help-you-with-access-and-sql-server/" target="_blank">Learn TSQL</a>: To really turbo charge Access with SQL Server you&#8217;re going to have to learn SQL Server&#8217;s native language. What are you waiting for? Go out and purchase a good TSQL beginner&#8217;s book and learn it today!</li>
</ul>
<p>Hope these tips help you out! If you want even more, look at those excellent guides:</p>
<p><strong><a href="http://www.utteraccess.com/wiki/index.php/Beginners_Guide_To_ODBC">UtterAccess&#8217; Beginner&#8217;s Guide to ODBC</a></strong></p>
<p><strong><a href="http://msdn.microsoft.com/en-us/library/bb188204(v=sql.90).aspx">Andy Baron&#8217;s Optimizing Microsoft Access with SQL Server</a></strong></p>
<p>&nbsp;</p>
<img src="http://feeds.feedburner.com/~r/accessexperts/feedburner/~4/F-NNGS2sxSE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://accessexperts.net/blog/2012/03/13/why-using-unbound-forms-are-a-bad-idea/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://accessexperts.net/blog/2012/03/13/why-using-unbound-forms-are-a-bad-idea/</feedburner:origLink></item>
		<item>
		<title>Checking if files are locked using VBA</title>
		<link>http://feedproxy.google.com/~r/accessexperts/feedburner/~3/v_7VrC_OOWg/</link>
		<comments>http://accessexperts.net/blog/2012/03/06/checking-if-files-are-locked/#comments</comments>
		<pubDate>Tue, 06 Mar 2012 07:11:57 +0000</pubDate>
		<dc:creator>Ben Clothier</dc:creator>
				<category><![CDATA[Access Help]]></category>
		<category><![CDATA[Outlook VBA]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://accessexperts.net/blog/?p=1329</guid>
		<description><![CDATA[In one of our client&#8217;s applications, we built an email template that sometimes may attach files to be sent out. Our client wanted a way to preview the attachment before they actually send the email. This created a dilemma &#8211; if they can preview and potentially edit the files, we certainly don&#8217;t want to continue [...]]]></description>
			<content:encoded><![CDATA[<p>In one of our client&#8217;s applications, we built an email template that sometimes may attach files to be sent out. Our client wanted a way to preview the attachment before they actually send the email. This created a dilemma &#8211; if they can preview and potentially edit the files, we certainly don&#8217;t want to continue and try to attach open files to an email, therefore creating a problem. So we needed a way to check whether files may be already open, alert the user to close the file, verify it&#8217;s closed then send the emails.</p>
<p><strong>Get Exclusivity</strong></p>
<p>Due to multitasking nature of Windows, there is no simple universal function to ask if a file, whatever type of file it may be, is open or not. However, we can at least approximate this functionality by attempting to open the file exclusively in our code and if we succeed, be reasonably sure that we are good to proceed onwards.</p>
<p><strong>Introducing IsFileLocked() Function</strong></p>
<p>When we open a text file with Notepad, Notepad does not place any locks on the file even when we dirty the file. In this situation, it does no harm to copy or read the file while it&#8217;s open by Notepad. Thus IsFileLocked() will return true for any .txt files opened by Notepad and in this situation, it&#8217;s generally OK. Of course, one shouldn&#8217;t try to write to the said file but that&#8217;s not what we are doing here. On the other hand, Word and Excel will place locks on their documents. Therefore trying to copy or read the file may be undesirable and threat it&#8217;s integrity. In this situation, our attempt to acquire an exclusive lock will fail, allowing us to alert the user to close the file themselves before proceeding further or cancel out.</p>
<p>The only significant caveat is that this procedure is not appropriate for checking whether a file is locked by other processes such as running background tasks. The locks can be acquired and released in milliseconds so calling the function is inherently <a href="http://en.wikipedia.org/wiki/Race_condition#Computing">racy</a>. For purposes of checking whether <em>users</em> has a file open, this should be sufficient.</p>
<pre style="font-style: normal;">Public Function IsFileLocked(PathName As String) As Boolean
On Error GoTo ErrHandler
  Dim i As Integer

  If Len(Dir$(PathName)) Then
    i = FreeFile()
    Open PathName For Random Access Read Write Lock Read Write As #i
    Lock i 'Redundant but let's be 100% sure
    Unlock i
    Close i
  Else
    Err.Raise 53
  End If

ExitProc:
  On Error GoTo 0
  Exit Function

ErrHandler:
  Select Case Err.Number
    Case 70 'Unable to acquire exclusive lock
      IsFileOpen = True
    Case Else
      MsgBox "Error " &amp; Err.Number &amp; " (" &amp; Err.Description &amp; ")"
    End Select
  Resume ExitProc
  Resume
End Function</pre>
<p>&nbsp;</p>
<p><strong>What if you have multiple files open?</strong></p>
<p>That gets us to a good start but we also have to handle the fact that there may be more than one file open, and nobody likes being alerted by multiple dialogs. Thus we need to roll up the individual checks into a single message so the users can only see one message for all locked files that they may need to close. Here&#8217;s the code:</p>
<pre style="font-style: normal;">Public Function CheckForLockedFiles( _
  Files() As String _
) As Boolean
On Error GoTo ErrHandler
  Dim i As Long
  Dim lngLocks As Long
  Dim strFiles() As String
  Dim strMessage As String

  Do
    lngLocks = 0
    For i = 0 To UBound(Files)
      If IsFileOpen(Files(i)) Then
        ReDim Preserve strFiles(lngLocks)
        strFiles(lngLocks) = Files(i)
        lngLocks = lngLocks + 1
      End If
    Next
    If lngLocks Then
      strMessage = "The following files are in use. " &amp; _
                   "Please close the application that may have it open." _
                   &amp; vbNewLine &amp; vbNewLine
      For i = 0 To UBound(strFiles)
        strMessage = strMessage &amp; strFiles(i) &amp; vbNewLine
      Next
      If vbCancel = MsgBox(strMessage, vbRetryCancel, "Files in use") Then
        CheckForLockedFiles = False
        Exit Do
      End If
    End If
  Loop Until lngLocks = 0
  If lngLocks = 0 Then
    CheckForLockedFiles = True
  End If

ExitProc:
  On Error GoTo 0
  Exit Function

ErrHandler:
  Select Case Err.Number
    Case 53 'File doesn't exist, ignore
      Resume Next
    Case Else
      MsgBox "Error " &amp; Err.Number &amp; " (" &amp; Err.Description &amp; ")"
  End Select
  Resume ExitProc
  Resume
End Function</pre>
<img src="http://feeds.feedburner.com/~r/accessexperts/feedburner/~4/v_7VrC_OOWg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://accessexperts.net/blog/2012/03/06/checking-if-files-are-locked/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://accessexperts.net/blog/2012/03/06/checking-if-files-are-locked/</feedburner:origLink></item>
	</channel>
</rss>

