In my table for specific column values are stored in three diffrent ways as shown below. It could be either one, two or three items separated by commas (of course if more than one value). Minimum is one value, maximum 3 values separated by commas. To be clear i know it's bad approach it was done (not by me) however i have to work on this and i have to change just only this query. Example showing three ways of storing values:
MaterialAttributes (column name)
----------------------------------
1,12,32
3,1
9
I have specific sql query for searching if some value existing within field. It is universal to check all tree ways.
somevalue1
or:
somevalue1,somevalue2
or:
somevalue1,somevalue2,somevalue3
Therefore for instance if i search entire table for each row in that column to get records where somevalue2 appears this query correctly gives me correct result.
This is the query:
";WITH spacesdeleted (vater, matatt) as (SELECT vater, REPLACE(MaterialAttributes, ' ', '') MaterialAttributes FROM myTable),
matattrfiltered (vat) as (SELECT vater FROM spacesdeleted WHERE matatt = #matAttrId
OR matatt LIKE #matAttrId +',%'
OR matatt LIKE '%,'+#matAttrId
OR matatt LIKE '%,'+#matAttrId+',%' ),
dictinctVaters (disc_vats) as (SELECT distinct(vat) FROM matattrfiltered)
SELECT ID from T_Artikel WHERE Vater IN (SELECT disc_vats FROM dictinctVaters)"
Note: For security reasons if for some reasons there are spaces close to commas there will be removed (just information from other developer).
What is the question:
The problem now is that logic changed in the way there could be instead of 3 (max) - 12 to store in that column.
OR matatt LIKE #matAttrId +',%'
OR matatt LIKE #matAttrId +',%'
These are the same, should one be '%,' + #matAttrId?
Regardless, I think there's only 4 cases you need:
= #matAttrId
LIKE #matAttrId + ',%'
LIKE '%,' +#matAttrId
LIKE '%,' +#matAttrId + ',%'
Covering
single value, equals
value is start of list
value is end of list
value is in middle of list
Which is what your original query already has.
You can search with
WHERE ',' + matatt + ',' LIKE '%,' + #matAttrId + ',%'
It works like this: matatt is extended to look like this
,1,12,32,
,3,1,
,9,
Now you can always serach for an id looking like ,id, by using the search pattern %,id,%, where id is the real id.
This works for any number of values per column.
Related
I have a column which has inconsistent data. The column named ID and it can have values such as
0897546321
ABC,0876455321
ABC,XYZ,0873647773
ABC,
99756
test only
The SQL query should fetch only Ids which are of 10 digit in length, should begin with a 08 , should be not null and should not contain all characters. And for those values, which have both digits and characters such as ABC,XYZ,0873647773, it should only fetch the 0873647773 . In these kind of values, nothing is fixed, in place of ABC, XYZ , it can be anything and can be of any length.
The column Id is of varchar type.
My try: I tried the following query
select id
from table
where id is not null
and id not like '%[^0-9]%'
and id like '[08]%[0-9]'
and len(id)=10
I am still not sure how should I deal with values like ABC,XYZ,0873647773
P.S - I have no control over the database. I can't change its values.
SQL Server generally has poor support regular expressions, but in this case a judicious use of PATINDEX is viable:
SELECT SUBSTRING(id, PATINDEX('%,08[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9],%', ',' + id + ','), 10) AS number
FROM yourTable
WHERE ',' + id + ',' LIKE '%,08[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9],%';
Demo
If you normalise your data, and split the delimited data into parts, you can achieve this some what more easily:
SELECT SS.value
FROM dbo.YourTable YT
CROSS APPLY STRING_SPLIT(YT.YourColumn,',') SS
WHERE LEN(SS.value) = 10
AND SS.value NOT LIKE '%[^0-9]%';
If you're on an older version of SQL Server, you'll have to use an alternative String Splitter method (such as a XML splitter or user defined inline table-value function); there are plenty of examples on these already on Stack Overflow.
db<>fiddle
I'm using SQL Server and would like to check if todays day name is in a list of values in a single field/column.
An example of the column "start_days" contents is:
'Monday','Tuesday','Sunday'
'Thursday'
'Friday','Sunday'
'Tuesday','Sunday'
'Tuesday','Wednesday','Thursday','Friday'
The code I am trying to run on this is:
case
when datename(weekday,getdate()) in (start_days) then 1
else 0
end as today_flag
And the result is 0 for every row.
Am I doing something wrong here or is it just not possible to use a single field as a list of values in the statement?
As a starter: you should fix your data model and not store multiple values in a single column. Storing list of values in a database column basically defeats the purpopose of a relational database. Here is a related reading on that topic.
That said, here is one option using pattern matching:
case
when ',' + start_days + ',' like '%,' + datename(weekday,getdate()) + ',%' then 1
else 0
end as today_flag
If you really have single quotes around values within the list, then we need to include them in the match:
case
when ',' + start_days + ',' like '%,''' + datename(weekday,getdate()) + ''',%' then 1
else 0
end as today_flag
If the values always are weekdays, this can be simplified since there is no risk of overlapping values:
case
when start_days like '%''' + datename(weekday,getdate()) + '''%' then 1
else 0
end as today_flag
The right answer to the question is fixing your data modal. Storing multiple values like that will leads you to many issue and you're stuck on one right now.
Until that, you could use LIKE operaor to get the desired results as:
SELECT *, CASE WHEN
Value LIKE CONCAT('%', QUOTENAME(DATENAME(WEEKDAY,GETDATE()), ''''), '%')
THEN 1
ELSE 0
END
FROM
(
VALUES
('''Monday'',''Tuesday'',''Sunday'''),
('''Thursday'''),
('''Friday'',''Sunday'''),
('''Tuesday'',''Sunday'''),
('''Tuesday'',''Wednesday'',''Thursday'',''Friday''')
) T(Value)
Here is a db<>fiddle where you can see how it's working online.
So i have declared a table:
DECLARE #VTable TABLE (ColtoAdj VARCHAR(50),HeadlineDescription
VARCHAR(50),HeadlineDescriptionGroup VARCHAR(50));
INSERT INTO #VTable VALUES ('Neopla','Neoplasia','Cancer');
INSERT INTO #VTable VALUES ('Metasta','Metastases','Cancer');
INSERT INTO #VTable VALUES ('CES','CES','Cauda Equina');
INSERT INTO #VTable VALUES ('CES-I','CES-I','Cauda Equina');
which is then used in an Outter apply on the main table to find the headlinedescription and headlinedescriptiongroup.
OUTER APPLY (
SELECT TOP 1
vt.ColtoAdj,
Vt.HeadlineDescription,
Vt.HeadlineDescriptionGroup
FROM #VTable AS vt
WHERE cmd.Headline LIKE ('%' + vt.ColtoAdj + '%')
Which for most of my data it works fine as alot of the vt.ColtoAdj lookup words are unique such as have a hyphon etc. so are only pulled. The problem is the CES value. This could be anywhere in a 255 character headline. So its currently picking up things like "BraCES" and adding it incorrectly. I tried to insert 2 values for it 'CES' or 'CES' to just get the abbreviation but this still grabs words ending in it or starting. Is there anyway for this value in the table i can get it to find just the 3 letters by themselves, but also search for full words for the other ones?
It may be a case of no, simply because its a like function and with a word lookup you cant always guarantee 100% accuracy, but thought i would check.
If you are looking for word boundaries and words are bounded by a space, you can use:
WHERE ' ' + cmd.Headline + ' ' LIKE '% ' + vt.ColtoAdj + ' %'
I can only think of a per-case solution:
WHERE
(
(cmd.Headline LIKE ('%' + vt.ColtoAdj + '%') and vt.ColtoAdj<>'CES')
OR
(cmd.Headline='CES' and vt.ColtoAdj='CES')
)
I'm trying to understand if the above question is possible. I've been conceptually thinking about it, and basically what I'm looking to do is:
Specify keywords that may appear in a title. Lets use the two terms "Portfolio" and "Mike"
I'm hoping to generate a query that will allow for me to search for when Portfolio is contained within a title, or Mike. These two titles need not to be together.
For instance, if I have a title dubbed: "Portfolio A" and another title "Mike's favorite" I'd like both of these titles to be returned.
The issue I've encountered with using a LIKE statement is the following:
WHERE 1=1
and rpt_title LIKE ''%'+#report_title+'%'''
If I were to input: 'Portfolio,Mike' it would search for the occurrence of just that within a title.
EDIT: I should have been a bit more clear. I believe it's necessary for me to input my variable as 'Portfolio, Mike' in order for it to find the multiple values. Is this possible?
I'm assuming you could maybe use a charindex with a substring and a replace?
Yep, multiple Like statements with OR will work just fine -- just make sure you use the correct parentheses:
SELECT ...
FROM ...
WHERE 1=1
and (rpt_title LIKE '%Portfolio%'
or rpt_title LIKE '%Mike%')
However, I might suggest you look into using a full-text search.
http://msdn.microsoft.com/en-us/library/ms142571.aspx
I can propose a solution where you could specify any number of masks, without using multiple LIKE -
DECLARE #temp TABLE (st VARCHAR(100))
INSERT INTO #temp (st)
VALUES ('Portfolio photo'),('- Mike'),('blank'),('else'),('est')
DECLARE #delims VARCHAR(30)
SELECT #delims = '|Portfolio|Mike|' -- %Portfolio% OR %Mike% OR etc.
SELECT t.st
FROM #temp t
CROSS JOIN (
SELECT substr =
SUBSTRING(
#delims,
number + 1,
CHARINDEX('|', #delims, number + 1) - number - 1)
FROM [master].dbo.spt_values n
WHERE [type] = N'P'
AND number <= LEN(#delims) - 1
AND SUBSTRING(#delims, number, 1) = '|'
) s
WHERE t.st LIKE '%' + s.substr + '%'
I am trying to query a mysql table which contains strings of numbers
(i.e. '1,2,3,4,5').
How do I search to see if it has '1' but not '11' bearing in mind if it is '9,10' '9%' doesnt work??
Fixed!
(field like '10' OR field like '%,10,%' OR field like '%,10' OR field like '10,%')
You could try the function find_in_set
select find_in_set('1','1,2,3,11,12')
You need the function FIND_IN_SET. Btw, '9%' should work, if the column contains the values you specified, are you sure you're querying
SELECT * FROM table WHERE field LIKE '9%'?
Standard SQL can do it as well:
...
WHERE
',' + SetValue + ',' LIKE '%,1,%'
AND ',' + SetValue + ',' NOT LIKE '%,11,%'
This expression cannot make use of an index, therefore performance will degrade quickly as the table size rises.
For better performance your table should be properly normalized, e.g.
SetId SetValue
1 1
1 2
1 3
1 4
1 5
instead of
SetId SetValue
1 '1,2,3,4,5'