LIKE condition with comma separated values - sql

This may seem silly but I am working on an old system where we don't have separate table for project. We have a table something like this.
| PROJECTNAME | EMPID |
|--------------------|-------|
| casio calc new | 1 |
| calc new | 2 |
| tech | 3 |
| financial calc new | 4 |
| casio | 5 |
Now what we want is to select EmpID from the above table where ProjectName can be either casio or calc. And we have user inputs for multiple selection like casio, calc. Meaning if user inputs casio, calc it should find ProjectName LIKE '%casio%' OR '%calc%'.
I really don't have any idea how can this be possible.
SELECT * FROM ProjectDetails
WHERE ProjectName LIKE 'casio, calc';
I searched for SQL LIKE with IN but I couldn't find any solution. Do anyone have idea how can I achieve this? Or any other approach to use? I am trying this on this fiddle.

Here you go. You can create a dynamic query with the help of REPLACE function with a little bit hack. Then use EXEC function to execute that query.
DECLARE #str VARCHAR(MAX)
SELECT #str='casio,calc'
SELECT #str='LIKE ''%'+REPLACE(#str,',','%'' OR ProjectName LIKE ''%')+'%'''
EXEC('SELECT * FROM ProjectDetails WHERE
ProjectName ' + #str +'');
Output:
| PROJECTNAME | EMPID |
|--------------------|-------|
| casio calc new | 1 |
| calc new | 2 |
| financial calc new | 4 |
| casio | 5 |
SQL Fiddle Demo
Thanks to Joe G Joseph for his hint.

The solution is to use several LIKE conditions:
SELECT *
FROM ProjectDetails
WHERE ProjectName LIKE '%casio%'
OR ProjectName LIKE '%calc%';

Like doesn't except comma delimited values. You are going to have to dynamically add an or condition for each passed in value.
It has to be of the form:
ProjectName Like'%param1%' OR ProjectName Like '%param2%'

We declare #str variable and store value we want to search and using REPLACE function place like keyword for every value and assign it to main query and execute it, you can get result
DECLARE #Query VARCHAR(MAX)
DECLARE #str VARCHAR(MAX)
SELECT #str='tech,casio, calc,casio calc new'
SELECT #str='LIKE ''%'+REPLACE(#str,',','%'' OR ProjectName LIKE ''%')+'%'''
set #Query ='SELECT * FROM ProjectDetails WHERE
ProjectName ' + #str
exec( #Query)

Related

Find all columns with different values for two rows in one table

I have a table from which two entries in particular from which I am looking for differences. This table has enough columns that I'd like a way to have it only display the different ones. I would like to identify which column values for those two entries are different. That is -
table_one
|------------------------------------------------------------------------------------------|
| key_id | order_number | serial_code | order_date | idk_more_data_one | idk_more_data_two |
|------------------------------------------------------------------------------------------|
| 0000 | 45576 | f56b22 | 20200101 | 22000 | 99.4 |
| 0001 | 45576 | f56b22 | 20200101 | 23000 | 91.7 |
| 0002 | 45577 | rt1000 | 20200101 | 19500 | 93.3 |
| 0003 | 45577 | rt1000 | 20200101 | 20000 | 93.3 |
| 0004 | 45577 | rt1000 | 20200101 | 19750 | 93.3 |
|------------------------------------------------------------------------------------------|
I would need a query that pulls out just the key_id values of 0000 and 0001, and then only displays columns key_id, idk_more_data_one, and idk_more_data_two, because they are the only columns that changed.
I saw online people talking about self joins and the like but I don't think that's what I want or if it is then I do not understand how to use it properly here, and it wasn't exactly the same issue so I wasn't able to transplant it directly. I also tried something very direct, like
Select *
From
(Select *
From table_one
Where order_number = '45576')
Where
but couldn't puzzle out what would yield me the right effect in the Where portion of the statement.
I'm not totally sure what are you looking to, but if you are trying to search 2 registries by and key_id and those 3 fields:
SELECT key_id, idk_more_data_one, idk_more_data_two
FROM table_one
WHERE key_id IN ("0000","0001")
EDITION AFTER COMMENTARY:
What you are trying to do is build a custom query, there are probably more ways to do this but I'll write what I've done and I hope it will help you.
First of all you'll have to create and storedProcedure (SP) for this kind of queries, the SP will have to accept at least one parameter that will be a varchar of N length (as much as you think it may do) and will contain the columns you are going to be queriing.
Then you'll have to construct your query as an string to which you'll concatenate your parameters:
ALTER/CREATE PROCEDURE sp_whatevername
#columns varchar(200)
AS
BEGIN
#DECLARE Query varchar(500)
SET Query = 'SELECT ' + #columns + ' FROM tbl_one'
EXEC (Query)
END
As I said, this may not be the best approach due to the use of "EXEC" which in mssql may do harm if is incorrectly used and you have to be very careful with what you allow to get to your db because you'll be opening one big open door there.
So, to append you where statement, you'll have to do the same appending to it the WHERE in front of the statetment
ALTER/CREATE PROCEDURE sp_whatevername
#columns varchar(200),
#where varchar(200)
AS
BEGIN
#DECLARE Query varchar(500)
SET Query = 'SELECT ' + #columns + ' FROM tbl_one ' + #where
EXEC (Query)
END

How to select data using table/column names stored in a table? Dynamically building SQL?

I have a table that shows events and vehicles associated with those events:
id | model | colour | cargo
--------------------------------------------
1 | vw | red | tomatoes
2 | bmw | red | golf clubs
I would like to have a table that I can use to manage alerts. There is a column that represents strings to check for, another column that shows which column/table it is applied to and some text that describes the alert:
id | column_name | check_string | alert_string
--------------------------------------------
1 | my_table.colour | red | 'Vehicle is red'
2 | my_table.cargo | [sport,club] | 'Vehicle is carrying sports goods'
or possibly:
id | column_name | check_string | alert_string
--------------------------------------------
1 | my_table.colour | red | 'Vehicle is red'
2 | my_table.cargo | sport | 'Vehicle is carrying sports goods'
3 | my_table.cargo | club | 'Vehicle is carrying sports goods'
I would like to have a query that I can run that would return all the alerts that apply to that row:
id | alert_text
--------------------------------------------
1 | ['Vehicle is red']
2 | ['Vehicle is red', 'Vehicle is carrying sports goods']
The way I was doing this was building up SQL commands in Python and running them against the database but this becomes a burden as the number of rules grow or variables need to be changed/updated (suddenly we don't care about red cars but are very concerned with blue cars).
SELECT id, 'Vehicle is red' as alert_text FROM my_table
WHERE my_table.colour = 'red';
SELECT id, 'Sports goods' as alert_text FROM my_table
WHERE my_table.cargo in ['sport', 'club'];
SELECT <many other rules>;
Is there a better way to do this? Is it worth building a DB table that can dynamically point to a column, strings to check in that column and then alert text associated with the rule? Should I even be using SQL for this problem?
I've got a feeling that SQL is maybe not the right tool for this job but I don't know what I don't know...
This SQL code would allow you to have a DB table of any size for both Events and Alerts
Declare #vSQL nvarchar(Max)
Declare #vColumnName nvarchar(25)
Declare #vCheckString nvarchar(25)
Declare #vAlertString nvarchar(50)
Declare vCursor CURSOR For
Select [column_name], [check_string], [alert_string] From vehicle_alerts
Open vCursor;
Fetch Next From vCursor Into #vColumnName, #vCheckString, #vAlertString
--Make global temp table from source then delete contents.
--Ensures field lengths are as large as the largest value in the temp table (Not the most efficient but it works)
Select id, alert_string INTO ##alerts From vehicle_alerts
Delete From ##alerts
While ##FETCH_STATUS = 0 --Loop through alerts and interrogate your events using the LIKE operator
Begin
Set #vSQL = 'INSERT INTO ##alerts Select id, '''+#vAlertString+''' As [Alert] From vehicle_events Where ' + #vColumnName + ' Like ''%' + #vCheckString + '%'''
Execute (#vSQL)
Fetch Next From vCursor Into #vColumnName, #vCheckString, #vAlertString
End;
--Use STUFF to combine the alert strings by id
Select id,STUFF((Select ',' + [alert_string] From ##alerts Where id = a.id FOR XML PATH('')),1,1,'') AS Tmp
From ##alerts AS a
Group By id
Drop Table ##alerts
Close vCursor
Deallocate vCursor

SQL Find String

I would like to know if finding a string can be done from another table. It's a bit complicated.
Here's the table: (tbl_dishes)
| dish | Type |
| egg, hotdog & bread | Breakfast |
From the table above, I want to get the individual descriptions of the column dish from another table
2nd Table (tbl_Foods)
| food | Description |
| egg | Fresh |
| hotdog | red |
| bread | toasted |
| steak | meat |
Let's say my query would look like this: (but it's wrong)
SELECT food, description FROM tbl_Foods
WHERE food Exists IN (SELECT dish FROM tbl_Dishes)
My desired results would be:
| food | Description |
| egg | Fresh |
| hotdog | red |
| bread | toasted |
It's like getting all matched word in the dish column. I don't know if it's possible. Please help.
Thank you.
SELECT food, description
FROM tbl_Foods
join tbl_Dishes
on tbl_Dishes.dish like ('%' + tbl_Foods.food +'%')
You will need to split the list
DECLARE #DelimString VARCHAR(100)
SET DelimString = SELECT REPLACE(REPLACE(dish,'&',','),' ', '') FROM tbl_Dishes
DECLARE #Dish TABLE (Dish VARCHAR(50)); INSERT INTO #Dish SELECT CAST(ParamValue AS VARCHAR) FROM MultiValueParams_String(#DelimString)
Use this function.
Create function [dbo].[MultiValueParams_String] (#ParamList varchar(4000))
returns #Values table (RoNum INT,ParamValue varchar(4000))
as
begin
declare #Delim char(1) = ',' -- comma is always the delimiter
declare #Chrind int = 1
declare #Piece nvarchar(50)
declare #RoNum int = 0
while #Chrind>0
begin
select #Chrind=charindex(#Delim,#ParamList)
if #Chrind>0
select #Piece=left(#ParamList,#chrind-1)
else
select #Piece=#ParamList
insert #values(RoNum,ParamValue) values (#RoNum,#Piece)
select #ParamList = right(#ParamList,len(#ParamList)-#chrind)
if len(#ParamList)=0 break
SELECT #RoNum = #RoNum + 1
end
return
end
SELECT food, description
FROM tbl_Foods f
INNER JOIN #Dish d ON f.food = d.dish
Something like this.

SQL Server: UPDATE after pivot (unpivot needed?)

Two days ago I asked how to use pivot in SQL to transpose a table.
With your help I got it right, here the solution: SQL server: Transpose Rows to Columns (n:m relationship)
I'm running SQL Server 2012, with an OBDC-connection, programming in C#.
So now I have:
| mitID | Name | FamName | DOB | abtIDref | HV | PEV | Drive | Nex |
|-------|--------|---------|------------|----------|---------------|------------|------------|------------|
| 1 | Frank | Sinatra | 12.12.1915 | 1 | **30.5.2016** | | 05.06.2015 | 02.11.2015 |
| 2 | Robert | Downey | 4.4.1965 | 2 | 27.7.2014 | 01.01.2016 | 20.01.2015 | |
I get this with following SQL statement:
DECLARE #sql AS NVARCHAR(MAX)
DECLARE #cols AS NVARCHAR(MAX)
SELECT #cols = ISNULL(#cols + ',', '') + QUOTENAME(Descr)
FROM Faehigkeiten ORDER BY faeID
SET #sql = N'
SELECT mitID, Name, FamName, DOB, abtIDref, ' + #cols + '
FROM(
SELECT mitID, Name, FamName, DOB, abtIDref, [when], descr
FROM Mitarbeiter m
JOIN[Link - List] l ON m.mitID = l.mitIDref
JOIN Faehigkeiten f ON f.faeID = l.feaIDref
) a
PIVOT(MAX([when]) FOR descr IN(' + #cols + ')) p'
EXEC sp_executesql #sql
But when I enter a new date (shown in asterisk above), or change a name of a member, how do I save the data?
I thought about unpivot, but I have no idea how to use it in my case.
My solution would be to loop through all the rows and compare it to existing entries ... but that could take a long time with lots of members.
Can you point me in some direction, wether it is possible to UPDATE this an easy way? I only need UPDATE no INSERT since new rows are forbidden.
Right now I have no class for my members. I load my DataGridView in C# with the following code:
BindingSource bsMember = new BindingSource();
bsMember.DataSource = DBMember.Get();
dgv.DataSource = bsMember;
The DBMember.Get() returns a DataTable made with the above shown SQL code.
Sorry, I have no approach except my loop through each row :/
EDIT: The provided duplicate is hard for me to follow because of the JOIN in my SQL-code. Can i JOIN while updating?
Please consider helping me directly.

How to merge multiple rows into one row with filtering rules in SQL Server

I have a table like this:
+---------------+---------------+----------------+---------------------+
| MedicalCardId | DiagnosisType | DiagnosisOrder | Symptom |
+---------------+---------------+----------------+---------------------+
| 1 | Main | 1 | Lung Cancer |
| 1 | Secondary | 1 | High Blood Pressure |
| 1 | Secondary | 2 | Heart Attack |
| 1 | Secondary | 3 | Gastritis |
| 2 | Main | 1 | Diabetes |
| 2 | Secondary | 1 | Kidney Malfunction |
| 3 | Main | 1 | Flu |
+---------------+---------------+----------------+---------------------+
The DiagnosisOrder for each 'Main' DiagnosisType is 1, and for 'Secondary' DiagnosisType of the same MedicalCardId, it restarts to increase from 1.
I would like to merge multiple rows of the same MedicalCardId into a single row, and each Symptom becomes a new column depending on its DiagnosisType and DiagnosisOrder
The query result is expected to be like:
+---------------+-------------+---------------------+-------------------+-------------------+
| MedicalCardId | MainSymptom | SecondarySymptom1 | SecondarySymptom2 | SecondarySymptom3 |
+---------------+-------------+---------------------+-------------------+-------------------+
| 1 | Lung Cancer | High Blood Pressure | Heart Attack | Gastritis |
| 2 | Diabetes | Kidney Malfunction | | |
| 3 | Flu | | | |
+---------------+-------------+---------------------+-------------------+-------------------+
I've tried using PIVOT, but I'm unable to apply it to my practice.
You can try with conditional aggregation -
select MedicalCardId,
max(case when DiagnosisType='Main' then Symptom end) as MainSymptom,
max(case when DiagnosisType='Secondary' and DiagnosisOrder=1 then Symptom end) as SecondarySymptom1,
max(case when DiagnosisType='Secondary' and DiagnosisOrder=2 then Symptom end) as SecondarySymptom2,
max(case when DiagnosisType='Secondary' and DiagnosisOrder=3 then Symptom end) as SecondarySymptom3
from tablename
group by MedicalCardId
I believe you need to create a dynamic pivot table. The reason why you can’t use a normal pivot table query is because you don’t know how many Secondary Symptoms there are and therefore you don’t know how many columns to create. Below is a stored procedure that works. The first step is creating a VARCHAR (#Columns) variable that will be used to store the dynamic column names these will be [Main], [Secondary1], [Secondary2], [Secondary3] so on and so forth (I used a case statement to create the column names per your expected query result). The second step is creating another VARCHAR (#SQL) variable that will contain the pivot table SQL query. In this step you will use string concatenation to put this variable together.
Kris Wenzel has a great tutorial on dynamic pivot tables at essentialsql.com here is the link https://www.essentialsql.com/create-dynamic-pivot-table-sql-server/
Here is the stored procedure.
USE [TestDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[GenerateData]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
--GATHER PIVOT COLUMNS DYNAMICALLY
DECLARE #Columns as VARCHAR(MAX)
SELECT #Columns =
COALESCE(#Columns + ', ','') + QUOTENAME([Diagnosis])
FROM
(SELECT DISTINCT case when [DiagnosisOrder] = 1 and [DiagnosisType] = 'Main' then 'MainSymptom' else 'SecondarySymptom' + CAST([DiagnosisOrder] AS VARCHAR) end [Diagnosis] FROM [TestDB].[dbo].[test] ) AS B
ORDER BY B.[Diagnosis]
--CREATE SQL QUERY FOR PIVOT TABLE
DECLARE #SQL as VARCHAR(MAX)
SET #SQL = 'SELECT MedicalCardId, ' + #Columns + '
FROM
(
select [MedicalCardId]
,[Diagnosis]
,[Sympton]
from
(
SELECT [MedicalCardId]
,case when [DiagnosisOrder] = 1 and [DiagnosisType] = ''Main'' then ''MainSymptom'' else ''SecondarySymptom'' + CAST([DiagnosisOrder] AS VARCHAR) end [Diagnosis]
,[Sympton]
FROM [TestDB].[dbo].[test]
) A
) t
PIVOT(
MAX([Sympton])
FOR [Diagnosis] IN (' + #Columns + ')
) AS pivot_table order by [MedicalCardId]'
--EXECUTE SQL
EXEC(#SQL)
END
GO