Select using case shows all results - sql

Two fields in the table articles:
title and body
Two records:
meow bark | 1234 5678 and bird snake | 8596 2952
Where meow bark is under title and 1234 5678 is under body, etc...
SQL Query:
SELECT *,
CASE WHEN title = 'meow' then 1 else 0 end + CASE WHEN title = 'bark' then 1 else 0 end AS matches
FROM articles
ORDER BY matches DESC
Returns both rows. Please help me understand what's wrong with my syntax. I am expecting it to return only rows where the title matches what is in the query. Unless I do not understand how CASE works, if title in the above example matches meow or bark, it should display - else, do not display.
The goal is to return results based on most matches. Take at fiddle look here: http://sqlfiddle.com/#!3/13b33/10
I modified it slightly, didn't think enough to break it though.

Unsure what you want to achieve ...what would you like to be returned
This might be a bit closer to what you want
SELECT *,
matches = CASE WHEN title LIKE '%meow5' THEN 1 ELSE 0 END + CASE WHEN title LIKE '%bark5' THEN 1 ELSE 0 END
FROM articles
ORDER BY matches desc
EDIT after OP has been updated
Try using the WHERE clause if you only want some of the records to be returned:
SELECT *
FROM articles
WHERE title LIKE '%meow%'
OR
title LIKE '%bark%'
ORDER BY matches desc
FINAL EDIT
Try this fiddle
In case Fiddle goes out of date here is the script:
CREATE TABLE YourTable (FieldToSearch varchar(max));
INSERT INTO YourTable
VALUES
('If there were a dog'),
('If there was a dog'),
('If that dog died!'),
('I''d be happy with cat');
SELECT x.*
FROM (
SELECT FieldToSearch,
CASE WHEN ' ' + FieldToSearch + ' ' like '% if %' then 1 else 0 end
+ CASE WHEN ' ' + FieldToSearch + ' ' like '% there %' then 1 else 0 end
+ CASE WHEN ' ' + FieldToSearch + ' ' like '% was %' then 1 else 0 end
+ CASE WHEN ' ' + FieldToSearch + ' ' like '% a %' then 1 else 0 end
+ CASE WHEN ' ' + FieldToSearch + ' ' like '% dog %' then 1 else 0 end AS matches
FROM YourTable
)x
WHERE x.matches >0
ORDER BY x.matches DESC;

You need to put that in a WHERE clause rather than the SELECT clause if you want to exclude rows.
Also, the comparisons you are using are for equivalence. This will not "match" if the column contains your search value, as you seem to think, but only if the column has exactly the same text and nothing else (with some small allowances for collation).

you dont have where clause mentioned in the query, it will fetch all the records unless you filter them using where condition

Related

SQL Server: remove list entry from the string of another list

I am sure that title is a bit confusing. Basically I have one table that has a column containing formation like "xx 123 Rg 43" and one that contains information like "Rg".. and if an entry from table 2's column is contained in the string contained in Table 1 then I need just that entry removed.. leaving us with "xx 123 43"
Currently I am using:
update [Table1]
set [Col1] = case
when (select * from [Table2]
where charindex(' ' + [Col2] + ' ', [Col1]) > 0) is not null
then replace([Col1], (select * from [Table2]
where charindex(' ' + [Col2] + ' ', [Col1]) > 0), '')
else [Col1]
end
And this works fine, but fails if this query
select *
from [Table2]
where charindex(' ' + [Col2] + ' ', [Col1]) > 0
returns more than 1 row with this error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
But I do need every match removed. Help!
Have you tried something like this?
update actual
set column1 = replace(column1, valueToReplace, '')
from TableWithActualData actual
inner join TableWithValuesToFind find
on actual.column1 like '%' + find.valueToReplace + '%';
See SQL Fiddle Example.
That said; this could have unpredictable behaviour... Suppose you have a value catamaran and you have logic to replace the words cat and tamara. If you replace cat first you're left with amaran, which doesn't contain tamara. If you replaced tamara first you're left with can, which doesn't contain cat. What should the behaviour be in such scenarios?
The above code sort of avoids this; by only acting on the first match... However this means that even in scenarios where there are multiple valid replacements (e.g. replacing cat and ran in catamaran) you still won't get your expected result (ama), but rather the result will depend on which of cat or ran were found first (giving amaran or catama accordingly).
There's no way for you to specif icy this order either; the database will just operate on whichever results are returned first.
To avoid that, you're best off replacing one value at a time, in a predefined order... e.g. SQL Fiddle.
declare #valueToReplace nvarchar(256)
declare replaceValueCuror cursor for
select valueToReplace
from TableWithValuesToFind
order by priority
open replaceValueCuror
fetch next from replaceValueCuror
into #valueToReplace
while ##fetch_status = 0
begin
update TableWithActualData
set column1 = replace(column1, #valueToReplace, '')
where column1 like '%' + #valueToReplace + '%'
fetch next from replaceValueCuror
into #valueToReplace
end
close replaceValueCuror
deallocate replaceValueCuror
You seems want :
update t1
set col1 = (case when exists (select 1
from t2
where charindex(t2.col2, t1.col1) > 0)
)
then stuff
else t1.col1
end)

SQL WHERE CONTAINS statement referencing columns not static text

I have these data below:
FName | Lname | Notes | Flag
----- ----- ----- ----
John Smith John Smith didn't know 1
Bill Jones Tom Johnson knows 0
I need to create and populate a variable (Flag) which looks at the Notes column, searches for values in Fname and Lname column, and assigns a 1 if Notes contains both Fname and Lname values, or 0 if it contains only 1, or none of the values from Fname and Lname.
I have looked at CONTAINS, LIKE, and INSTR, but I am having trouble with the references, the examples I see want me to enter a static value to search on ("John"), rather than a column reference ("Fname").
I'd like to write a CASE statement that says
Look in each row, if the Notes field contains the values in the Fname and Lname fields, Flag =1, else, Flag =0.
I have tried
CASE
WHEN
(
SELECT
Fname, Lname, Notes
FROM
table
WHERE CONTAINS ((Notes, Fname) AND (Notes, Lname)) > 0
)
THEN '1' ELSE '0' END
AS Flag
FROM table;
Any help is appreciated. Thank you !
Not sure if the coalesce/isnull is necessary.
select
case
when ((Notes like '%' + coalesce(u.FName,'') + '%') and (Notes like '%' + coalesce(LName,'') + '%'))
then 1
else 0
end Flag
from Table
update t
set t.Flag =
case
when ((Notes like '%' + coalesce(u.FName,'') + '%') and (Notes like '%' + coalesce(LName,'') + '%'))
then 1
else 0
end
From Table t
You were close:
SELECT
CASE WHEN
t.Notes LIKE '%' + t.FName + '%'
AND
t.Notes LIKE '%' + t.LName + '%'
THEN 1
ELSE 0 END AS Flag
FROM
table AS t
However, if you really just want to filter where the Flag = 1, you don't need this as a column:
SELECT
*
FROM
table AS t
WHERE
CASE WHEN
t.Notes LIKE '%' + t.FName + '%'
AND
t.Notes LIKE '%' + t.LName + '%'
THEN 1
ELSE 0 END =1

SQL count string matches in each row

Please take a look at this simple SQL server database :
What I want is, I want to create a summary with only 3 column, here is the code:
select ProductID, Name,
*code* as CountString
from product
where Name in ('this', 'is', 'count', 'example')
I want the result to have 3 column, and the column "CountString" is the total number of string that matches ('this','is', 'count', 'example'). Here is the result I want :
So for example, I want the Countstring for ProductID 1 is 4, because it contains all of 4 words.
If you can solve this, it would be amazing!
If I understand correctly:
select ProductID, Name,
( (case when Name like '%this%' then 1 else 0 end) +
(case when Name like '%is%' then 1 else 0 end) +
(case when Name like '%count%' then 1 else 0 end) +
(case when Name like '%example%' then 1 else 0 end)
) as CountString
from product;
Note: Any Name that has "this" also has "is".
If "words" are separated by spaces (and only spaces), you can do:
select ProductID, Name,
( (case when concat(' ', Name, ' ') like '% this %' then 1 else 0 end) +
(case when concat(' ', Name, ' ') like '% is %' then 1 else 0 end) +
(case when concat(' ', Name, ' ') like '% count %' then 1 else 0 end) +
(case when concat(' ', Name, ' ') like '% example %' then 1 else 0 end)
) as CountString
from product;
The following query should suffice your need ---
SELECT PRODUCTID,
NAME,
REGEXP_COUNT(NAME, 'this|is|count|example', 1, 'c') CountString
FROM product;
This query will result in "Case Sensitive" checking, means only "example" will be counted not "Example". If you want "Case Insensitive" checking just put 'i' instead of 'c'.

Parsing Name Field in SQL

I am trying to separate a name field into the appropriate fields. The name field is not consistently the same. It can show up as Doe III,John w or Doe,John, or Doe III,John, or Doe,John W or it may be lacking the suffix and or middle initial. Any ideas would be greatly appreciated.
SELECT (
CASE LEN(REPLACE(FirstName, ' ', ''))
WHEN LEN(FirstName + ' ') - 1
THEN PARSENAME(REPLACE(FirstName, ' ', '.'), 2)
ELSE PARSENAME(REPLACE(FirstName, ' ', '.'), 3)
END
) AS LastName
,(
CASE LEN(REPLACE(FirstName, ' ', ''))
WHEN LEN(FirstName + ',') - 1
THEN NULL
ELSE PARSENAME(REPLACE(FirstName, ' ', '.'), 2)
END
) AS Suffix
,PARSENAME(REPLACE(FirstName, ' ', '.'), 1) AS FirstName
FROM Trusts.dbo.tblMember
I need the name regardless of the format, as stated above, to parse into the appropriate fields of LastName,Suffix,FirstName,MiddleInitial, regardless of whether it has a suffix or a middle initial
If the given 4 names are the only type of cases, then you can use something like below.
Note: I used a CTE table tbl2 to separate comma_pos,first_space,second_space for better understanding in the main query. You can replace these value in main query with their corresponding function in CTE, to make the main query faster. I mean replace comma_pos in main query with charindex(',',name) an so on.
Also I am assuming that there are no leading/trailing or extra whitespaces or any junk character in name column. If you have, then sanitize your data first before proceeding.
Rexter Sample
with tbl2 as (
select tbl.*,
charindex(',',name) as comma_pos,
charindex(' ',name,1) first_space,
charindex(' ',name,charindex(' ',name,1)+1) second_space
from tbl)
select tbl2.name
,case when second_space <> 0
then substring(name,comma_pos+1,second_space-comma_pos-1)
when first_space > comma_pos
then substring(name,comma_pos+1,first_space-comma_pos-1)
else substring(name,comma_pos+1,len(name)-comma_pos)
end as first_name
,case when second_space <> 0
then substring(name,second_space+1,len(name)-second_space)
when first_space > comma_pos
then substring(name,first_space+1,len(name)-first_space)
end as middle_name
,case when first_space=0 or first_space>comma_pos
then substring(name,1,comma_pos-1)
else substring(name,1,first_space-1)
end as last_name
,case when first_space=0 or first_space>comma_pos
then null
else substring(name,first_space,comma_pos-first_space)
end as suffix
from tbl2;

Printing out list of attribute descriptions based on boolean columns in SQL

I've got a table with a few boolean columns like: IsProductionWorker, IsMaterialHandler, IsShopSupervisor, etc. A record in this table may have several of these column values as true.
What I would like to do is have a query that returns 1 field with a list of all the attributes that are true, say AttributeList which, if those 3 columns were true would return: "Production Worker, Material Handler, Shop Supervisor".
I can think of a few brute force methods and maybe a more elegant method through the use of a temp-table (I've done similar things before), but I'm curious as to what the best way of doing this would be and if there are any easier implementations.
Thanks.
No elegance is possible, really. Simplicity, yes.
Per row you want to change a flag into a string, for each flag. Not many options for cleverness...
SELECT
SUBSTRING (
CASE WHEN IsProductionWorker = 1 THEN ', Production Worker' ELSE '' END +
CASE WHEN IsMaterialHandler= 1 THEN ', Material Handler' ELSE '' END +
CASE WHEN IsShopSupervisor= 1 THEN ', Shop Supervisor' ELSE '' END +
... ,
3, 8000)
FROM
MyTable
WHERE
...
You can try this.
select CASE WHEN isProductionWorker = 1 THEN 'Production Worker' ELSE '' END
+ CASE WHEN cast(isProductionWorker as int) + isMaterialHandler = 2 THEN ', ' else '' END
+ CASE WHEN isMaterialHandler = 1 THEN 'Material Handler' ELSE '' END
+ CASE WHEN cast(isProductionWorker as int) + isMaterialHandler + isShopSupervisor > 1 THEN ', ' else '' END
+ CASE WHEn isShopSupervisor = 1 THEN 'Shop Supervisor' ELSE '' END AS AttributeList
from MyTable