how I can hide displaying result of exec command - sql

WHILE #nxt < #rc
BEGIN
set #sql = (select Rec from DmsRec where row=#nxt)
use TestDB1
exec (#sql)
select #rc_child = ##ROWCOUNT
use MyTempDB
if #rc_child = 0
begin
insert into DMSResults
select DOCID from DmsRec where row=#nxt
end
set #nxt = #nxt + 1
END
My Question is how I can hide displaying result of exec command.
(using Sql Server 2008r2) Above query is small part of complete procedure.
Accessing multiple conditions,value and multiple databases I generate a select statement and stored in Rec Field into table DmsRec
After generating require Select.... statement I stored it into table DmsRec.
e.g. SELECT ACCD FROM M_TABLE WHERE 1=1 and ACCD='0034422'.
This select statement which is stored as a value in table DmsRec
want to execute in different database.
So I used use command and change the database name, access the recordset.
If the executed sql (return 0 row) then run the insert command which is executed in different database.
With this I came to know wether Inserted docid into DMSResults is those tranaction whose master is not avalialbel.
It works perfectly but can not hide displaying records of exec command.
I run exec(#sql) is only to check whether it is returning any row or not.
and stored rowcount value into variable.
But do not want to display records in grid (at the same time result {effected rows} should stored in variable).
Without changing options in SSMS manually i.e.
Tools/Options, Query Results/SQL Server/Results to XX, check "Discard results after query executes"

EDIT - based on comments below
You can use sp_executesql and pass parameters to it, even OUTPUT parameters.
Here's an example - you will need to amend the SQL query you're storing slightly
DECLARE #SQL NVARCHAR(MAX), #Rows INT, #nxt INT = 1
CREATE TABLE DmsRec (row INT, rec NVARCHAR(10))
INSERT INTO DmsRec(row, rec)
VALUES(1, 1)
SET #SQL = 'IF EXISTS ( SELECT rec FROM dbo.DmsRec WHERE row = #nxt) SET #Rows = 1 ELSE SET #Rows = 0' --+'; SELECT #Rows = ##ROWCOUNT'
EXEC sys.sp_executesql #sql, N'#nxt INT, #Rows INT OUTPUT', #nxt, #Rows OUTPUT;
SELECT #Rows
SET #nxt = 0 -- record doesn't exist
SET #SQL = 'IF EXISTS ( SELECT rec FROM dbo.DmsRec WHERE row = #nxt) SET #Rows = 1 ELSE SET #Rows = 0'
EXEC sys.sp_executesql #sql, N'#nxt INT, #Rows INT OUTPUT', #nxt, #Rows OUTPUT;
SELECT #Rows
You can then use #Rows variable to determine whether you need to insert a new record or not.
If #Rows = 1
BEGIN
--INSERT record
END

Related

How to use results from an SQL Query as a list to delete (WSUS) updates

My problem is that I want to use the results from a SELECT query as the input values for a Stored Procedure. The issue is that the SP will only accept Scalar values, and I do not know SQL and so have been struggling to find a workaround or solution.
I want to modify the following Proc to accept multiple values to be used within the query:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spDeleteUpdateByUpdateID]
#updateID UNIQUEIDENTIFIER
AS
SET NOCOUNT ON
DECLARE #localUpdateID INT
SET #localUpdateID = NULL
SELECT #localUpdateID = LocalUpdateID FROM dbo.tbUpdate WHERE UpdateID = #updateID
IF #localUpdateID IS NULL
BEGIN
RAISERROR('The update could not be found.', 16, 40)
RETURN(1)
END
IF EXISTS (SELECT r.RevisionID FROM dbo.tbRevision r
WHERE r.LocalUpdateID = #localUpdateID
AND (EXISTS (SELECT * FROM dbo.tbBundleDependency WHERE BundledRevisionID = r.RevisionID)
OR EXISTS (SELECT * FROM dbo.tbPrerequisiteDependency WHERE PrerequisiteRevisionID = r.RevisionID)))
BEGIN
RAISERROR('The update cannot be deleted as it is still referenced by other update(s).', 16, 45)
RETURN(1)
END
DECLARE #retcode INT
EXEC #retcode = dbo.spDeleteUpdate #localUpdateID
IF ##ERROR <> 0 OR #retcode <> 0
BEGIN
RAISERROR('spDeleteUpdateByUpdateID got error from spDeleteUpdate', 16, -1)
RETURN(1)
END
RETURN (0)
TLDR: if anyone knows a quick way for me to use the results from SELECT UpdateID FROM tbUpdate WHERE UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629' to run exec spDeleteUpdateByUpdateID #updateID= i'd be extremely grateful.
There are some examples online of people using cursors to clean up WSUS. It will be slow but you are presumably only running it once. As mentioned there are other strategies for WSUS cleanup that should probably be investigated first.
DECLARE #var1 INT
DECLARE #msg nvarchar(100)
-- Get obsolete updates into temporary table
-- insert your own ID's here if you wish
CREATE TABLE #results (Col1 INT)
INSERT INTO #results(Col1) EXEC spGetObsoleteUpdatesToCleanup
DECLARE WC Cursor
FOR SELECT Col1 FROM #results
OPEN WC
FETCH NEXT FROM WC INTO #var1
WHILE (##FETCH_STATUS > -1)
BEGIN
SET #msg = 'Deleting' + CONVERT(varchar(10), #var1)
RAISERROR(#msg,0,1) WITH NOWAIT EXEC spDeleteUpdateByUpdateId #var1
FETCH NEXT FROM WC INTO #var1
END
CLOSE WC
DEALLOCATE WC
DROP TABLE #results

SQL - Dynamically selecting information into a variable from different databases

i have 3 databases, db 1 and db 2 are for jobs and db 3 is for workflows.
both db 1 and 2 have a process to create workflows directly into db 3.
i have a trigger in db 3 that activates when there is a workflow creation because i need to add more information into the workflow from the jobs.
so what i did was create a variable that i set with a normal select from db 1 (select job from db1.dbo.job)
i want to know if there is a way to do the select statement dynamically
for example:
if db1 then #db = db1
if db2 then #db = db2
then in the #variable = select job from #db
right now what i have is the following query but i am simple adding all my logic to another IF and then changing the selects statements... i dont want to do that becuase i will be adding more data bases to integrate with db3
Declare
#flag int,
#variable varchar(10)
set #flag = 1
if #flag = 1
begin
set #variable = (select job from db1.dbo.job)
end
else if #flag = 2
begin
set #variable = (select job from db2.dbo.job)
end
update db3 set job = #variable
is it even possible to do what im trying to do????
You need dynamic SQL for this.
Note:
Always use QUOTENAME to correctly escape names
Use sp_executesql to pass data in parameters all the way through. You can use OUTPUT parameters too
Declare
#flag int
set #flag = 1
DECLARE #sql nvarchar(max) = N'
UPDATE db3
SET job = (
SELECT TOP 1 job
FROM ' + QUOTENAME(CASE WHEN #flag = 1 THEN 'db1' ELSE 'db2' END) + '.dbo.job
);
';
EXEC sp_executesql #sql;
This kind of thing is possible using techniques like dynamic sql and sp_executesql, or by creating synonyms on the fly.
HOWEVER, you have a more fundamental issue with the approach.
When a trigger is called, you cannot make the assumption that only a single row will be in the inserted table, because it is possible to insert multiple rows into a table all at once.
To demonstrate the problem, here is a "solution" to your problem which "works" if only one row is inserted into table T. But think about what would happen if more than one row was inserted. What would the "correct" flag value be if multiple rows are inserted with different flag values? How can we update the row in T based on the value of the #id variable if multiple rows are affected?
You could use this pattern and iterate over the rows in the inserted table using a cursor, but it would be a bit ugly.
create table T(id int, flag int, extraData nvarchar(128));
create or alter trigger T_ins on T for insert as
begin
declare #sql nvarchar(max) = 'update T set extraData = (select top 1 name from {otherDB}.sys.tables) where id = #id'
declare #db sysname, #id int;
-- this select doesn't make any sense if more than one row exists in the inserted table!
select #id = id,
#db = iif(inserted.flag = 1, 'master', 'msdb')
from inserted;
set #sql = replace(#sql, '{otherDB}', #db);
exec sp_executesql #sql, N'#id int', #id;
end
A way to do it without a cursor is to left join onto all of the possible sources of additional data in the other databases, including the mutually exclusive flag value in the join condition, and coalesce the columns into the update statement. I think the code is also much cleaner:
create or alter trigger jobs_ins on jobs for insert as
begin
update j
set extraData = coalesce(j1.somedata, j2.somedata)
from jobs j
join inserted ins on ins.id = j.id
left join otherDB1.dbo.jobdata j1 on i.flag = 1 and j1.id = ins.id
left join otherDB2.dbo.jobdata j2 on i.flag = 2 and j2.id = ins.id;
end

looping through recordset in stored procedure

I have created a tbl having SELECT statement as value (fieldname sqltxt).
Now want to read rows one by one and execute all the select statement stored in this table.
If it does not return any row i.e. zero row
insert a new record in DMSResults with value of DOCID from DMSRec
For that I use following script
set nocount on
use TESTDB
declare #sqlTXT as varchar(max);
DECLARE #DocID nvarchar(30);
drop table DMSResults
CREATE TABLE DMSResults (DOCID nvarchar(30) );`
drop table DMSRec
SELECT .....intoDMSRec FROM tbl....
Above syntax is a Big SQl script to create a recordset.
For my conveyance I insert all the records into new tbl.
Its returns more than 10,00,000 records
Now want to loop in tbl DMSREC, read the value of field sqltxt
Execute that statement.
If it doesn't return a record
Insert a record in DMSResults with value of DOCID field.
I also tried with following commands, but do not know how to loop in sql for next rec until eof and exit
Since DMSRec is a temporary table, once a row is processed then we can remove record from DMSRec.
declare #rc as bigint
Select #rc = Row_Count
From sys.dm_db_partition_stats
Where Object_Name(Object_Id) = 'DMSRec'
WHILE #rc <1
BEGIN
exec(select sqltxt from dmsrec where row=1)
-- here check record is exist or not then
-- if it is not exist or returning zero
-- add record in dmsresult with docid value
-- delete dmsrec where row=1
-- loop for next
END
Considering the huge size of database SQL-Server 2008r2 please guide me any optimize solution.
DMSRec TBL recordset.
DOCID         SQLTXT
A01/17-18     SELECT VRNO FROM TBL_LET WHERE VRNO='A01/17-18'
I can't address the actual problem here, but I can elaborate on the question of how to loop through all records. BTW< loops are terrible for performance and thus are avoided at all costs in SQL Server.
--get the row count of the table
declare #rc as bigint
Select #rc = (select count(*) from DMSRec)
--variables for incrementing rows and storing SQL
declare #i bigint = 1
declare #sql varchar(max)
WHILE #i <= #rc
BEGIN
--get the SQL Statement from the table
set #sql = (select sqltxt from dmsrec where row=#i)
--If no value was returned, insert into DSMResults
if (#sql is null) or (ltrim(rtrim(#sql)) = '')
begin
insert into DMSResults
select DOCID from dmsrec
end
--If a value was returned, execute that statement
else
begin
exec(#sql)
end
--increment the row number
set #i = #i + 1
END

SQL "if exists..." dynamic query

Suppose I have a query stored in a variable like this (it's actually dynamically populated and more complex, but this is for demonstration purposes):
DECLARE #Query VARCHAR(1000) = 'SELECT * FROM dbo.MyTable'
Is there a way to check if the query would return any results? Something like this, but this doesn't work:
IF EXISTS (#Query)
BEGIN
-- do something
END
The only way that I can think of to do this is to put the results in a temp table and then query from that, but that is not ideal because the columns in the dynamic query can vary and I really don't need the temp table at all for any reason other than checking whether some rows would be returned. Is there a better way?
Try Executing the Dynamic query and use ##RowCount to find the existence of rows.
DECLARE #Query NVARCHAR(1000) = 'SELECT * FROM [dbo].[Mytable]',
#rowcnt INT
EXEC Sp_executesql #query
SELECT #rowcnt = ##ROWCOUNT
IF #rowcnt > 0
BEGIN
PRINT 'row present'
END
Try this:
DECLARE #Query NVARCHAR(1000) = 'SELECT #C = COUNT(*) FROM dbo.MyTable'
DECLARE #Count AS INT
EXEC sp_executesql #Query, N'#C INT OUTPUT', #C=#Count OUTPUT
IF (#Count > 0)
BEGIN
END
I know this answer is too late. but, I'm leaving this here to help someone else to use IF EXISTS with a dynamic query.
This is how you should do it with dynamic queries.
DECLARE #Query VARCHAR(MAX)
SET #Query = 'SELECT * FROM [dbo].[MyTable]'
SET #Query = 'IF EXISTS (' + #Query + ')
BEGIN
-- do something
print ''1''
END
ELSE
BEGIN
-- do something else
print ''0''
END
'
exec (#Query)
Hope this helped someone. Vote if it did :)
You can use EXEC to execute sql statement, then call ##ROWCOUNT which Returns the number of rows affected by the last statement, to check row exists in sql select stetement.
DECLARE #Query VARCHAR(1000) = 'SELECT * FROM dbo.MyTable',#hasRow int
EXEC (#Query)
SELECT #hasRow =##ROWCOUNT // Returns the number of rows affected by the last statement
PRINT #hasRow
IF #hasRow > 0
BEGIN
Print 1
END
BEGIN
Print 2
END
Hi I think that only way is to put IF EXISTS part into code of execution. My case is to stop execution in point when select affects at least one row, that is goal of IF EXISTS.
Little example that saves reading all records covering by condition to first occurence:
set nocount off;
drop table if exists #temp
go
create table #temp (idCol int identity(1,1),someText nvarchar(1))
go
insert into #temp values ('a')
go 25000
declare #query nvarchar(max)
,#resultFork bit
set #query = 'if exists (select * from #temp where idCol % 3 = 0)
set #resultFork=1
else
set #resultFork=0'
print #query
exec sp_executeSQL #query, N'#resultFork int output', #resultFork=#resultFork output
print #resultFork
/*Now U can use #resultFork in simple if condition...
if #resultFork = 1
begin
--
end
else
begin
--
end
*/

SQL Server - Execute statements using WHILE Loop Issues

I'm trying to write a script that can be used to restore permissions to stored procedures after our merge replication snapshot agent completes applying snapshot to subscribers. This SQL needs to be somewhat dynamic.
Currently, I'm selecting a list of all our stored procedures and inserting them into a temporary table along with string statements for "Granting" permissions. I'm attempting to loop through all the rows on that table, executing the statements one by one using EXEC() command. I keep getting the error
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS
but my SQL statements look like they should be fine. Maybe I'm not understanding how WHILE works in SQL Server.
Here is my code:
BEGIN
CREATE TABLE sqltemp (id int IDENTITY(1, 1) , Stmt1 varchar(max), Stmt2 varchar(max), Stmt3 varchar(max))
INSERT INTO sqltemp
SELECT
'GRANT EXECUTE ON OBJECT::' as Stmt1, name as Stmt2, 'TO edoc_only_execute' as Stmt3
FROM sys.sysobjects
WHERE
type = 'P' AND name NOT LIKE 'MSMerge%'
DECLARE #counter int = 1
WHILE (#counter < (SELECT COUNT(*) FROM sqltemp))
BEGIN
DECLARE #sqlrun varchar(max)
SET #sqlrun = (SELECT Stmt1, Stmt2, Stmt3 FROM sqltemp WHERE id = #counter)
EXEC(#sqlrun)
SET #counter = #counter + 1
END
END
GO
DROP TABLE sqltemp
Two questions:
How can I accomplish executing the above script for each item in my temporary table?
Is there a better way of writing a script to restore permissions for each stored procedure in my database after the snapshot is applied (Note: I must be able use SQL system tables to pull stored procedure names)?
You can't say
SET #sqlrun = (SELECT Stmt1, Stmt2, Stmt3 FROM sqltemp WHERE id = #counter)
You will have to concatenate them
SELECT #sqlrun = Stmt1 +' '+ Stmt2 +' '+ Stmt3 FROM sqltemp WHERE id = #counter
A better solution might be?
GRANT EXEC TO edoc_only_execute
Corrected query for you first question
BEGIN
CREATE TABLE sqltemp (id int IDENTITY(1, 1) , Stmt1 varchar(max), Stmt2 varchar(max), Stmt3 varchar(max))
INSERT INTO sqltemp SELECT 'GRANT EXECUTE ON OBJECT::' as Stmt1, name as Stmt2, 'TO edoc_only_execute' as Stmt3
FROM sys.sysobjects
WHERE type = 'P' AND name NOT LIKE 'MSMerge%'
DECLARE #counter int = 1
WHILE (#counter < (SELECT COUNT(*) FROM sqltemp))
BEGIN
DECLARE #sqlrun varchar(max)
SELECT #sqlrun = Stmt1 + Stmt2 +' '+ Stmt3 FROM sqltemp WHERE id = #counter
PRINT #sqlrun
EXEC(#sqlrun)
SET #counter = #counter + 1
END
END
#010001100110000101110010011010 and #podiluska beat me to it, but...
SELECT COUNT(*) FROM sqltemp
outside of the while:
SET #end = SELECT COUNT(*) FROM sqltemp
WHILE (#counter < #end)
...
No need to re-calculate the end condition for each loop iteration.