Press "Enter" to skip to content

Category: Syntax

Surrogate Keys in Fabric Data Warehouse

Louis Davidson does some more digging:

Creating the simplest of tables, the first thing I start thinking about is making sure that the data is going to be protected from the user. Users (including myself on my own projects when I have my user hat on) don’t notice when they start inserting poor quality data sometimes. Oops, I hit F5 twice, I wonder if that will affect my data? Without proper constraints, it probably will.

In this second entry, I want to cover a few things about handling surrogate values that will help you avoid some of the (in retrospect) kind of dumb expectations that I had. Fabric Data Warehouse T-SQL feels so much like SQL Server Relational T-SQL that some stuff like choosing a surrogate key makes me think I am missing something.

One of the things Louis mentions is how the values get inserted and how it looks like they’re in different ranges. This makes sense, as each distributed node likely has its own range of identity values, similar to the way merge replication would work with identity keys to prevent overlap.

Leave a Comment

Replacing REPLACE()s with TRANSLATE() in SQL Server

Greg Low makes use of an uncommon function:

If your T-SQL is buried under layers of nested REPLACE() calls just to swap out a few characters, there’s a simpler way. SQL Server’s TRANSLATE() function — introduced in 2017 but still rarely used — lets you replace multiple characters in a single string with one function call instead of stacking several REPLACE() functions inside each other.

This guide covers how TRANSLATE() works, how it compares to REPLACE(), and where it falls short compared to other SQL dialects like PostgreSQL and Oracle.

One important thing to remember with TRANSLATE() is that it’s a character-for-character replacement. In other words, if you TRANSLATE('ABCDEFG', 'x'), it will replace every instance of each of those characters with the letter “x.” It doesn’t replace a substring.

Leave a Comment

Taking Advantage of Newer Date Functions in SQL Server

Andy Brownsword gets beyond SQL Server 2000:

Date handling in SQL Server tends to accumulate tried and trusted combinations of DATEPART()DATEADD(), and DATEDIFF() – with nested variations. The challenge with these isn’t raw performance, but more with conveying intent and readability.

So let’s look at some simpler patterns to try and avoid some of these and be clearer with what we’re trying to achieve.

Click through for some functions that have been around since 2012, and others that just became available in 2022.

Leave a Comment

The Value of TRY_PARSE()

Steve Jones answers a question:


Someone asked why I would use TRY_PARSE after I posted a question at SQL Server Central: Getting the Average. Isn’t is slower?

A fair question. This quick post looks at why.

I’d use TRY_CAST() or TRY_CONVERT() in this particular scenario. The main reason I’d use TRY_PARSE() would be if you need .NET-specific parsing functionality, such as parsing dates by a specific locale. The reason is that PARSE() and TRY_PARSE() are an order of magnitude slower than their CAST() and CONVERT() cousins.

That said, Steve’s example reminds me of a PolyBase demo I used to do, in which I took a CSV of North Carolina populations by county and read in the information. In that particular dataset, they would use the letter “A” to describe either “Not enough people to show an answer without potentially violating PII” or “We don’t know what the answer is.” So even though it was clearly a numeric attribute in “Population,” the output process overloaded the definition of that attribute and the only way you would know is to happen to see the three rows in ~1500 that happened to have an A in the column value.

Leave a Comment

Choosing between Temporary Data Options

Chad Callihan builds a list:

Jeff provides half a dozen prompts to get the ball rolling, and I thought I’d discuss my thoughts on “the whole family. #temp vs. table variables vs. CTEs vs. indexed views. When does each one earn a spot?”

Indexed views are an odd man out. As far as table variables go, there are two places where I really like to use them. First is for logging, because they survive a transaction rollback, so even if you roll back your transaction in a catch block, you can still insert that vital error information into a logging table. Second is for table-valued parameters in stored procedures, though that does require a user-defined table type versus an ad hoc table variable.

Leave a Comment

Simplifying Code via Computed Columns

Andy Brownsword moves an expression:

Computed columns allow us to bake logic into our schema. I find particular use for these when reviewing or optimising established solutions where you spot the quirky ways the data is being used.

Here I want to demonstrate 3 symptoms and show how different implementations of computed columns solve them.

Click through for the technique. It certainly won’t solve every performance problem relating to non-SARGable functions, but it does work pretty well on specific classes where you have limited control over the code.

Leave a Comment

Challenges with DATE_BUCKET()

Erik Darling has a new video:

But what’s also strange here, too, is that SQL Server estimates one row very reliably for a date bucket. So, you know, you might be careful about that as well, especially if you’re returning far more than one row. You might be unhappy with the one row estimate.

It might bring you back to the bad old days of table variables and off histogram values, stuff like that. But, yeah, anyway, I had a point with all that. Let’s do this.

Click through to learn Erik’s point.

Comments closed

Wrong Outer Joins

Aaron Bertand only likes the right kind, by which I mean the left kind:

The headline is probably unfair and is not meant to imply that a RIGHT OUTER JOIN is wrong. But when I see a RIGHT OUTER JOIN, my first thought is, “the rest of this review will probably be harder than it needs to be.” I find that it makes queries harder to read, because most people naturally read queries left-to-right. With a left join, the “important” table is on the left, and the query is saying, “give me everything from this table, and maybe something from this related table.” With a right join, I have to mentally flip things around to understand which table is important.

Aaron is absolutely right about left-handed scissors. I extend this as well to can openers and a half-dozen other tools that fit very well in the right hand but are quite awkward for southpaws. And don’t get me started on writing.

Aaron is kinder toward RIGHT OUTER JOIN than I am. I’m not convinced there’s ever a reason that we should use RIGHT OUTER JOIN. LEFT OUTER JOIN is much easier for humans to interpret, and (save for very specific scenarios) we should optimize code for human interpretability over pretty much anything else. And yes, that includes (again, save for very specific scenarios) performance.

Comments closed

Copy-Pasta’d Temp Tables and More Fun

Andy Levy shares some thoughts:

I’ve spent a lot of time over the past 8 or years trying to “right the ship.” Systems that have been built and evolved over 10-15 years and the cracks are starting to show. Yes, there’s always the hot spot code that desperately needs attention, the stored procedure that runs in 6 hours but could be 20 minutes with the right adjustments. But I’m looking at a macro level today, more “operational” than “surgical.” When I see __ in a chunk of code, it’s a signal to me that there are overarching problems in how the whole system I’m working on was built and it’s going to take me a good, long while to undo that to deliver constant performance as data grows or improve maintainability.

Andy’s main topic is pre-populated temp tables serving as lookup tables in queries. Though if Andy wants eldrich temp table horrors, I raise him global temp tables (##table) created from a separate session and a SQL Agent job that runs every minute to create it, with people ignoring the failures because “That’s how it’s supposed to work.”

I’ve never seen that in practice, but now I kind of want to do it.

Bonus comment: leading semi-colons for CTEs. I rarely do that, but when I do, it’s because a semi-colon on the same line as a batch separator doesn’t count. In other words,

GO;

WITH records as (...)

returns an error. There might be some workable variant, admittedly, but in those cases, I do put the semi-colon in front of the CTE. The rest of the time, when I know there isn’t a batch separator right before the common table expression, I of course don’t. Commas and semi-colons belong at the end, not the beginning.

Comments closed

Bad Query Pattern: Wildcards on Both Ends

Chad Callihan covers this month’s T-SQL Tuesday topic:

A lot of SQL queries or code can still “work,” but that doesn’t mean it’s good, especially with so much vibe coding and the like going on these days. When I think of signs I’ve noticed when seeing a query for the first time, one thing that will get my attention (besides seeing NOLOCK throughout) is when a string is being searched for surrounded by percent signs.

I’ve had instances of working with someone that was looking for certain error logs. We may know the log record starts with “Error 123” and could search a field for “Error 123%” in our query.

Click through for the consequences of a search on “Error 123%” versus “%Error 123%”. Sometimes it’s simply necessary to do the full search, but if you find yourself doing that frequently, it’s a sign that you could design the table better.

Comments closed