Enumerated types in SQL Server 2008? - sql-server

Is there some kind of mechanism in SQL Server to allow Enumerated type like functionality?
For example, if I have a column Called "UpdateStatus" it usually gets setup with single letter values like so:
D
X
U
I
This could equate to a lot of things. That leads to confusion. The alternative is to have it be a string column like this:
Downloaded
Deleted
Updated
Initialized
But that has its own problems. Eventually someone is going to write something like this: where UpdateStatus = 'Initalized' (spelled wrong). Plus I hear that keying off of strings is not all that performant.
So, is there any kind of enumerated type for SQL Server that can help out with this? Basically I am looking for compile time checking that a value being compared (ie "Initialized") is part of a list of values.
I am using SQL Server 2008.

Why not have lookup table that contains the code and description. Creating a foreign key to this lookup table will result in only valid codes being used.

Besides lookup tables (FKs), in simple cases, you can use check constraints:
CREATE TABLE my_table (
UpdateStatus VARCHAR2(11)
CHECK( UpdateStatus IN ('Downloaded', 'Deleted', 'Updated', 'Initialized'))
)

The only way that I've seen this done is by using a UDF to evaluate whether or not the enum's string representation is valid. It's slow, it's painful, and usually not worth it, but at least you have a way to fail loudly instead of silently.
And remember, you can't RAISERROR in a UDF so you have to cause an intentially cause an error, and log separately.
Ultimately, at the moment, the 'perfect' solution to the problem would be to approach from the other side -- you can achieve this mentality with a code-first ORMs, which would allow you to use native enums in your code, and the corresponding SQL lookups will be created properly in migration.
Here's to hoping we get enums soon, we're feeling a little left out.

Related

How to avoid SQL Server error on ORDER BY with duplicate columns

Although this question references PHP, it is not actually PHP-specific, so I have not flagged it as such.
We have a PHP framework which supports multiple DB back-ends.
There is a generic function in our data object class, which allows you to get records from the underlying table, with a specified criteria and sort order.
It looks something like this:
function GetAll($Criteria, $OrderBy = "") {
...
// Add primary key (column 1) to end of order by list,
// so that returned order is predictable.
if ($OrderBy != "") {
$OrderBy .= ", ";
}
$OrderBy .= "1";
...
// Build and run query, returning the result as an array.
}
If you specify an $OrderBy argument of StaffID on a Staff object, the resulting SQL looks something like the following:
SELECT * FROM adminStaff ORDER BY StaffID, 1;
This works fine on a MySQL back-end, and from my searching of the web it should also be fine on most other DB back-ends. However, when using SQL Server, we get the following error message:
A column has been specified more than once in the order by list.
Columns in the order by list must be unique.
This arises because SQL Server disallows the same column appearing multiple times in the ORDER BY clause. In this case StaffID is column 1 and therefore we have multiple instances of the same column.
Is there a way to disable this check in SQL Server? MySQL provides a lot of options to enable/disable strictness checks and incompatible features - does SQL Server provide anything of that nature that would allow the above query to run without errors?
If not, do you have any suggestions for how we could resolve this in our data-object layer? Bear in mind we need to maintain compatibility with existing projects which expect this behaviour, so it is not sufficient to only include the first column when $OrderBy is blank.
The situation is also slightly complicated in the fact that the field list is customisable elsewhere in the data object configuration, so we can't rely on * being used as the field list - it could contain pretty much anything that is valid in a normal SQL field list. However, if that is asking too much, a solution to the simpler case (as outlined above) would be a good start!
In SQL Server you are able to sort either by column name or by ordinal position of the column order in the SELECT list.
In your case the column StaffID became the ordinal position 1. Hence SQL Server cannot sort the same result set based on the same column twice.
If you remove the 1 from your query, the problem will be solved.
Avoid using the ordinal position of the column for sorting.
The basic question - is it possible to suppress this SQL Server restriction on ORDER BY column duplication - was answered by Venu: No it is not.
There are various suggestions (mostly from me) about how you could possibly code around this limitation in a generic manner. For any future readers, those answers are probably the most helpful if you are adapting an existing system. (If you are starting from scratch, just try and avoid this situation altogether.)
However, the actual solution that I came to was to add versioning to our internal API for our DBAL. The API version is now 2 but you can call setApiVersion(1) to instruct the back-end to use the old version of the API instead.
v2 is identical to v1* except it no longer automatically adds column 1 to the ORDER BY unless it is completely blank. Therefore, the SQL Server issue is resolved for new (v2) projects, whilst existing projects can be set to use the v1 API and therefore continue to work correctly (but without SQL server compatibility).
(* Actually, I've taken this opportunity to make some other breaking changes in v2, but that is not relevant to this answer.)
I've come up with a couple of potential solutions at the framework level. All of them have performance implications which would need to be profiled, and in practice that may rule some or all of them out. However, in theory at least, these are ways that a generic solution could be implemented.
Omit the ORDER BY altogether, and do the sorting in code. Would involve parsing the provided ORDER BY string. Would be problematic if ORDER BY contained expressions, but I can't remember ever seeing that in our projects, so can probably be ignored. Probably the slowest solution.
Perform the query without the ORDER BY, limiting the results set to a single row. Use resulting column list to work out whether column 1 is already in the ORDER BY clause, and therefore whether to add it. Then run the full query. Would require parsing the provided ORDER BY string. Query caching may mean this won't add as much overhead as it appears.
Parse the field list to get the first column name and see if this appears in the ORDER BY clause. If field list contains * or table.* would require a schema lookup. May be too difficult if we need to deal with table aliases and wildcards in combination.
Parse ORDER BY string and see if it contains any primary key. If so it is already uniquely ordered and doesn't require the addition of an extra field. Would require a schema look-up.
Use a sub-select to give us a new instance of the column that we can sort on instead. Not sure whether SQL Server would still complain that this is the 'same' column, though.
Could you just append '--' to your OrderBy parameter when working with SQL Server and just explicitly define the Order By fields where necessary?

SQL Server - Simple multiple choice field definition

I am new to SQL Server, coming from a MySQL background. I am trying to migrate a MySQL table that contains several fields defined similarly to the following one:
"FavoriteColors" SET('Red','Blue','Dark Purple', 'Green') DEFAULT NULL,
Basically, they are multiple-choice questions. When entering these fields in a form, the user will be able to select one or more of them.
When looking for a SQL Server equivalent to this definition, I have seen that many people create an extra table for the different choices, and then a lookup table to connect the two previous ones. Knowing that there are several multiple-choice fields like this one, it seems a pretty complicated solution for such a simple definition. Is this really best practices, or do you recommend an alternate solution? Of course, I can use BIT fields for each of the choices, but again, it seems to me that SQL Server probably has a simpler, better organized solution for this.
Thanks a lot!
You can create user-defined type and create a rule for this data type. This enables you use this new data type everywhere in your database
Here is the code, please execute step by step
CREATE TYPE [dbo].[Color] FROM [nvarchar](40) NULL
CREATE RULE ruleColor
AS
(#phone='Red') OR
(#phone='Black')
GO
EXEC sp_bindrule 'ruleColor', 'Color'
I hope it helps,

Questions in Sybase lag and over by concept

I have table like this below in my sybase database
ID,Col1,Col2
1,100,300
2,300, 400
3,400,500
4,900,1000.
I want result like this below only in sybase.
1,100,500 --- cross interrow checking the values
2,900,1000.
SInce you did not specify which database you're using, I'm assuming your using Sybase ASE (rather than Sybase IQ or Sybase SQL Anywhere, which do support lag/lead etc.)
Also it's not quite clear what you want since you have not defined how the relation between the various rows and columns should be interpreted. But I'm guessing you're essentially hinting at a dependency graph between Col2->Col1.
In ASE, you'll need to write this as a multi-step, loop-based algorithm whereby you determine the dependency graph. Since you don't know how many levels deep this will run, you need a loop rather than a self-join. You need to keep track of the result in a temporary table.
Can't go further here... but that's the sort of approach you'll need.

Referencing a Schema's table batch/perl

I just came across this when looking into someone else code.
Say there is this schema called Books that has a table call Genres...whenever this schema and table is being used on a script, such as batch/perl it was originally Books..Genres
question is, should it stay like this or changed to Books.Genres? and what is the difference?
First of all, I rarely work outside my default schema and thus rarely ever list the schema name in my SQL statements. Having said that, there are rare occasions when I do need to access more than one schema and only a single dot is used to separate the schema name from the table name. I checked both DB2 and Oracle: neither even allow a double dot. So, unless they are manipulating the SQL in some manner (e.g. maybe the code is processed in a template), SQL statements with a double dot should not work.
MySQL doesn't allow a double dot as separator either; so unless they're preprocessing the SQL in some way as kjpires suggested, this is likely an error. Does the code work?

Define a String constant in SQL Server?

Is it possible in SQL Server to define a String constant? I am rewriting some queries to use stored procedures and each has the same long string as part of an IN statement [a], [b], [c] etc.
It isn't expected to change, but could at some point in future. It is also a very long string (a few hundred characters) so if there is a way to define a global constant for this that would be much easier to work with.
If this is possible I would also be interested to know if it works in this scenario. I had tried to pass this String as a parameter, so I could control it from a single point within my application but the Stored Procedure didn't like it.
You can create a table with a single column and row and disallow writes on it.
Use that as you global string constant (or additional constants, if you wish).
You are asking for one thing (a string constant in MS SQL), but appear to maybe need something else. The reason I say this is because you have given a few hints at your ultimate objective, which appears to be using the same IN clause in multiple stored procedures.
The biggest clue is in the last sentence:
I had tried to pass this String as a
parameter, so I could control it from
a single point within my application
but the Stored Procedure didn't like
it.
Without details of your SQL scripts, I am going to attempt to use some psychic debugging techniques to see if I can get you to what I believe is your actual goal, and not necessarily your stated goal.
Given your Stored Procedure "didn't like that" when you tried to pass in a string as a parameter, I am guessing the composition of the string was simply a delimited list of values, something like "10293, 105968, 501940" or "Juice, Milk, Donuts" (pay no attention to the actual list values - the important part is the delimited list itself). And your SQL may have looked something like this (again, ignore the specific names and focus on the general concept):
SELECT Column1, Column2, Column3
FROM UnknownTable
WHERE Column1 IN (#parameterString);
If this approximately describes the path you tried to take, then you will need to reconsider your approach. Using a regular T-SQL statement, you will not be able to pass a string of parameter values to an IN clause - it just doesn't know what to do with them.
There are alternatives, however:
Dynamic SQL - you can build up the
whole SQL statement, parameters and
all, then execute that in the SQL
database. This probably is not what
you are trying to achieve, since you
are moving script to stored
procedures. But it is listed here
for completeness.
Table of values -
you can create a single-column table
that holds the specific values you
are interested in. Then your Stored
Procedure can simply use the column
from this table for the IN clause).
This way, there is no Dynamic SQL
required. Since you indicate that
the values are not likely to change,
you may just need to populate the
table once, and use it wherever
appropriate.
String Parsing to
derive the list of values - You can
pass the list of values as a string,
then implement code to parse the
list into a table structure on the
fly. An alternative form of this
technique is to pass an XML
structure containing the values, and
use MS SQL Server's XML
functionality to derive the table.
Define a table-value function that
returns the values to use - I have
not tried this one, so I may be
missing something, but you should be
able to define the values in a
table-value function (possibly using
a bunch of UNION statements or
something), and call that function
in the IN clause. Again - this is an
untested suggestion and would need
to be worked through to determine
it's feasibility.
I hope that helps (assuming I have guessed your underlying quandary).
For future reference, it would be extremely helpful if you could include SQL script showing
your table structure and stored procedure logic so we can see what you have actually attempted. This will considerably improve the effectiveness of the answers you receive. Thanks.
P.S. The link for String Parsing actually includes a large variety of techniques for passing arrays (i.e. lists) of information to Stored Procedures - it is a very good resource for this kind of thing.
In addition to string-constants tables as Oded suggests, I have used scalar functions to encapsulate some constants. That would be better for fewer constants, of course, but their use is simple.
Perhaps a combination - string constants table with a function that takes a key and returns the string. You could even use that for localization by having the function take a 'region' and combine that with a key to return a different string!

Resources