Alternative TSQL - sql

This query works well as you can see I have to put split between between #SearchCriteria and the rest of the query due to it's varchar. If I forced, the syntax works well BUT it return nothing when you query possible because extra '
Can you help?
ALTER PROCEDURE [dbo].[sp_rte_GetRateList]
(
#TenantID INT,
#CustomerID BIGINT = -1,
#SearchCriteria VARCHAR(64) = '',
#SortBy VARCHAR(16) = '',
#SortType VARCHAR(16) = '',
#Debug BIT = 0
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql nvarchar(4000),
#paramlist nvarchar(4000)
IF (#SearchCriteria = '')
BEGIN
SELECT #sql = 'SELECT r.TenantID, r.RateID, r.RateGUID, r.RateCode, r.RateName, r.RateDescription, r.ValidityUTCDate, r.CreatedUTCTimeStamp,
r.CreatedIP, r.CreatedBy, r.LastModifiedUTCTimeStamp, r.LastModifiedIP, r.LastModifiedBy, r.IsActive,
c.CustomerID, c.CustomerName, rt.RateTypeID, rt.RateTypeName, s.SupplierID, s.SupplierName, r.FixedLineAmount, r.MobileAmount, r.DataAmount, r.OtherAmount,
(r.FixedLineAmount + r.MobileAmount + r.DataAmount + r.OtherAmount) AS TotalAmount,
r.CreatedUTCTimeSTamp,
STUFF((SELECT '', '' + ct.CustomerTypeName
FROM glb_CustomerTypes ct JOIN glb_CustomerCustomerTypes cct ON cct.CustomerTypeID = ct.CustomerTypeID
WHERE cct.CustomerID = C.CustomerID
GROUP BY ct.CustomerTypeName FOR XML PATH('''')), 1, 2, '''') AS CustomerTypeName
FROM dbo.rte_Rates r
INNER JOIN dbo.rte_RateTypes rt ON r.RateTypeID = rt.RateTypeID
INNER JOIN dbo.glb_Suppliers s ON r.SupplierID = s.SupplierID
INNER JOIN dbo.glb_Customers c ON r.CustomerID = c.CustomerID
INNER JOIN dbo.glb_Addresses a ON c.CustomerID = a.CustomerID
INNER JOIN dbo.glb_AddressTypes at ON a.AddressTypeID = at.AddressTypeID
WHERE at.AddressTypeCode = ''GLB_ADT_PHYSCLDDRS'' AND
r.TenantID = #xTenantID AND
rt.TenantID = #xTenantID AND
s.TenantID = #xTenantID AND
r.IsActive = 1 AND
rt.IsActive = 1 AND
c.IsActive = 1 AND
c.CustomerID = #xCustomerID '
END
ELSE
BEGIN
SELECT #sql = 'SELECT r.TenantID, r.RateID, r.RateGUID, r.RateCode, r.RateName, r.RateDescription, r.ValidityUTCDate, r.CreatedUTCTimeStamp,
r.CreatedIP, r.CreatedBy, r.LastModifiedUTCTimeStamp, r.LastModifiedIP, r.LastModifiedBy, r.IsActive,
c.CustomerID, c.CustomerName, rt.RateTypeID, rt.RateTypeName, s.SupplierID, s.SupplierName, r.FixedLineAmount, r.MobileAmount, r.DataAmount, r.OtherAmount,
(r.FixedLineAmount + r.MobileAmount + r.DataAmount + r.OtherAmount) AS TotalAmount,
r.CreatedUTCTimeSTamp,
STUFF((SELECT '', '' + ct.CustomerTypeName
FROM glb_CustomerTypes ct JOIN glb_CustomerCustomerTypes cct ON cct.CustomerTypeID = ct.CustomerTypeID
WHERE cct.CustomerID = C.CustomerID
GROUP BY ct.CustomerTypeName FOR XML PATH('''')), 1, 2, '''') AS CustomerTypeName
FROM dbo.rte_Rates r
INNER JOIN dbo.rte_RateTypes rt ON r.RateTypeID = rt.RateTypeID
INNER JOIN dbo.glb_Suppliers s ON r.SupplierID = s.SupplierID
INNER JOIN dbo.glb_Customers c ON r.CustomerID = c.CustomerID
INNER JOIN dbo.glb_Addresses a ON c.CustomerID = a.CustomerID
INNER JOIN dbo.glb_AddressTypes at ON a.AddressTypeID = at.AddressTypeID
WHERE at.AddressTypeCode = ''GLB_ADT_PHYSCLDDRS'' AND
r.TenantID = #xTenantID AND
rt.TenantID = #xTenantID AND
s.TenantID = #xTenantID AND
r.IsActive = 1 AND
rt.IsActive = 1 AND
c.IsActive = 1 AND
c.CustomerID = #xCustomerID AND
(r.RateCode LIKE ''%' + #SearchCriteria + '%'' OR
r.RateName LIKE ''%' + #SearchCriteria + '%'' OR
rt.RateTypeName LIKE ''%' + #SearchCriteria + '%'' OR
r.RateDescription LIKE ''%' + #SearchCriteria + '%'' OR
s.SupplierCode LIKE ''%' + #SearchCriteria + '%'' OR
s.SupplierName LIKE ''%' + #SearchCriteria + '%'' OR
c.CustomerCode LIKE ''%' + #SearchCriteria + '%'' OR
c.CustomerName LIKE ''%' + #SearchCriteria + '%'' OR
c.CustomerDescription LIKE ''%' + #SearchCriteria + '%'' ) '
END
SELECT #sql = #sql + 'ORDER BY ' + #SortBy + ' ' + #SortType
IF (#Debug = 1) PRINT #sql
SELECT #paramlist = '#xTenantID INT, #xCustomerID BIGINT'
EXEC sp_executesql #sql, #paramlist, #TenantID, #CustomerID
END

You could just double any quotes in #SearchCriteria, but that won't protect you against all forms of SQL injection - which you can only do by getting away from dynamic SQL.
I'm not 100% sure you need dynamic SQL for this particular problem in the first place.

I think you'd be better off initializing the #SearchCriteria to NULL:
ALTER PROCEDURE [dbo].[sp_rte_GetRateList]
( ...
#SearchCriteria VARCHAR(64), --inits as NULL
....
)
IF #SearchCriteria IS NOT NULL
BEGIN
SET #SearchCriteria = REPLACE(#SearchCriteria, '''', '''''')
...
END
ELSE
...
I get why you setup the dynamic SQL the way you did - I noticed the paramlist doesn't have #SearchCriteria in it, so you don't have to define the param instances of #SearchCriteria. Might consider full text searches when you have 2+ columns from the same table - likely faster, and less complicated SQL.

Related

How to create a "Catalyst" to view data before x minutes from z timestamp and x minutes after z timestamp for every 'ABC' specific data

" I want a SSRS report that can identify all activations received within the last 5 minutes before the CNT signal was received from a store and signals that were received within 5 minutes after the CNT signal "
Need to know what is the best practice to achieve this goal - what to google to fix my query to make it easier to design in report builder
I have q query below but within SSRS I cant group it or expand it in a way useful for viewing
I have a proof of concept (image) but don't know how to approach the query to get to the result
a bit ambitious for a Jnr report writer!
POC Catalyst Idea <<<<<-
DECLARE #Division varchar(2) = '*',
#SubDivision varchar(4) = '*',
#MainArea varchar(3) = '*',
#SubArea varchar(3) = '*',
#StartD datetime = '2022-03-29',
#StartTime Varchar(10) = '06:00:00',
#EndD datetime = '2022-03-29',
#EndTime Varchar(10) = '18:00:00',
#X int = 5,
#Catylist varchar(3) = 'CNT'
DECLARE #Arc varchar(100),
#Svr varchar(50),
#db varchar(50),
#Str varchar(max) = '',
#Qry varchar(max) = '',
#mon varchar(100) = '',
#StartDate varchar(20),
#EndDate varchar(20)
SET #StartDate = CONVERT(varchar(11),#StartD,106) + ' ' + #StartTime
SET #EndDate = CONVERT(varchar(11),#EndD,106) + ' ' + #EndTime
SELECT #mon = IIF(UPPER(ServerName)=UPPER(##ServerName),DatabaseName,'[' + ServerName + '].' + DatabaseName) + '.dbo.'
FROM maBranchModules WITH (NOLOCK) WHERE Module = 'MONITOR'
CREATE TABLE #FirstBL
(CustId int, Signl varchar(10), StartTime datetime, EndTime datetime,Seq int,Catalyst char(1))
DECLARE Arc_cursor CURSOR FOR
SELECT SQLServer, SQLDatabase FROM RW_ArchiveDTL WITH (NOLOCK)
WHERE StartDTTM >= DATEADD(month,-1,EOMONTH(#StartDate))
AND EndDTTM <= DATEADD(day,1,EOMONTH(#EndDate))
ORDER BY StartDTTM
OPEN Arc_cursor
FETCH NEXT FROM Arc_cursor INTO #Svr, #db
WHILE ##FETCH_STATUS = 0
BEGIN
IF #Svr = ##ServerName
SET #Arc = #db + '.dbo.'
ELSE
SET #Arc = '[' + #Svr + '].' + #db + '.dbo.'
IF #Str = ''
SET #Str = 'INSERT INTO #FirstBL (CustId,Signl,StartTime,Seq)'
ELSE
SET #Str = #Str + char(13) + 'UNION ALL '
/*GET ALL CATYLIST SIGNALS IN DATE RANGE*/
SET #Str = #Str + char(13) + 'SELECT
a.CustId, a.FirstAlarm,a.SignalTime,ROW_NUMBER() OVER (PARTITION BY a.CustId ORDER BY a.SignalTime) AS Seq
FROM ' + #Arc + 'ArchiveHistory AS a WITH (NOLOCK) INNER JOIN
' + #mon + 'Address AS b WITH (NOLOCK) ON a.AddressId = b.AddressId
WHERE a.SignalTime >= ''' + CONVERT(varchar,#StartDate,121) + '''
AND a.SignalTime < ''' + CONVERT(varchar,#EndDate,121) + '''
AND a.FirstAlarm = ''' + #Catylist + '''
AND a.CustId > 0 '
IF #Division <> '*'
SET #Str = #Str + char(13) + 'AND b.Division = ''' + #Division + ''' '
IF #SubDivision <> '*'
SET #Str = #Str + char(13) + 'AND b.SubDivision = ''' + #SubDivision + ''' '
IF #MainArea <> '*'
SET #Str = #Str + char(13) + 'AND a.MainArea = ''' + #MainArea + ''' '
IF #SubArea <> '*'
SET #Str = #Str + char(13) + 'AND a.SubArea = ''' + #SubArea + ''' '
IF #Qry <> ''
SET #Qry = #Qry + char(13) + 'UNION ALL '
/*GET ALL SIGNALS FOR #X MINUTES BEFORE & AFTER CATYLIST SIGNAL RECEIVED*/
SET #Qry = #Qry + char(13) + 'SELECT DISTINCT
--a.CustId, b.StartTime, a.SignalTime, a.FirstAlarm, b.EndTime,
a.CustId, a.SignalTime, a.FirstAlarm, a.OBNumber,
c.CustCode, c.CustDesc, d.Division, d.SubDivision, d.MainArea, d.SubArea, c.SuspendMode
FROM ' + #Arc + 'ArchiveHistory AS a WITH (NOLOCK) INNER JOIN
#FirstBL AS b WITH (NOLOCK) ON a.CustId = b.CustId INNER JOIN
' + #mon + 'Client AS c WITH (NOLOCK) ON a.CustId = c.CustId INNER JOIN
' + #mon + 'Address AS d WITH (NOLOCK) ON c.AddressId = d.AddressId
AND a.SignalTime BETWEEN DATEADD(minute,-' + CONVERT(varchar,#X) + ',b.StartTime) AND b.EndTime '
FETCH NEXT FROM Arc_cursor INTO #Svr, #db
END
CLOSE Arc_cursor;
DEALLOCATE Arc_cursor;
SET #Str = #Str + char(13) + 'ORDER BY CustId, SignalTime'
EXEC(#Str)
/*CLEAN OUT ALL EXTRA CATYLIST SIGNALS THAT FALLS WITHIN #X OF "FIRST"*/
UPDATE #FirstBL SET EndTime = DATEADD(minute,#X,StartTime) WHERE Seq = 1
UPDATE a SET a.Catalyst = IIF(a.StartTime BETWEEN b.StartTime AND b.EndTime,'N','Y')
FROM #FirstBL AS a INNER JOIN
#FirstBL AS b ON a.CustId = b.CustId
WHERE b.Seq = 1
AND a.Seq > 1
DELETE FROM #FirstBL WHERE Catalyst = 'N'
DECLARE #N int
SET #N = 1
WHILE (SELECT COUNT(*) FROM #FirstBL WHERE EndTime IS NULL) > 0
begin
UPDATE #FirstBL SET EndTime = DATEADD(minute,#X,StartTime), Seq = #N + 1
WHERE Seq = (SELECT TOP 1 a.Seq FROM #FirstBL a WHERE #FirstBL.CustId = a.CustId AND Seq > #N ORDER BY a.Seq)
UPDATE a SET a.Catalyst = IIF(a.StartTime BETWEEN b.StartTime AND b.EndTime,'N','Y')
FROM #FirstBL AS a INNER JOIN
#FirstBL AS b ON a.CustId = b.CustId
WHERE b.Seq = #N
AND a.Seq > #N
DELETE FROM #FirstBL WHERE Catalyst = 'N'
Set #N = #N +1
end
/*ALL TOGETHER NOW*/
SET #Qry = #Qry + char(13) + 'ORDER BY CustId, SignalTime'
EXEC(#Qry)
/*GET RID OF THE #*/
DROP TABLE #FirstBL
If you want to look behind and ahead 5 minutes, recommend just using APPLY. For example, here's how to find every match to a "CNT" event within 5 minutes
Using APPLY to Find Events +/- 5 Minutes
DROP TABLE IF EXISTS #Data
CREATE TABLE #Data (
ID INT IDENTITY(1,1) PRIMARY KEY
,SignalDateTime DATETIME2(0)
,FirstAlarm CHAR(3)
)
INSERT INTO #Data VALUES
('2022-03-29 10:06','LRQ')
,('2022-03-29 10:07','CNF')
,('2022-03-29 10:07','CNT')
,('2022-03-29 10:07','DNT')
,('2022-03-29 13:19','LRQ')
,('2022-03-29 13:20','CNF')
,('2022-03-29 13:20','CNT')
,('2022-03-29 13:20','DNT')
,('2022-03-29 13:24','LRQ')
,('2022-03-29 13:24','CNF')
,('2022-03-29 13:24','CNT')
,('2022-03-29 13:24','DNT')
,('2022-03-29 13:25','CNF')
,('2022-03-29 13:25','CNT')
,('2022-03-29 13:25','DNT')
,('2022-03-29 14:31','LRQ')
,('2022-03-29 14:31','CNF')
,('2022-03-29 14:31','CNT')
,('2022-03-29 14:31','DNT')
SELECT CNTGroupID = DENSE_RANK() OVER (ORDER BY A.ID)
,*
FROM #Data AS A
CROSS APPLY (
SELECT *
FROM #Data AS DTA
WHERE DTA.FirstAlarm <> 'CNT'
AND DTA.SignalDateTime BETWEEN DATEADD(mi,-5,A.SignalDateTime) AND DATEADD(mi,5,A.SignalDateTime)
) AS B
WHERE A.FirstAlarm = 'CNT'

How to compare data from multiple databases

I'm trying to compare some data from different multiple databases, as I have illustrate my current case, I have there databases, database 1 is the main, and time to time database 2 and database 3 are updated from database 1. I have some difficulties to get the final result which return the data from database 1 and two columns column show the availability in database 2 as Yes or No, and the same with second extra column that will indicate the data availability on the database 3 with Yes or NO.
SELECT *
FROM (
Select ID as db1_ID,
First_name as db1_First_name,
Last_name as db1_Last_name,
Email as db1_Email,
Password as db1_Password,
Request_Id as db1_Request_Id,
User_Id as db1_User_Id,
Request_name as db1_Request_name
from User
inner join User_request
on User_request.User_Id = user.ID
) AS DB1_VIEW
LEFT OUTER JOIN
(
Select ID as db2_ID,
First_name as db2_First_name,
Last_name as db2_Last_name,
Email as db2_Email,
Password as db2_Password,
Request_Id as db2_Request_Id,
User_Id as db2_User_Id,
Request_name as db2_Request_name
from User
inner join User_request
on User_request.User_Id = user.ID
) AS DB2_VIEW
ON db2_ID = db1_ID
LEFT OUTER JOIN
(
Select ID as db3_ID,
First_name as db3_First_name,
Last_name as db3_Last_name,
Email as db3_Email,
Password as db3_Password,
Request_Id as db3_Request_Id,
User_Id as db3_User_Id,
Request_name as db3_Request_name
from User
inner join User_request
on User_request.User_Id = user.ID
) AS DB3_VIEW
ON db3_ID = db1_ID
ID First_name Last_name Email Password Request_Id User_Id Request_name
1 Oliver Jake OJake#domain.com 123 1 1 Request1
2 Mathew Harry MHarry#domain.com 123 1 2 Request1
3 Jacob Reece JReece#domain.com 123 1 3
Request1
4 Charlie Damian CDamian#domain.com 123 1 4 Request1
Use this as your first select statement:
SELECT DB1_VIEW.*
,CASE WHEN DB2_VIEW.db2_ID IS NOT NULL THEN 'Y' ELSE 'N' END AS Available_db2
,CASE WHEN DB3_VIEW.db3_ID IS NOT NULL THEN 'Y' ELSE 'N' END AS Available_db3
You can remove all the details apart from the ID fields in the db2_view and db3_view subqueries.
You can use the below query before execute you should use replace [SourceDB] to your source database and [TargertDB] to your target database. Insert the table name into #mdtables to include for comparison.
USE [SourceDB]
IF Object_id('tempdb..#mdTables') IS NOT NULL
DROP TABLE #mdtables;
CREATE TABLE #mdtables
(
id INT IDENTITY(1, 1) NOT NULL,
schemaname NVARCHAR(128),
tablename NVARCHAR(128)
);
INSERT INTO #mdtables
(schemaname,
tablename)
VALUES ('dbo',
'user');
DECLARE #mdTableLim INT =0,
#mdTableRowId INT =0
SELECT #mdTableLim = Count(*)
FROM #mdtables;
SET #mdTableRowId = 1;
WHILE #mdTableRowId <= #mdTableLim
BEGIN
DECLARE #SDBName VARCHAR(50) = '[SourceDB]',
#TDBName VARCHAR(50) = '[TargertDB]',
#tableName VARCHAR(100) = ''
DECLARE #WhereF VARCHAR(max) ='',
#joincondition VARCHAR(max) ='',
#or VARCHAR(10) ='',
#select VARCHAR(max) = '',
#comma VARCHAR(1)='',
#query VARCHAR(max) ='',
#and VARCHAR(5)='',
#where1 VARCHAR(1000) ='',
#wOR VARCHAR(5)=''
SELECT #tableName = tablename
FROM #mdtables
WHERE id = #mdTableRowId;
SELECT #joincondition += Isnull(#and + ( CASE
WHEN cu.column_name IS NULL
THEN
NULL
ELSE ' src.[' + cu.column_name
+
'] = ' +
'trgt.['
+ c.column_name + ']'
END ), ''),
#WhereF += Isnull (#or + ( CASE
WHEN cu.column_name IS NOT NULL THEN
NULL
ELSE Isnull ( ' src.[' +
TC.column_name
+
'] ',
' isnull( src.[' +
C.column_name +
'],1) ' )
+ Isnull( '<> trgt.[' +
TC.column_name
+ ']',
' = isnull (src.['
+
C.column_name + '],1) ')
END ), ''),
#or = ( CASE
WHEN cu.column_name IS NOT NULL THEN ''
ELSE ' OR '
END ),
#and = ( CASE
WHEN cu.column_name IS NULL THEN ''
ELSE ' AND '
END ),
#select += #comma + ' src.[' + c.column_name + '] '
+ Isnull (' , trgt.[' + TC.column_name + ']', ''),
#comma = ',',
#where1 += Isnull(( #wOR + ( CASE
WHEN cu.column_name IS NULL THEN
NULL
ELSE ' trgt.[' + cu.column_name +
'] is null '
END ) ), ''),
#wOR = ( CASE
WHEN cu.column_name IS NULL THEN ''
ELSE ' OR '
END )
FROM information_schema.columns C
LEFT JOIN information_schema.key_column_usage CU
ON C.column_name = cu.column_name
AND constraint_name LIKE 'PK_%'
AND c.table_name = cu.table_name
LEFT JOIN [TargertDB].information_schema.columns TC
ON C.column_name = TC.column_name
AND c.table_name = TC.table_name
WHERE c.table_name = #tableName
--AND columnproperty(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 0
AND c.column_name NOT IN ( 'LST_CHG_TMS', 'LST_CHG_TMS',
'LST_CHG_USR_ID'
,
'LST_CHG_USR_ID' )
AND c.data_type NOT IN ( 'image' )
ORDER BY cu.column_name
SET #query = 'select ' + #select + ' from ' + #SDBName + '.dbo.'
+ #tableName + ' as src left join ' + #TDBName
+ '.dbo.' + #tableName + ' as trgt on '
+ #joincondition + ' where (' + #where1 + ')'
+ Isnull ('and '+ NULLIF (#WhereF, ''), '')
DECLARE #qu1 VARCHAR(max) =
' declare #cnt int =0 select #cnt =count (1) from '
+ #SDBName + '.dbo.' + #tableName
+ ' as src left join ' + #TDBName + '.dbo.'
+ #tableName + ' as trgt on ' + #joincondition
+ ' where (' + #where1 + ')'
+ Isnull (' OR '+ NULLIF (#WhereF, ''), '')
+ ' if (#cnt>0) begin select '''
+ #tableName + ''' as [ ],#cnt ' +-- #query + ' end '
BEGIN try
EXECUTE ( #qu1)
END try
BEGIN catch
PRINT #qu1;
END catch
SET #mdTableRowId = #mdTableRowId + 1
END
This might not need CTE's or sub-queries.
A few joins might do it.
SELECT
Usr1.ID AS db1_User_Id,
Usr1.First_name AS db1_First_name,
Usr1.Last_name AS db1_Last_name,
Usr1.Email AS db1_Email,
Usr1.Password AS db1_Password,
MAX(UsrReq1.Request_Id) AS db1_Request_Id,
MAX(UsrReq1.Request_name) AS db1_Request_name,
CASE WHEN COUNT(UsrReq2.User_Id) > 0 THEN 'Y' ELSE 'N' END AS Available_Db2,
CASE WHEN COUNT(UsrReq3.User_Id) > 0 THEN 'Y' ELSE 'N' END AS Available_Db3
FROM [Database1].[User] AS Usr1
LEFT JOIN [Database1].[User_request] AS UsrReq1 ON UsrReq1.User_Id = Usr1.ID
LEFT JOIN [Database2].[User] AS Usr2 ON Usr2.ID = Usr1.ID
LEFT JOIN [Database2].[User_request] AS UsrReq2 ON UsrReq2.User_Id = Usr2.ID
LEFT JOIN [Database3].[User] AS Usr3 ON Usr3.ID = Usr1.ID
LEFT JOIN [Database3].[User_request] AS UsrReq3 ON UsrReq3.User_Id = Usr3.ID
GROUP BY
Usr1.ID,
Usr1.First_name,
Usr1.Last_name,
Usr1.Email,
Usr1.Password;

SQL - Dynamic Condition in Where Clause

I have the following stored proc. The issue I'm having is with the "conditions" parameter. Basically each condition is its own column so it it passed in like this-
#Conditions = ' AND hcc_108 = 1 AND ...' etc.
I'm trying to do something like this-
ALTER PROC [dbo].[GetPatientPanelList]
(
#CareProviderId int=null,
#Patient nvarchar(60)=null,
#Conditions varchar=null,
#LocationId int=null
)
AS
if #Conditions is null
SELECT *
FROM vw_patient_attributes t1
INNER JOIN STG_OSHODS_DW.osh_rpt.dim_member_care_measures t2
ON t1.PatientID = t2.emr_id
WHERE
(t1.PreferredServiceLocationID = #LocationId OR #LocationId IS NULL)
AND (t1.CareProviderID = #CareProviderId OR #CareProviderId IS NULL)
AND (t1.FullName like '%' + #Patient + '%' OR #Patient IS NULL)
else
SELECT *
FROM vw_patient_attributes t1
INNER JOIN STG_OSHODS_DW.osh_rpt.dim_member_care_measures t2
ON t1.PatientID = t2.emr_id
WHERE
(t1.PreferredServiceLocationID = #LocationId OR #LocationId IS NULL)
AND (t1.CareProviderID = #CareProviderId OR #CareProviderId IS NULL)
AND (t1.FullName like '%' + #Patient + '%' OR #Patient IS NULL)
+ #Conditions
I just need the last AND condition to populate based off the parameter. I understand that the " + " is the syntax error but I can't seem to figure out a way on how to implement this.
Thanks!
Update
I have tried dynamic sql but it keeps saying "Command(s) completed successfully)"
Here is my current code. I wrote this in a separate window to first get the query to work.
DECLARE #where nvarchar(50) = ' and hcc_18 = 1'
,#sql nvarchar(MAX) ,
#CareProviderId int=null,
#Patient nvarchar(60)=null,
#LocationId int=null
set #sql = 'select *
FROM vw_patient_attributes t1
INNER JOIN STG_OSHODS_DW.osh_rpt.dim_member_care_measures t2
ON t1.PatientID = t2.emr_id
WHERE t1.PreferredServiceLocationID = IsNull('+ convert(varchar,#LocationId) +',t1.PreferredServiceLocationID)
AND (t1.CareProviderID = isnull(' + convert(varchar,#CareProviderId)+ ', t1.CareProviderID)
AND (t1.FullName like %' + #Patient + '% OR ' + #Patient + ' IS NULL)' + #where
exec(#sql)
I fixed the syntax issues in your last updated. This should work...
DECLARE #where nvarchar(50) = ' and hcc_18 = 1'
,#sql nvarchar(MAX) ,
#CareProviderId int=null,
#Patient nvarchar(60)=null,
#LocationId int=null
set #sql = 'select *
FROM vw_patient_attributes t1
INNER JOIN STG_OSHODS_DW.osh_rpt.dim_member_care_measures t2
ON t1.PatientID = t2.emr_id
WHERE t1.PreferredServiceLocationID = case when '+ convert(varchar(8),isnull(#LocationId,0)) +' = 0 then t1.PreferredServiceLocationID else ' + convert(varchar,isnull(#LocationId,0)) + ' end
AND (t1.CareProviderID = case when ' + convert(varchar,isnull(#CareProviderId,0)) + ' = 0 then t1.CareProviderID else ' + convert(varchar,isnull(#CareProviderId,0)) + ' end
AND (t1.FullName like ''%' + isnull(#Patient,'') + '%'' OR ' + isnull(#Patient,0) + '=0)' + #where
print(#sql)
--exec(#sql)
Check my answer at
No need to use ad-hoc query (just execute SP_ExecuteSQL)
Check below logic, you can use N number of dynamic / un-sure parameters / conditions........

cast list of strings as int list in sql query / stored procedure

I have this stored procedure:
exec SearchResume #KeywordSearch=N'', #GreaterThanDate='2013-09-22 00:00:00',
#CityIDs=N'0,56,31,271,117,327,3,328,228',
#ProvinceIDs=N'0,1,12,13',
#CountryIDs=N'1',
#IndustryIDs=N'0,2,3,4,38,113,114,115,116,117'
Which doesn't return any results because the ids are in nvarchar but the actual values are integer.
Now, when I test the actual SP with a manual list of int values I'm able to get the results, this is the example:
SELECT DISTINCT
UserID,
ResumeID,
CASE a.Confidential WHEN 1 THEN 'Confidential' ELSE LastName + ',' + FirstName END as 'Name',
a.Description 'ResumeTitle',
CurrentTitle,
ModifiedDate,
CASE ISNULL(b.SalaryRangeID, '0') WHEN '0' THEN CAST(SalarySpecific as nvarchar(8)) ELSE c.Description END 'Salary',
h.Description 'Relocate',
i.Description + '-' + j.Description + '-' + k.Description 'Location'
FROM dbo.Resume a JOIN dbo.Candidate b ON a.CandidateID = b.CandidateID
LEFT OUTER JOIN SalaryRange c ON b.SalaryRangeID = c.SalaryRangeID
JOIN EducationLevel e ON b.EducationLevelID = e.EducationLevelID
JOIN CareerLevel f ON b.CareerLevelID = f.CareerLevelID
JOIN JobType g ON b.JobTypeID = g.JobTypeID
JOIN WillingToRelocate h ON b.WillingToRelocateID = h.WillingToRelocateID
JOIN City i ON b.CityID = i.CityID
JOIN StateProvince j ON j.StateProvinceID = b.StateProvinceID
JOIN Country k ON k.CountryID = b.CountryID
WHERE (b.CityID IN (0,56,31,125,229,5,219,8,228))
AND (b.StateProvinceID IN (0,1,13))
AND (b.CountryID IN (1))
AND (b.IndustryPreferenceID IN (0,2,3,4,5,6,115,116,117))
I would like to know what can I do to send a list of int values, not a list of nvarchar values since as you can see the query doesn't work properly.
Update
Original SP:
ALTER PROCEDURE [dbo].[SearchResume]
#KeywordSearch nvarchar(500),
#GreaterThanDate datetime,
#CityIDs nvarchar(500),
#ProvinceIDs nvarchar(500),
#CountryIDs nvarchar(500),
#IndustryIDs nvarchar(500)
AS
BEGIN
DECLARE #sql as nvarchar(4000)
SET #sql = 'SELECT DISTINCT
UserID,
ResumeID,
CASE a.Confidential WHEN 1 THEN ''Confidential'' ELSE LastName + '','' + FirstName END as ''Name'',
a.Description ''ResumeTitle'',
CurrentTitle,
ModifiedDate,
CurrentEmployerName,
PersonalDescription,
CareerObjectives,
CASE ISNULL(b.SalaryRangeID, ''0'') WHEN ''0'' THEN CAST(SalarySpecific as nvarchar(8)) ELSE c.Description END ''Salary'',
e.Description ''EducationLevel'',
f.Description ''CareerLevel'',
g.Description ''JobType'',
h.Description ''Relocate'',
i.Description + ''-'' + j.Description + ''-'' + k.Description ''Location''
FROM dbo.Resume a JOIN dbo.Candidate b ON a.CandidateID = b.CandidateID
LEFT OUTER JOIN SalaryRange c ON b.SalaryRangeID = c.SalaryRangeID
JOIN EducationLevel e ON b.EducationLevelID = e.EducationLevelID
JOIN CareerLevel f ON b.CareerLevelID = f.CareerLevelID
JOIN JobType g ON b.JobTypeID = g.JobTypeID
JOIN WillingToRelocate h ON b.WillingToRelocateID = h.WillingToRelocateID
JOIN City i ON b.CityID = i.CityID
JOIN StateProvince j ON j.StateProvinceID = b.StateProvinceID
JOIN Country k ON k.CountryID = b.CountryID
WHERE ( (ModifiedDate > ''' + CAST(#GreaterThanDate as nvarchar(55)) + ''')
'
IF (LEN(#CityIDs) >0)
BEGIN
SET #sql = #sql + 'AND (b.CityID IN (' + #CityIDs + '))'
END
IF (LEN(#ProvinceIDs) >0)
BEGIN
SET #sql = #sql + 'AND (b.StateProvinceID IN (' + #ProvinceIDs + '))'
END
IF (LEN(#CountryIDs) >0)
BEGIN
SET #sql = #sql + 'AND (b.CountryID IN (' + #CountryIDs + '))'
END
IF (LEN(#IndustryIDs) >0)
BEGIN
SET #sql = #sql + 'AND (b.IndustryPreferenceID IN (' + #IndustryIDs + '))'
END
IF (LEN(#KeywordSearch) > 0)
BEGIN
SET #sql = #sql + ' AND (' + #KeywordSearch + ')'
END
SET #sql = #sql + ') ORDER BY ModifiedDate desc'
--select #sql
exec sp_executesql #sql
END
You can create a Table-Valued Function which takes the nVarChar and creates a new record for each value, where you tell it the delimiter. My example here returns a table with a single Value column, you can then use this as a sub query for your IN Selection :
Create FUNCTION [dbo].[fnSplitVariable]
(
#List nvarchar(2000),
#delimiter nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Variable varchar(15),
Value nvarchar(100)
)
AS
BEGIN
Declare #Count int
set #Count = 1
While (Charindex(#delimiter,#List)>0)
Begin
Insert Into #RtnValue (Value, Variable)
Select
Value = ltrim(rtrim(Substring(#List,1,Charindex(#delimiter,#List)-1))),
Variable = 'V' + convert(varchar,#Count)
Set #List = Substring(#List,Charindex(#delimiter,#List)+len(#delimiter),len(#List))
Set #Count = #Count + 1
End
Insert Into #RtnValue (Value, Variable)
Select Value = ltrim(rtrim(#List)), Variable = 'V' + convert(varchar,#Count)
Return
END
Then in your where statement you could do the following:
WHERE (b.CityID IN (Select Value from fnSplitVariable(#CityIDs, ','))
I have included your original Procedure, and updated it to use the function above:
ALTER PROCEDURE [dbo].[SearchResume]
#KeywordSearch nvarchar(500),
#GreaterThanDate datetime,
#CityIDs nvarchar(500),
#ProvinceIDs nvarchar(500),
#CountryIDs nvarchar(500),
#IndustryIDs nvarchar(500)
AS
BEGIN
DECLARE #sql as nvarchar(4000)
SET #sql = N'
DECLARE #KeywordSearch nvarchar(500),
#CityIDs nvarchar(500),
#ProvinceIDs nvarchar(500),
#CountryIDs nvarchar(500),
#IndustryIDs nvarchar(500)
SET #KeywordSearch = '''+#KeywordSearch+'''
SET #CityIDs = '''+#CityIDs+'''
SET #ProvinceIDs = '''+#ProvinceIDs+'''
SET #CountryIDs = '''+#CountryIDs+'''
SET #IndustryIDs = '''+#IndustryIDs+'''
SELECT DISTINCT
UserID,
ResumeID,
CASE a.Confidential WHEN 1 THEN ''Confidential'' ELSE LastName + '','' + FirstName END as ''Name'',
a.Description ''ResumeTitle'',
CurrentTitle,
ModifiedDate,
CurrentEmployerName,
PersonalDescription,
CareerObjectives,
CASE ISNULL(b.SalaryRangeID, ''0'') WHEN ''0'' THEN CAST(SalarySpecific as nvarchar(8)) ELSE c.Description END ''Salary'',
e.Description ''EducationLevel'',
f.Description ''CareerLevel'',
g.Description ''JobType'',
h.Description ''Relocate'',
i.Description + ''-'' + j.Description + ''-'' + k.Description ''Location''
FROM dbo.Resume a JOIN dbo.Candidate b ON a.CandidateID = b.CandidateID
LEFT OUTER JOIN SalaryRange c ON b.SalaryRangeID = c.SalaryRangeID
JOIN EducationLevel e ON b.EducationLevelID = e.EducationLevelID
JOIN CareerLevel f ON b.CareerLevelID = f.CareerLevelID
JOIN JobType g ON b.JobTypeID = g.JobTypeID
JOIN WillingToRelocate h ON b.WillingToRelocateID = h.WillingToRelocateID
JOIN City i ON b.CityID = i.CityID
JOIN StateProvince j ON j.StateProvinceID = b.StateProvinceID
JOIN Country k ON k.CountryID = b.CountryID
WHERE ( (ModifiedDate > ''' + CAST(#GreaterThanDate as nvarchar(55)) + ''')
'
IF (LEN(#CityIDs) >0)
BEGIN
SET #sql = #sql + N'AND (b.CityID IN (Select Value from fnSplitVariable(#CityIDs,'','') ))'
END
IF (LEN(#ProvinceIDs) >0)
BEGIN
SET #sql = #sql + N'AND (b.StateProvinceID IN (Select Value from fnSplitVariable(#ProvinceIDs,'','') ))'
END
IF (LEN(#CountryIDs) >0)
BEGIN
SET #sql = #sql + N'AND (b.CountryID IN (Select Value from fnSplitVariable(#CountryIDs,'','') ))'
END
IF (LEN(#IndustryIDs) >0)
BEGIN
SET #sql = #sql + N'AND (b.IndustryPreferenceID IN (Select Value from fnSplitVariable(#IndustryIDs,'','') ))'
END
IF (LEN(#KeywordSearch) > 0)
BEGIN
SET #sql = #sql + N' AND (' + #KeywordSearch + ')'
END
SET #sql = #sql + N') ORDER BY ModifiedDate desc'
--select #sql
exec sp_executesql #sql
END
DECLARE #SQL AS NVARCHAR(MAX)
SET #SQL = 'SELECT DISTINCT
UserID,
ResumeID,
CASE a.Confidential WHEN 1 THEN ''Confidential'' ELSE LastName + '','' + FirstName END as ''Name'',
a.Description ''ResumeTitle'',
CurrentTitle,
ModifiedDate,
CASE ISNULL(b.SalaryRangeID, ''0'') WHEN ''0'' THEN CAST(SalarySpecific as nvarchar(8)) ELSE c.Description END ''Salary'',
h.Description ''Relocate'',
i.Description + ''-'' + j.Description + ''-'' + k.Description ''Location''
FROM dbo.Resume a JOIN dbo.Candidate b ON a.CandidateID = b.CandidateID
LEFT OUTER JOIN SalaryRange c ON b.SalaryRangeID = c.SalaryRangeID
JOIN EducationLevel e ON b.EducationLevelID = e.EducationLevelID
JOIN CareerLevel f ON b.CareerLevelID = f.CareerLevelID
JOIN JobType g ON b.JobTypeID = g.JobTypeID
JOIN WillingToRelocate h ON b.WillingToRelocateID = h.WillingToRelocateID
JOIN City i ON b.CityID = i.CityID
JOIN StateProvince j ON j.StateProvinceID = b.StateProvinceID
JOIN Country k ON k.CountryID = b.CountryID
WHERE (b.CityID IN (' + #CityIDs + '))
AND (b.StateProvinceID IN (' + #ProvinceIDs + '))
AND (b.CountryID IN (' + #CountryIDs + '))
AND (b.IndustryPreferenceID IN (' + #IndustryIDs + '))'
EXEC #SQL
You could do a split on the id's that are coming in to the store procedure. So consider this split function:
CREATE FUNCTION [dbo].[Split]
(
#String NVARCHAR(4000),
#Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
WITH Split(stpos,endpos)
AS(
SELECT 0 AS stpos, CHARINDEX(#Delimiter,#String) AS endpos
UNION ALL
SELECT endpos+1, CHARINDEX(#Delimiter,#String,endpos+1)
FROM Split
WHERE endpos > 0
)
SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
'Data' = SUBSTRING(#String,stpos,COALESCE(NULLIF(endpos,0),LEN(#String)+1)-stpos)
FROM Split
)
Then you could write your where statement like this:
WHERE
EXISTS(SELECT NULL FROM dbo.Split(#CityIDs,',') AS city
WHERE city.Data=b.CityID)
AND EXISTS(SELECT NULL FROM dbo.Split(#ProvinceIDs,',') AS Province
WHERE Province.Data=b.StateProvinceID)
AND EXISTS(SELECT NULL FROM dbo.Split(#CountryIDs,',') AS Country
WHERE Country.Data=b.CountryID)
AND EXISTS(SELECT NULL FROM dbo.Split(#IndustryIDs,',') AS Industry
WHERE Industry.Data=b.IndustryPreferenceID)

Stored Procedure with dynamic SQL returns wrong data

For the fiscal year parameter I have 2010, 2011 and 2012 as an option but no matter what year I select the "submitted On" column still shows 2011 dates. I want for example if I select 2010, only data submitted on 2010 should show and likewise for all the years. Any help?
set #sqlstr = '
Select
[SchoolName] As [School Name],
Status= CASE WHEN PS.PrivateSchoolID = Ed.PrivateSchoolID THEN ''Submitted''
ELSE ''Not Submitted''END,
[Submitted By]= CASE WHEN PS.PrivateSchoolID = Ed.PrivateSchoolID
THEN [FirstName] + '' '' + [LastName] ELSE NULL END,
[Submitted On]= CASE WHEN PS.PrivateSchoolID = Ed.PrivateSchoolID
THEN Convert( Varchar(10), Ed.CreatedDate, 101 ) ELSE NULL END
From EnrollmentDateSchool Ed Right Outer Join
(select FP.FiscalYear, PrivateSchool.* from PrivateSchool
INNER JOIN FiscalYearPrivateSchool FP
ON PrivateSchool.PrivateSchoolID = FP.PrivateSchoolID) PS
ON Ed.PrivateSchoolID = PS.PrivateSchoolID Left Outer Join
Finance.dbo.Person P ON Ed.CreatedBy = P.PersonID
Where (FiscalYear = '+convert(varchar, #FiscalYear)+') AND (PS.IsActive = 1)'
IF (#SchoolID != -1)
set #sqlstr = #sqlstr + ' AND SchoolID ='+ convert(varchar, #SchoolID)
IF (#Status = -1)
set #sqlstr = #sqlstr + ' AND (PS.PrivateSchoolID = PS.PrivateSchoolID' + ')'
ELSE IF (#Status = 1)
set #sqlstr = #sqlstr + ' AND (PS.PrivateSchoolID = Ed.PrivateSchoolID' + ')'
ELSE
set #sqlstr = #sqlstr + 'AND (Ed.PrivateSchoolID is null' + ')'
SET #sqlstr = #sqlstr + 'ORDER BY SchoolName'
EXEC(#sqlstr)
END
There is no need at all for dynamic sql here.
SELECT
...
FROM ...
WHERE FiscalYear=#FiscalYear AND PS.IsActive=1
AND (#SchoolID = -1 OR SchoolID=#SchoolID)
AND ( (#Status = -1)
OR (#Status=1 AND PS.PrivateSchoolID = Ed.PrivateSchoolID)
OR (Ed.PrivateSchoolID is null) )
ORDER BY SchoolName