I want to declare multiple variables based on user input and use them all as conditions in a WHERE clause. I have the variables hard set to the values I want right now for testing. I plan on using the #Well and #Analyst variables in a similar manner in the future. Here is the code:
DECLARE #Analysis nvarchar(20)
DECLARE #SQLQuery nvarchar(max)
DECLARE #Formation nvarchar(50)
DECLARE #Well nvarchar(30)
DECLARE #Analyst nvarchar(50)
SET #Analysis = 'Elemental Analysis'
SET #Formation = 'Bruce'
SET #SQLQuery = N'SELECT TB_Projects.JobLog#, TB_Projects.ProjName, COUNT(TB_Samples.Sample#) AS [Total Samples]
FROM TB_Projects INNER JOIN TB_Samples ON TB_Projects.JobLog# = TB_Samples.JobLog#
WHERE TB_Samples.['+ #Analysis +'] = 1 AND TB_Projects.Formation ='+#Formation+' GROUP BY TB_Projects.JobLog#, TB_Projects.ProjName'
EXECUTE(#SQLQuery)
I receive the following error with this code:
Msg 207, Level 16, State 1, Line 3
Invalid column name 'Bruce'.
'Bruce' should be the value returned for the column TB_Projects.Formation, it's not a column name. Why doesn't this work?
You have this in the string:
TB_Projects.Formation = '+#Formation+'
This is turned into:
TB_Projects.Formation = Bruce
See the problem? If you printed out the string before you ran it, the problem would probably be obvious.
The simplest solution is:
TB_Projects.Formation = '''+#Formation+'''
That will add single quotes.
A better solution is to use sp_executesql with a parameter for the value.
you need to wrap Formation value in single quotes:
SET #SQLQuery = N'SELECT TB_Projects.JobLog#, TB_Projects.ProjName, COUNT(TB_Samples.Sample#) AS [Total Samples]
FROM TB_Projects INNER JOIN TB_Samples ON TB_Projects.JobLog# = TB_Samples.JobLog#
WHERE TB_Samples.['+ #Analysis +'] = 1 AND TB_Projects.Formation ='''+#Formation+''' GROUP BY TB_Projects.JobLog#, TB_Projects.ProjName'
EXECUTE(#SQLQuery)
Related
Edit:
I tried to replace:
#LocationIDs NVARCHAR(MAX) = null,
with
#LocationIDs LocationIdArray READONLY,
but now I get an error saying:
Must declare the scalar variable "#LocationIDs".
--END EDIT--
I have this stored procedure that I need to address:
CREATE PROCEDURE [dbo].[spAP_GetTechnician_Door_Unlock]
#LocationIDs NVARCHAR(MAX) = NULL,
#AlarmDateFrom DATETIME = NULL,
#AlarmDateTo DATETIME = NULL,
#TechnicianID INT = NULL,
#LocationId INT = NULL
AS
BEGIN
IF (#LocationIDs = 'x')
BEGIN
SELECT #LocationIDs = dbo.fn_GetAll_Location_Id()
END
DECLARE #query NVARCHAR(MAX);
SET #query = 'WITH CTE AS (SELECT ROW_NUMBER() OVER(ORDER BY al.Alarm_Log_ID desc)AS RowNumber,
isnull(t.Technician_ID,'''')[Technician_ID], (isnull(t.Last_Name,'''') +'' ''+ isnull(t.Name,'''')) TechnicianName,isnull(t.Emailid,'''') as EmailID,isnull(t.phone,'''') as Phone,dbo.fNAP_DateFormat(al.Alarm_date) as Alarm_date,
Al.Site_ID,s.Name as SiteName,al.point_Address,l.location_Name,l.Location_ID ,shs.StatusData
from z_EntityMast_Alarm_Log al
left join z_EntityMast_Technician t on al.Technician_ID=t.Technician_id
left join z_EntityMast_Site s on s.Site_ID=al.Site_ID
left join z_EntityMast_Location l on s.Location_ID=l.Location_id
left join z_EntityMast_Site_Hardware_Status shs on s.site_id=shs.siteid
left join z_SysVar_Alarm_Type_00004 at on al.Alarm_Type=at.ID
where at.Is_Linkable=1 and al.Alarm_Type !=70'
if(isnull(#LocationId,0)!=0)
set #query=#query+' and s.Location_ID ='+convert(varchar(12),#LocationId);
else
set #query=#query+' and s.Location_ID in ('+#LocationIDs+')';
if(isnull(#AlarmDateFrom,0)!=0 and #AlarmDateFrom !='')
set #query=#query+'and (DATEDIFF(DAY,'''+convert(varchar(30),#AlarmDateFrom)+''', al.Alarm_Date)>=0 and DATEDIFF(DAY,'''+convert(varchar(30),#AlarmDateTo)+''',al.Alarm_Date)<=0)';
if(isnull(#TechnicianID,0)!=0)
set #query=#query+'and t.Technician_ID ='+ convert(varchar(10),#TechnicianID);
set #query=#query + ')';
set #query=#query +'select * from CTE ';
-- PRINT #query
EXEC (#query)
END
I need to optimize it and I have to use table valued parameters for the LocationIds parameter, instead of it using NVARCHAR(MAX).
The problem is in this line of code:
SET #query = #query + ' and s.Location_ID in ('+#LocationIDs+')';
My question is: how does one replace that line of code and replace it with a table valued parameter in such a way that the concatenation would still work?
Thanks!
SET #query = #query + ' and s.Location_ID in ('+#LocationIDs+')';
My question is: how does one replace that line of code and replace it
with a table valued parameter in such a way that the concatenation
would still work?
Suppose your LocationIdArray has this definition:
create type LocationIdArray as table (LocationId int);
Then your IN should look like this:
and s.Location_ID in (select LocationId from #LocationIDs)
This won't work within your exec because #LocationID is in the outer scope respect to exec, you can pass it as a parameter in sp_executesql but the best you can do is to rewrite your dynamic query to static one as there is no reason to use dynamic code here.
In a query with a where, I need to be able to still thorw all rows as a result.
For example:
declare #Crit nvarchar(15)
set #Crit = 'Package'; --as an example
IF #Crit = ''
¿¿??
SELECT * FROM Criterios
WHERE CRITERIO = #Crit
In this case, if I set the value of #Crit to 'Package', it works like a normal query, but if I do not set any value #Crit = '', and the query throws nothing.
What I am trying to do inside the if, is to expecify a value that equals to everything, sort of the * from selects.
Is there anyway to achieve this?
You're talking about a conditional WHERE clause, which can be achieved a number of ways.
One approach is:
SELECT *
FROM Criterios
WHERE (CRITERIO = #Crit OR #Crit = '')
Another way is to use dynamic SQL:
DECLARE #SQL NVARCHAR(1000)
SET #SQL = 'SELECT * FROM Criterios'
IF (#Crit <> '')
SET #SQL = #SQL + ' WHERE CRITERIO = #Crit'
EXECUTE sp_executesql #SQL, N'#Crit VARCHAR(10)', #Crit
There are pros and cons to each, depending on scenario. Dynamic SQL typically less readable, more complicated to write (and need to be careful about SQL injection) but can give you better execution plans especially in more complex scenarios, as you only end up with the exact conditions you need.
The typical way doing this is by not passing a value for your parameter.
SELECT * FROM Criterios
WHERE CRITERIO = #Crit
OR #Crit IS NULL
Be careful with this pattern though. You can create some serious performance problems. Here is a great article that goes into more detail about how to solve that issue.
http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/
If you are stuck using an empty string you can change the above slightly to.
SELECT * FROM Criterios
WHERE CRITERIO = #Crit
OR #Crit = ''
You can use a dynamic SQL to do this. If #crit is null then the where clause is excluded, if it is not null it will be in the where clause.
DECLARE #crit nvarchar(15) = 'Package'
,#sqlStatement nvarchar(max) =
'SELECT * FROM Criterios'
;
SET #sqlStatement = CONCAT(#sqlStatement,'WHERE CRITERIO = ' +#crit)
EXEC sp_executesql #sqlStatement;
Consider using the COALESCE function to return the first non-null value, as below
declare #Crit nvarchar(15)
set #Crit = 'Package'; --as an example
IF #Crit = ''
BEGIN
SET #Crit = NULL
END
SELECT * FROM Criterios
WHERE CRITERIO = COALESCE(#Crit, CRITERIO)
I am trying to do the following where the #POtable variable and #ProdID will be passed to the stored procedure. The #POtable name shall be one of the Order table in the database, that I shall select randomly. I know that the following statement is incorrect, what would be the right syntax?
Select *
From Products
Join #POtable On Products.ProdID = #POtable.ProdID
Where ProdID = #ProdID
Thanks for helping.
As said in comments,you can't use variables in Tablenames,column names,Databasename,function names...
To use variables you have to use dynamic SQL..
Declare #potable Nvarchar(200);
Set #potable='sometablename';
Declare #SQL nVarchar(max)
Set #SQL='
Select *
From Products p
Join '+QUOTENAME(#POtable)+' po On p.ProdID = po.ProdID
Where p.ProdID = '+#ProdID;
Exec(#SQL)
I'm working with SQL Server 2014 Express with FileTable. I'm trying to select documents from the filetable (unstructured, pdf) based on whether they contain specific keywords based on the registration mark of an aircraft:
--SET VARIABLE FOR A REGISTRATION MARK
DECLARE #Reg nvarchar(10)
SET #Reg = 'PH-BGA'
--SET VARIABLE FOR MANUFACTURER OF REGISTRATION MARK
DECLARE #Manufacturer nvarchar(10) = NULL
SELECT FleetInfoKLM.Manufacturer FROM FleetInfoKLM WHERE FleetInfoKLM.Reg = #Reg;
SET #Manufacturer = '""'
--SET VARIABLE FOR FAMILY OF REGISTRATION MARK
DECLARE #Family nvarchar(10) = NULL
SELECT FleetInfoKLM.Family FROM FleetInfoKLM WHERE FleetInfoKLM.Reg = #Reg;
SET #Family = '""'
--SET VARIABLE FOR SERIES OF REGISTRATION MARK
DECLARE #Series nvarchar(10) = NULL
SELECT FleetInfoKLM.Series FROM FleetInfoKLM WHERE FleetInfoKLM.Reg = #Reg;
SET #Series = '""'
--SELECT MAINTENANCE DOCUMENTS BASED ON VARIABLES FOR MANUFACTURER, FAMILY AND SERIES
SELECT MaintenanceDocumentation.name FROM MaintenanceDocumentation
WHERE ((#Manufacturer = '""') AND CONTAINS(file_stream, #Manufacturer))
AND ((#Family = '""') AND CONTAINS(file_stream, #Family))
AND ((#Series = '""') AND CONTAINS(file_stream, #Series))
Without SET #VARIABLE = '""' I get the error Msg 7645 Null or empty full-text predicate. Hence I added the SET #VARIABLE = '""' as it was found as a solution in this question 7645 Null or empty full-text predicate. However, now the result set is empty (no documents found), while I know that there should be results. The variables are properly set, in this example as Boeing, 737 and 800 respectively. If I replace the variables as a string (e.g. 'Boeing') as an argument in CONTAINS, I do get the expected results.
Anyone got a clue what the problem is? Have been Googling for hours without result other than avoiding the error with SET #VARIABLE = '""'.
Okay, I finally fixed it by altering the SET statement to SET #variable = (SELECT ..):
--SET VARIABLE FOR A REGISTRATION MARK
DECLARE #Reg nvarchar(10);
SET #Reg = 'PH-BGO';
--SET VARIABLE FOR MANUFACTURER OF REGISTRATION MARK
DECLARE #Manufacturer nvarchar(100);
SET #Manufacturer = (SELECT FleetInfoKLM.Manufacturer FROM FleetInfoKLM WHERE FleetInfoKLM.Reg = #Reg);
--SET VARIABLE FOR FAMILY OF REGISTRATION MARK
DECLARE #Family nvarchar(100);
SET #Family = (SELECT FleetInfoKLM.Family FROM FleetInfoKLM WHERE FleetInfoKLM.Reg = #Reg);
--SET VARIABLE FOR SERIES OF REGISTRATION MARK
DECLARE #Series nvarchar(100);
SET #Series = (SELECT FleetInfoKLM.Series FROM FleetInfoKLM WHERE FleetInfoKLM.Reg = #Reg);
--SHOW LOCAL VARIABLES VALUES
SELECT #Manufacturer;
SELECT #Family;
SELECT #Series;
--SELECT MAINTENANCE DOCUMENTS BASED ON VARIABLES FOR MANUFACTURER, FAMILY AND SERIES
SELECT MaintenanceDocumentation.name FROM MaintenanceDocumentation
WHERE MaintenanceDocumentation.path_locator IS NOT NULL
AND CONTAINS(file_stream, #Manufacturer)
AND CONTAINS(file_stream, #Family)
AND CONTAINS(file_stream, #Series);
No need for the SET #variable = '""' statements.
Below is the code where I am getting a columns name dynamically(example F8 is the column name) and storing it in #whcode. What i need is the value that is stored in this column for the where condition specified below. I can see the value stored in the column is 2 but I cannot get it. What it is returning me is the column name itself. How can I get the value in the column. Please help.
declare #count1 int
set #count1 = (select min(srno) from TEMP_STOCK_uPDATE)
declare #whcode varchar(20)
select * from TEMP_STOCK_uPDATE where srno='16091'
set #whcode=(SELECT COLUMN_NAME
FROM Ecata_New.INFORMATION_SCHEMA.COLUMNS
where Table_Name = 'TEMP_STOCK_uPDATE'
and COLUMN_NAME =(select whcode from dbo.temp_stock_map where func=(select func from dbo.temp_stock_map where sr_no=6)))
--select #whcode as 'abcd'
select #whcode as 'abc'
from TEMP_STOCK_uPDATE
where
F1=(select F1 from dbo.TEMP_STOCK_uPDATE where srno=#count1)
You can build your SQL statement dynamically to do this. Build your statement in a varchar and then EXEC it.
DECLARE #SQL VARCHAR(4000)
SET #SQL = 'select ' + #whcode + ' from TEMP_STOCK_uPDATE where F1=(select F1 from dbo.TEMP_STOCK_uPDATE where srno=#count1)'
EXEC (#SQL)