T-SQL Tuesday #119 Changing my mind

Thank you Alex Yates for this month’s topic!

Something I’ve changed my mind on recently is working on contracting projects instead of performing work directly for a company. Very recently I had a (good) problem of choosing between a few different job roles and companies. The choice was not easy and two years ago I told myself I’d never do contract work again. I’m not talking about starting an S-Corp or an LLC but working for a company that contracts your work out to another company. I have also in the past changed my mind about how I update rows in critical systems and whether you can ROLLBACK a TRUNCATE statement (in SQL Server).

Contracting can be very lucrative but there are issues with contracting that aren’t immediately evident. In the last 10 years, I will have worked for 13 different companies across 5 jobs. For each job I work, I have an average of 2.6 employers. This is due to company buyouts, sub-contracting to contracting, and organization splits / reorganization. For the most part, this just means the logo on the paycheck changes. I’ve been very fortunate to have employers who at the very least matched the overall compensation between employers as they change.

Now, here are the things that people may not tell you about contracting:

  • PTO / Holidays. Everyone has their own policy and your PTO counter resets when you change employers. Some companies offer a higher salary in lieu of PTO or holiday pay.
  • Deductibles reset / insurance changes. It seems like I’m switching doctors for everything every 3-6 months because my coverage keeps fluctuating. It can be challenging to build a steady history at one location.
  • HSA / 401K / other accounts. Eventually, the same systems/companies re-use systems for some of the reimbursement (like ADP). Between each employer though, it seems to change frequently. This means you’ll have to aggregate accounts as your employer changes over time.
  • So many tax forms. Every year doing taxes seems like an entire feat. This only really changes when your employer does.
  • Your employer can change at any moment. If the customer does not like the company they are contracting for, they will bring in a new contractor. Maybe the contract is up for bid and someone new wins it. There is an inherent risk with this, but 95% of the time you are fine unless you or your company really messed up with the customer. Most new contracting companies want to buy up the old contractors so there is less business knowledge lost. Some companies will offer you to keep working with them on a new customer if your contract is lost.

That may seem like a lot of negatives, and it really is. Something I’ve learned though is that many of these can be true for working for a company instead of just contracted to a company. The PTO / Holiday is less likely to change on you as it is in your contract when you’re hired, it may affect new hires though. Companies can change insurance and you do see premiums or features fluctuate. (For better or for worse.) The same deal can also go for 401ks, I’ve seen those changes before too. And finally, you can still change employers. What if your company closes or goes under? What if they are bought out?

Typically working for a company means more stability than doing contract work, but it always depends on the company. That’s why I’ve changed my mind on continuing to do contract work instead of giving that life up. If you can find a company that contracts you out but will take care of you when things get rough, that’s when I’d be willing to do contract work again. At the end of the day, a company or a contracting company is not going to differ in loyalty. A company is there to make money and work towards its mission through its vision.

All these thoughts in mind, I decided to stay in contracting but to continue to search for employers who have a reputation for taking care of their workers. I also want their reputation to be geared towards continual improvement and high-quality work so I can push myself to be the best I can be.

On the more technical side, there are two things I’ve changed my mind on.

Back in 2011, I was convinced that when performing data manipulation language (DML) tasks, I should wrap my transaction in BEGIN TRANSACTION and ROLLBACK TRANSACTION with a SELECT statement towards the end to verify the results. I learned this lesson with a missed WHERE clause. I don’t really need to dive deeper into that story, you already know where it goes. Obviously, when you wrap your transaction like this, you need to be aware of the implications. This means you are still performing the transaction, but you are rolling it back. So, if you are updating the entire table, you are still going to be placing locking and blocking resources on this table.

Here’s an example of what I’m talking about. Let’s create a temp table and then fill in some rows to work with. (Note: When using a temp table with a single hash mark, this table will be deallocated at the end of the transaction. When using a global temp table with two hash marks, it will be deallocated when all transactions using the global temp table complete. I’m using temp tables instead of physical tables so you can follow along with less cleanup later.)

IF OBJECT_ID('tempdb..#Test') IS NOT NULL DROP TABLE #Test;
GO
CREATE TABLE #Test ( FakeField VARCHAR(255) );
GO
INSERT INTO #Test 
VALUES ('TestOne'),('TestTwo'),('TestThree');
 
SELECT * FROM #Test;

Now I’ll demonstrate the rollback and viewing your results.

IF OBJECT_ID('tempdb..##Test') IS NOT NULL DROP TABLE ##Test;
GO
CREATE TABLE ##Test ( FakeField VARCHAR(255) );
GO
INSERT INTO ##Test 
VALUES ('TestOne'),('TestTwo'),('TestThree');
 
BEGIN TRANSACTION
 
UPDATE ##Test 
SET FakeField = 'Woopsies!'
 
SELECT * FROM ##Test;
 
ROLLBACK TRANSACTION

I can see that I updated all my rows when I meant to update only one because I missed my WHERE clause. I can go back and correct my query now.

IF OBJECT_ID('tempdb..##Test') IS NOT NULL DROP TABLE ##Test;
GO
CREATE TABLE ##Test ( FakeField VARCHAR(255) );
GO
INSERT INTO ##Test 
VALUES ('TestOne'),('TestTwo'),('TestThree');
 
BEGIN TRANSACTION
 
UPDATE ##Test 
SET FakeField = 'Woopsies!'
WHERE FakeField = 'TestOne';
 
SELECT * FROM ##Test;
 
ROLLBACK TRANSACTION

Success! I’ll change my statement to COMMIT to keep the results now.

IF OBJECT_ID('tempdb..##Test') IS NOT NULL DROP TABLE ##Test;
GO
CREATE TABLE ##Test ( FakeField VARCHAR(255) );
GO
INSERT INTO ##Test 
VALUES ('TestOne'),('TestTwo'),('TestThree');
 
BEGIN TRANSACTION
 
UPDATE ##Test 
SET FakeField = 'Woopsies!'
WHERE FakeField = 'TestOne'
 
SELECT * FROM ##Test;
 
COMMIT TRANSACTION

Now what about locking that table? Didn’t I say earlier this can have repercussions? I’ll demonstrate what’s happening to users while this is occurring. To do so, I’m going to leave the transaction open without a ROLLBACK or COMMIT to show the behavior users would feel for a long transaction.

IF OBJECT_ID('tempdb..##Test') IS NOT NULL DROP TABLE ##Test;
GO
CREATE TABLE ##Test ( FakeField VARCHAR(255) );
GO
INSERT INTO ##Test 
VALUES ('TestOne'),('TestTwo'),('TestThree');
 
BEGIN TRANSACTION
 
UPDATE ##Test 
SET FakeField = 'Woopsies!'
WHERE FakeField = 'TestOne';

While this executes in one tab, I’ll show you what another tab reflects as another user trying to access that table.

SELECT * FROM ##Test;

Ack! Spinning for over a minute!

What about users who are using READ UNCOMMITTED ISOLATION LEVELS?

SELECT * FROM ##Test WITH (NOLOCK);

What if the first user decides to rollback?

Meanwhile… back in the other tab.

SELECT * FROM ##Test;

It’s different from the results in the other tab! That means your users were reading dirty data if they could even read the table at all. You need to be careful using this method, but it’s a great way to make sure you aren’t updating the wrong information.

One other technical topic I’ve changed my mind about a long time ago, is that you can ROLLBACK a TRUNCATE statement. I’m not going to dive deep into that right now as I’ve written about this previously.

Leave a Reply

Your email address will not be published. Required fields are marked *