tags:

views:

79

answers:

6

Let's say TableA has a field called, FieldA. FieldA consists of a list of values with comma being the delimiter (i.e. 1,2,3,4). #MyVar# contains the value (a single value, NOT a list) I want to search for. Other than doing the followings,

SELECT *
  FROM TableA
 WHERE FieldA LIKE '%,#MyVar#,%'
    OR FieldA LIKE '#MyVar#,%'
    OR FieldA LIKE '%,#MyVar#'

Is there a SQL command/reserved word to perform the equivalent of the SQL statement above?

A: 

You can use IN to check an list:

SELECT * FROM TableA WHERE FieldA IN '%,#MyVar#,%'
Dustin Laine
Yes, but 'A,B,C' is NOT in ('A') (and you need parens around the list).
Larry Lustig
I want the exact opposite of this. FieldA is a list; #MyVar# is a value and NOT a list.
Monte Chan
+6  A: 

You have a badly designed, denormalized database. If at all possible, fix the design.

If that's not possible then consider the nature of the MyVar values. If they cannot possibly nest inside each other (for instance, they're all guaranteed to be the same number of characters) you can get away with a single like. If not, your solution is about as good as you'll get.

Larry Lustig
The design was already done. It would be a MAJOR rework to change the database.Thank you very much for your answer.
Monte Chan
+1  A: 

There isn't any need to include the several ORs or commas. This query should do what you need.

SELECT * 
FROM TableA 
WHERE FieldA LIKE '%#MyVar#%'

If the variable appears anywhere in the field, the row will be returned. You don't have to try to compare it to each of your "list" items in each field.

You're kind of abusing database design by including a list of values in a single field. There isn't any built-in SQL function that deals with this kind of data, that I know of.

Jim
Jim: Consider the case of 'AB,BC,D,F' and MyVar contains simply 'A'. Your query would falsely match.
Larry Lustig
The database structure was designed by somebody else. It would be a MAJOR rework to correct that. In your case though, let's say FieldA has '10,11,12,13,14' and I am looking for 1. It would actually return the record while only '1,2,3,4,5' should return.
Monte Chan
It just depends on your data, then. In certain cases, my query would return too many results.
Jim
+2  A: 

As per Pounding A Nail: Old Shoe or Glass Bottle?:

This is quite possibly the worst way you could store this data in a database. No, seriously. They had better ways of doing this over thirty years ago. You have created a horrible problem that is only starting to rear its ugly head. It will only continue to get horribly worse, costing your company more and more money to maintain.

The answer is to make a new table, with a one-to-many relationship between the main ID and the different values. Then it's a much simpler query:

SELECT MainID
FROM NewTable
WHERE FieldA = @Value

This is a much easier solution to code against, not to mention understand. And it will help significantly when you have to join this table to others.

EDIT: From your responses, I understand that doing this would be a serious amount of work. However, you're already running into the issues that are arising from the current setup. Doing this will take time up front, but it will make future development significantly faster in the long run.

Adam V
The OP did not state whether they have control of the database structure or not.
Larry Lustig
I understand that. But as it stands, doing this is more work upfront, but significant time savings in the long run. (Not to mention it's easy to get this query *wrong*, so it's entirely possible this may be the only way to get it completely right anyway.)
Adam V
I don't have control over the db structure.
Monte Chan
Then there are three solutions I see: 1) Come up with another way to do the search in the DB. Judging by the answers here, coming up with a better solution is difficult (at best). 2) Read all the data into the backend and use functions like "Array.Contains(MyVal)" to determine the existence of your value. Script is easier, more work on the backend. 3) Lobby for the necessary DB changes. Don't know where you work, but it seems like it'd be pretty easy to raise this issue as an example of the problems you're likely to see. Good luck.
Adam V
As an aside, please don't think I'm blaming you for the DB issues. I recognize that these things happen, where we're forced to work with a design that has flaws.
Adam V
A: 

No, in a word. In a normalized database you would usually split these list items into a separate table, but there are times where is this is either not possible (user has no ability to alter the database structure) or undesired (budget limitations).

you can either

  • do something like durilai suggests (not performant for large amounts of data, but probably the easiest to implement)

  • use a trigger to split the entries in your on arrival (i.e. on INSERT) into a subtable (SubTableA) and then do

:-

select * from TableA a where exists (select 1 from SubTableA s on s.a_id = a.id
and list_element like '%#MyVar#%')
davek
A: 

Put your delimiters on the left side of the like comparison too and then make sure you include your delimiters on the right side. Like this:

SELECT *
  FROM TableA
 WHERE ',' + FieldA + ',' LIKE '%,#MyVar#,%'
G Mastros