3

I want to create a bible verse table that has one field representing a range of bible verses. Currently I represent this range as pair of values (VerseBegId and VerseEndId). I want something like the Sql Server spatial data type

Instead of

CREATE TABLE BibleVerse AS TABLE
(
    VerseBegId int NOT NULL,
    VerseEndId int NOT NULL
)

I want

CREATE TABLE BibleVerse AS TABLE
(
  VerseRange ??? NOT NULL
)
  • 3
    What is the driving force for wanting to store it this way? – LowlyDBA Sep 7 '18 at 16:29
8

Besides SQLCLR, you could also store both values in either XML or JSON (if you are using SQL Server 2016 or newer) and retrieve them as discrete values. Similarly you could simply convert them to VARCHAR and place them, separated by a comma, in a single column (I don't recommend this at all, but it is functionally similar to the other approaches I just mentioned). The SQLCLR approach makes it easy to get the discrete values back out, and in their native datatypes, but you could just as easily write a few helper UDFs to do the same with those values shoved into XML or JSON.

In all of these cases, while you could accomplish the goal of storing two values in a single column, I don't see what you gain by doing this given that each approach has some amount of overhead yet the usage doesn't seem to justify it. The main reason for creating your own type isn't to merely associated related data points, but to have the ability to act upon them. The internal CLR types not only store the discrete data points, but also offer quite a few methods to do interesting things with those data points. I am not sure what you can do operationally with just beginning and ending numbers that don't have commonly used algorithms for making use of them. It seems that you will be doing more work to get the values back out (and most likely decrease performance while doing so) than you will be gaining by putting them in such a structure.

Unless you can clearly see a guaranteed benefit from doing this, I suggest you keep them as discrete data points. And if my memory serves me correctly, you should be able to get away with using TINYINT, assuming no verse # goes above 255 (and they certainly wouldn't be negative or NULL). Looking here ( New Testament Statistics ) and here ( Old Testament Statistics - New American Bible ) it seems that the highest verse number is 80 for the New Testament (Luke chapter 1), and 176 for the Hebrew Bible — "Old Testament" in Christian terminology — (Pslam 119).

  • All JSON will do is validate text. I'm unsure what that provides here. No text, and no indexing abilities. – Evan Carroll Sep 15 '18 at 22:40
  • 3
    @EvanCarroll I am not recommending to use JSON, nor even XML. I am merely pointing out that these, along with SQLCLR, are options for storing discrete data points in a single value. But, more importantly, none of these methods are advantageous here given the intended use of the range. They each have additional overhead (both in terms of size and complexity in working with) compared to storing two TINYINT values. Given that bible verses are informational, not operational, there is no need to compare them, or find intersections, overlaps, etc. And likely no need to even index them. – Solomon Rutzky Sep 17 '18 at 17:16
6

You would need to use a CLR user defined datatype for this.

It would be very similar to the example code for Point here.

But I don't recommend it. It builds in a requirement for CLR that makes your database less portable (you won't be able to migrate it to Azure SQL database).

Updating the datatype when in use is quite cumbersome too and I can't think of any advantages of doing this compared to just having two int columns.

-2

Consider checking out PostgreSQL where this is actually pretty simple because it has range types,

CREATE TABLE BibleVerse (
  VerseRange int4range NOT NULL
);

CREATE INDEX ON BibleVerse USING GIST (verserange);

INSERT INTO BibleVerse VALUES (int4range(10,20)), (int4range(20,30));

Finding intersections is also very easy,

SELECT * FROM BibleVerse WHERE verserange && int4range(5,15);
 verserange 
------------
 [10,20)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.