declare #pid int
declare #mid int
declare #tableName varchar(10)
declare #query nvarchar(1000)
declare #subquery nvarchar(300)
set #pid = 1
set #mid = 2
set #query = 'Select * from '+#tableName+' where'
if(#pid is not null)
begin
set #query = #query+' pid ='+#pid+' and'
end
if(#mid is not null)
begin
set #query = #query+' mid ='+#mid+' and'
end
if #pid and #mid are not null, get added into the query. If #pid and #mid null, I want to remove 'where' from query. Same for 'and' also, if both get selected.
set #subquery = select right('''+#query+''',5)
if(#subquery = 'where')
begin
print #query
-- execute sp_executesql #query
end
but unable to compare those, in if clause. Does I need to execute #subquery. If yes, how to take that value?
if #pid and #mid are not null,get added into the query.
If #pid and #mid null,I want to remove 'where' from query.
both get selected.
I think you are looking for something like this:
WHERE 1 = 1
AND (#mid IS NULL OR mid = #mid )
AND (#pid IS NULL OR pid = #pid)
If #pid and #mid are not NULLs, the the previous WHERE would be:
WHERE 1 = 1
AND mid = #mid
AND pid = #pid
Therefore they get added into the query.
If #pid and #mid are NULLs, then the WHERE clause would become:
WHERE 1 = 1
Therefore it would be like it it doesn't exist.
Note that, I used WHERE 1 = 1 in case that the two #pid and #mid are both NULLs, the query is keep working and doesn't break.
Related
I am trying to execute this conditional statement from a string, but I always get errors.
Is there a way to CAST or CONVERT this varchar to a logical string?
I am using SQL Server 2000
Declare #myQuery varchar(100)
SET #myQuery= '3043=3043 OR ( 3043=97 AND 0=8065 ) OR 3043=1853 OR 3043=5749'
if(#myQuery)
select 'ok'
I want to execute this:
These conditions need to go in a where clause so they are properly interpreted. Something like:
declare #myquery varchar(100)
set #myquery = '3043 = 3043 or (3043 = 97 and 0=8065) or 3043 = 1853 or 3043 = 5749'
exec('select ''ok'' where ' + #myquery)
If you want to use it in IF condition, you need to set the flag using sp_executesql as below:
Declare #myQuery nvarchar(100)
Declare #flag tinyint
SET #myQuery= 'select #flag = 1 where 3043=3043 OR ( 3043=97 AND 0=8065 ) OR 3043=1853 OR 3043=5749'
exec sp_executesql #myQuery, N'#flag tinyint output', #flag = #flag output
if(#flag = 1)
select 'ok'
This is my code:
DECLARE #LoopCounter INT = 1,#max INT,#table nvarchar(100),#academic nvarchar(100)
SELECT #max = max(id)
FROM #tablelist
WHILE(#LoopCounter <= #max)
BEGIN
SET #table = (SELECT TABLE_NAME
FROM #tablelist WHERE id = #LoopCounter)
SET #academic = (SELECT F6
FROM #table WHERE F5 = Academic)
SET #LoopCounter = #LoopCounter + 1
END
where #tablelist is a list of all my tables in the database that are relevent.
The step:
SET #academic = (SELECT F6
FROM #table WHERE F5 = Academic)
does not work... I've tried with sp_execute but I get thrown back standard errors, at the moment the error is 'Must declare the standard variable '#table'. I have also tried an EXEC but it doesn't like that either.
What I want to do is define #academic to be a value from the #table The problem I'm having is the SET does not like being from #table.
Any help would be fab!
I think you want dynamic SQL:
DECLARE #LoopCounter INT = 1,
#max INT,#table nvarchar(100),
#academic nvarchar(100);
DECLARE #SQL NVARCHAR(MAX);;
SELECT #max = max(id)
FROM #tablelist;
WHILE(#LoopCounter <= #max)
BEGIN
SET #table = (SELECT TABLE_NAME FROM #tablelist WHERE id = #LoopCounter) ;
SET #SQL = '
SELECT #academic = F6
FROM [table]
WHERE f5 = 'Academic'
';
SET #SQL = REPLACE(#SQL, '[Table]', #table_name);
EXEC sp_executesql #SQL,
N'#academic NVARCHAR(100)',
#academic=#academic;
SET #LoopCounter = #LoopCounter + 1
END;
All that said, this is not an example of good coding (even ignoring the fact that I'm not escaping the table name).
You should not have multiple tables with the same columns, distinguished only by a variant of the name. Instead, you should have a single table with all the rows, and perhaps an additional column or two for identifying the columns.
Having to use dynamic SQL can illustrate a problem with the data model. And in this case, I think that it does.
I have a function which I have created in SQL but I am getting this error 'SQL server issue - Create Function must be the only statement in the batch'. I checked other similar topics but couldn't find anything wrong. I am using SQL Server 2012
CREATE FUNCTION GETLLPATH(#objectid FLOAT)
RETURNS VARCHAR(4000)
AS
BEGIN
DECLARE #dir VARCHAR(MAX);
DECLARE #obj_id FLOAT;
DECLARE Name_Cursor CURSOR LOCAL FOR
SELECT A.Name, A.ParentID FROM OTCS_User.DTree A
WHERE A.DataID = #obj_id;
DECLARE
SET #dir = NULL;
SET #obj_id = #objectid;
WHILE 1=1 BEGIN
OPEN Name_Cursor;
FETCH Name_Cursor INTO #name;
IF ##FETCH_STATUS <> 0 BREAK or #name_NAME = 'Enterprise';
IF #dir IS NOT NULL BEGIN
SET #dir = (ISNULL(#name_NAME, '') + ':' + isnull(#dir, '')) ;
END
IF #dir IS NULL BEGIN
SET #dir = #name_NAME;
END
SET #obj_id = #name_PARENTID;
CLOSE Name_Cursor;
DEALLOCATE Name_Cursor;
END;
return(#dir);
END;
GO
I am also getting error for variables as 'Must declare Scalar variable', In the end there is one more error - 'Expecting conversation', request you to please help.
I believe you just have some bad code.
Try this:
CREATE FUNCTION GETLLPATH(
#objectid FLOAT
)
RETURNS VARCHAR(4000)
AS
BEGIN
DECLARE #dir VARCHAR(MAX);
DECLARE
#obj_id FLOAT
, #name_NAME VARCHAR(50) -- or whatever your field size is.
, #name_PARENTID VARCHAR(50) -- again, whatever your field size is.
DECLARE Name_Cursor CURSOR LOCAL FOR
SELECT A.Name, A.ParentID FROM OTCS_User.DTree A WHERE A.DataID = #obj_id;
SET #dir = NULL; -- redundant.
SET #obj_id = #objectid; -- this can be set at declaration ( e.g. DELARE #obj_id FLOAT = #obj_id ).
WHILE ( 1 = 1 ) BEGIN
OPEN Name_Cursor;
FETCH Name_Cursor INTO #name;
IF ( ##FETCH_STATUS <> 0 OR #name_NAME = 'Enterprise' )
BREAK;
IF ( #dir IS NOT NULL ) BEGIN
SET #dir = (ISNULL(#name_NAME, '') + ':' + isnull(#dir, '')) ;
END
IF #dir IS NULL BEGIN
SET #dir = #name_NAME;
END
SET #obj_id = #name_PARENTID;
CLOSE Name_Cursor;
DEALLOCATE Name_Cursor;
END
RETURN #dir;
END
GO
On a personal note, I am never fond of using WHILE (1=1). Are you guaranteed to have an exit?
Also, I would highly recommend using an alternative to a cursor. Perhaps use a TABLE variable and loop through that like so:
CREATE FUNCTION GETLLPATH(
#objectid FLOAT
)
RETURNS VARCHAR(4000)
AS
BEGIN
-- declare variables --
DECLARE #id INT
, #dir VARCHAR(MAX)
, #obj_id FLOAT = #objectid
, #name_NAME VARCHAR(50)
, #name_PARENTID VARCHAR(50)
-- declare table variable --
DECLARE #data TABLE( [name] VARCHAR(50), [parent_id] VARCHAR(50), [id] INT IDENTITY (1,1) );
-- insert data --
INSERT INTO #data ( [name], [parent_id] )
SELECT A.Name, A.ParentID FROM OTCS_User.DTree A WHERE A.DataID = #obj_id;
-- for-each row... --
SET #id = 1;
WHILE ( #id <= ( SELECT MAX( id ) FROM #data ) )
BEGIN
-- current row --
SELECT
#name_NAME = [name]
, #name_PARENTID = [parent_id]
FROM #data WHERE [id] = #id;
-- do your work here...
-- next row --
SET #id = ( #id + 1 );
END
RETURN #dir;
END
GO
There are a couple of syntax errors even before I test your query:
The word 'DECLARE' should not appear in the middle without a variable name,
#name_Name and #name_PARENTID are undeclared
DECLARE #name_NAME varchar, #name_PARENTID int
(check for the variable types according to the source table)
IF ##FETCH_STATUS <> 0 BREAK or #name_NAME = 'Enterprise' is incorrect
IF ##FETCH_STATUS <> 0 or #name_NAME = 'Enterprise'
BREAK
"Create Function must be the only statement in the batch" - usually
means there is some syntax error.
This is, honestly, a total guess, and (most importantly) completely untested; due to the absence of sample data and expected results.
Anyway, like I said in the comments, a CURSOR and a Scalar-value Function are both really bad performers here. If you're trying to simply delimit your data with a colon (:), then you can use STUFF and FOR XML PATH.
Like I said, this is completed untested, but might get you on the right path:
CREATE FUNCTION dbo.GetllPath (#objectID int) --Is it really a float? I've used an int
RETURNS table
AS RETURN
SELECT STUFF((SELECT ':' + DT.[Name]
FROM OTCS_User.DTree DT
WHERE DT.DataID = #obj_id
--ORDER BY SOMETHING HERE!!!
FOR XML PATH('')),1,1,'') AS llPath;
GO
I want to add a record in a aTable using a stored procedure. But before that I need to check if it's a duplicate entry. If its not duplicate then only add to aTable.
I have one stored procedure that does two things
checking for duplicate
and if not duplicate then only add the record.
In this stored procedure, I have
#count variable (scope is the stored procedure itself)
column values as parameters (7-8 as varchar datatype)
I am setting #count to 1 and then building the dynamic #qry string that will hold the #count value as follows using #column values
CREATE PROCEDURE sp_aTable_ADD
#col1 varchar(20) = null,
#col2 varchar(20) = null,
#col3 varchar(20) = null,
...
#colN varchar(20) = null,
AS
DECLARE #count int
SET #count = 1
DECLARE #qry nvarchar(max)
SET #qry = 'SELECT #count = count(*) FROM aTable WHERE '
IF #col1 IS NOT EMPTY
BEGIN
SET #qry = #qry + ' col1 = '+ ''''+#col1+''''
END
IF #col2 IS NOT EMPTY
BEGIN
SET #qry = #qry + ' AND col2 = '+ ''''+#col2+''''
END
...
...
IF #colN IS NOT EMPTY
BEGIN
SET #qry = #qry + ' colN = '+ ''''+#colN+''''
END
/*once all the stored procedure variables are done processing, close the sql*/
SET #qry = #qry + ' )'
/*final #qry value would end up looking like as follows
SELECT #count = count(*)
FROM aTable
WHERE (col1 = 'val1' AND col2 = 'val2' AND col3 = 'val3')*/
Now, within this stored procedure I want to know the value of #count and if it is '0' then continue with the 'INSERT' procedure. I am stuck at getting '#count' value within this stored procedure.
Any thoughts?
Why do you want to use dynamic sql for this just Write a query with a WHERE Clause something like this
CREATE PROCEDURE usp_aTable_ADD --<-- Use usp
#col1 varchar(20) = null,
#col2 varchar(20) = null,
#col3 varchar(20) = null,
...
#colN varchar(20) = null,
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Count INT;
SELECT #count = count(*)
FROM aTable
WHERE
(#col1 IS NULL OR Col1 = #col1)
AND (#col2 IS NULL OR Col2 = #col2)
AND (#col3 IS NULL OR Col3 = #col3)
.
.
AND (#colN IS NULL OR ColN = #colN)
--And then at the end of your Proc just return the #Count Variable
RETURN #count;
END
Use an output parameter:
EXECUTE sp_executesql #qry, N'#Count INT OUTPUT', #Count OUTPUT;
For a simple test:
DECLARE #count INT;
DECLARE #qry NVARCHAR(MAX) = 'SELECT #Count = 10';
EXECUTE sp_executesql #qry, N'#Count INT OUTPUT', #Count OUTPUT;
SELECT #Count;
Finally, you never open the parentheses in your WHERE Clause:
SET #qry = 'SELECT #count = count(*) FROM aTable WHERE '
But you go on to close them:
SET #qry = #qry + ' )'
Also, if all your parameters are null even if you did open the parentheses you will get an incorrect syntax error since your SQL will be:
SELECT #count = count(*) FROM aTable WHERE ();
Or if #Col1 is NULL You will get:
SELECT #count = count(*) FROM aTable WHERE AND col2 = col2();
You can avoid this by firstly removing the parenthesis. WHERE A = 1 means exactly the same as WHERE (A = 1), and by adding a meaningless where first:
SET #qry = 'SELECT #count = count(*) FROM aTable 1 = 1 ';
IF #col1 IS NOT EMPTY
BEGIN
SET #qry = #qry + ' AND col1 = '+ ''''+#col1+''''
END
Finally I would recommend further parameterising your query.
SET #qry = 'SELECT #count = count(*) FROM aTable WHERE 1 = 1 '
DECLARE #ParamDef NVARCHAR(MAX) = '#Col1 VARCHAR(20), #Col2 VARCHAR(20), #Col3 VARCHAR(20), #Count INT OUTPUT';
IF #Col1 IS NOT NULL
SET #qry = #qry + ' AND Col1 = #Col1';
IF #Col2 IS NOT NULL
SET #qry = #qry + ' AND Col2 = #Col2';
IF #Col3 IS NOT NULL
SET #qry = #qry + ' AND Col3 = #Col3';
EXECUTE sp_executesql #qry, #ParamDef, #Col1, #Col2, #Col3, #Count OUTPUT;
Working Examples on SQL Fiddle
I want get the value from Exec(#sql) and assign to #Rowcount(int)
Here is my query:
'SET #RowCount = (select count(*)
FROM dbo.Comm_Services
WHERE CompanyId = '+cast(#CompanyId as char)+' and '+#condition+')'
On the one hand you could use sp_executesql:
exec sp_executesql N'select #rowcount=count(*) from anytable',
N'#rowcount int output', #rowcount output;
On the other hand you could use a temporary table:
declare #result table ([rowcount] int);
insert into #result ([rowcount])
exec (N'select count(*) from anytable');
declare #rowcount int = (select top (1) [rowcount] from #result);
DECLARE #nReturn int = 0
EXEC #nReturn = Stored Procedure
Was playing with this today... I believe you can also use ##ROWCOUNT, like this:
DECLARE #SQL VARCHAR(50)
DECLARE #Rowcount INT
SET #SQL = 'SELECT 1 UNION SELECT 2'
EXEC(#SQL)
SET #Rowcount = ##ROWCOUNT
SELECT #Rowcount
Then replace the SELECT 1 UNION SELECT 2 with your actual select without the count. I'd suggest just putting 1 in your select, like this:
SELECT 1
FROM dbo.Comm_Services
WHERE....
....
(as opposed to putting SELECT *)
Hope that helps.
that's my procedure
CREATE PROC sp_count
#CompanyId sysname,
#codition sysname
AS
SET NOCOUNT ON
CREATE TABLE #ctr
( NumRows int )
DECLARE #intCount int
, #vcSQL varchar(255)
SELECT #vcSQL = ' INSERT #ctr FROM dbo.Comm_Services
WHERE CompanyId = '+#CompanyId+' and '+#condition+')'
EXEC (#vcSQL)
IF ##ERROR = 0
BEGIN
SELECT #intCount = NumRows
FROM #ctr
DROP TABLE #ctr
RETURN #intCount
END
ELSE
BEGIN
DROP TABLE #ctr
RETURN -1
END
GO
If i understand you correctly, (i probably don't)
'SELECT #RowCount = COUNT(*)
FROM dbo.Comm_Services
WHERE CompanyId = ' + CAST(#CompanyId AS CHAR) + '
AND ' + #condition