Run Select statement in Stored Procedure based on conditional logic - sql-server

I've recently been simplifying many formally manual processes on SQL Server 2008 into stored procedures. I'm attempting to turn the below multi-step process into a stored procedure with conditional logic, but not sure how to accomplish this.
Run SELECT COUNT(*) FROM vw_GENERIC_VIEW_NAME
Run SELECT COUNT(*) FROM tbl_SIMPLE_TABLE_NAME
Compare results and if they are not equal run a SELECT statement against tbl_SIMPLE_TABLE_NAME to analyze details.
Is there a way to compare the results through some sort of conditional logic and only run the final SELECT statement if they are not equal in a stored procedure on SQL Server?

Use IF statement with <> operator
IF (SELECT COUNT(*) FROM vw_GENERIC_VIEW_NAME) <> (SELECT COUNT(*) FROM tbl_SIMPLE_TABLE_NAME)
BEGIN
Select ... From tbl_SIMPLE_TABLE_NAME
END

You can just compare the counts from the 2 tables in an IF statement and conditionally execute code within the block if the valued don't match:
IF ( SELECT COUNT(*)
FROM vw_GENERIC_VIEW_NAME
) != ( SELECT COUNT(*)
FROM tbl_SIMPLE_TABLE_NAME
)
BEGIN
PRINT 'NOT EQUAL - run your code in place of this print statement'
END

Related

Using sys.dm_os_sys_info for SQL 2008 R2 and above

I'm trying to write a query to gather memory stats across my multiple SQL editions that are SQL 2008 R2, SQL 2012, SQL 2014, SQL 2016.
Due to the column name changes in sys.dm_os_sys_info I'm trying to get around that, but both of the queries fail with:
Msg 207, Level 16, State 1, Line 7
Invalid column name 'physical_memory_kb'.
Any ideas?
IF (LEFT(cast(serverproperty('productVersion') as varchar(100)),2) = '10')
BEGIN
select physical_memory_in_bytes/1048576 FROM sys.dm_os_sys_info
END
ELSE
BEGIN
select physical_memory_kb/1024 FROM sys.dm_os_sys_info
END
select
CASE LEFT(cast(serverproperty('productVersion') as varchar(100)),2)
WHEN 10 Then physical_memory_in_bytes/1048576
ELSE physical_memory_kb/1024
END
FROM sys.dm_os_sys_info
The error you've got is compilation error, i.e. parser tries to figure out the columns of existing tables/views and it doesn't consider execution flow (IF)
You can use this code for your purpose:
IF (LEFT(cast(serverproperty('productVersion') as varchar(100)),2) = '10')
BEGIN
exec('select physical_memory_in_bytes/1048576 FROM sys.dm_os_sys_info')
END
ELSE
BEGIN
exec ('select physical_memory_kb/1024 FROM sys.dm_os_sys_info')
END
You can't put a conditional statement to select from non-existent columns like that, the compiler will still validate all the statements within the select clause.
The first conditional works because it is two distinct select statements.
I would suggest using the first conditional only, if you need additional info then select the physical_memory_in... column into a temp table or table variable and then join that into your main query.

Execute multiple statements and CTE in stored procedure in SQL Server 2012?

I'm newish to SQL server 2012, and I'm trying to create a stored procedure that should:
Delete previous data from a table, based on a parameter, then
Insert new data on that table.
But I need to use CTEs for performance and other reasons (please don't get hung up on that, I have to, just take my word).
The CTE query works fine if it's by itself in a Stored Procedure, but I can't get the SP to work with two clauses.
I get an error when trying to create the procedure, complaining that I should use a semicolon before the CTE. If I add the semicolon, SQL Server complains about it too. It's driving me insane, please help!
Table where I want to delete/insert:
CREATE MYTABLE ( APPUSER NVARCHAR(15), DATA NVARCHAR(100) )
Simplified stored procedure (no semicolon):
CREATE PROCEDURE P1 ( #SOMEUSER NVARCHAR(15), #TYPE INTEGER) AS
BEGIN
DELETE FROM MYTABLE WHERE ( APPUSER=#SOMEUSER )
WITH CTE AS (
SELECT DATA
FROM SOURCETABLE
WHERE ( TYPE = #TYPE )
)
INSERT INTO MYTABLE
SELECT
#SOMEUSER,
DATA
FROM CTE
END
Error message without semicolon:
[Error Code: 319, SQL
State: S1000] Incorrect syntax near the keyword 'with'. If this
statement is a common table expression, an xmlnamespaces clause or a
change tracking context clause, the previous statement must be
terminated with a semicolon.
Please note that even though that's a simplified version of the actual query, the error is exactly the same. I did try the above code, without any luck :(
Stored procedure with semicolon (same query as above, showing only the semicolon for brevity):
(...)
BEGIN
DELETE FROM MYTABLE WHERE ( APPUSER=#SOMEUSER ); /* Semicolon */
WITH CTE AS (
(...)
Error with semicolon:
[Error Code: 102, SQL State: 42000] Incorrect syntax near ')'.
I tried enclosing the DELETE clause in it's own transaction, that didn't work either, always get one of the two errors.
Any pointers will be very appreciated, thanks!!!
You need to put a ';' before 'With' keyword, your code look like this
CREATE PROCEDURE P1 ( #SOMEUSER NVARCHAR(15), #TYPE INTEGER) AS
BEGIN
DELETE FROM MYTABLE WHERE ( APPUSER=#SOMEUSER )
;WITH CTE AS (
SELECT DATA
FROM SOURCETABLE
WHERE ( TYPE = #TYPE )
)
INSERT INTO MYTABLE
SELECT
#SOMEUSER,
DATA
FROM CTE
END
As a thumb rule for CTE, always start with a semicolon if you have any executable statement above your CTE.
You have something strange going on because the following works for me:
CREATE PROCEDURE P1 ( #SOMEUSER NVARCHAR(15), #TYPE INTEGER) AS
BEGIN
DELETE FROM [Table_1] WHERE ( [lname]=#SOMEUSER );
WITH CTE AS (
SELECT [fname], [lname]
FROM [Table_1]
WHERE ( [ID] = #TYPE )
)
INSERT INTO [Table_1]
SELECT top 1
#SOMEUSER,
[lname],
#TYPE
FROM CTE
END
Check your environment
A CTE is just syntax - it does not help performance
For complete clarity of the points raised by others, this excerpt form the MSDN documentation on CTE's in SQL Server is an essential note for usage of CTE's:
•When a CTE is used in a statement that is part of a batch, the
statement before it must be followed by a semicolon.
As also noted, it is best practice to either:
Develop the habit of ending all SQL statements with a semicolon; or
Learn and memorize all required semicolons, such as here, and preface all these constructs with one.
I prefer the first, but I have seen competent developers who prefer the second.

SQL Server syntax error for stored procedure

I am getting a syntax error trying to create a stored procedure, although the exact same code runs perfectly as a query. I can't see the error myself, so any help would be appreciated.
The error is:
Msg 102, Level 15, State 1, Procedure DataSelect, Line 12
Incorrect syntax near 'OrderedYTD'.
And the code is simply:
CREATE PROCEDURE DataSelect
(
#TargetPdc int
)
AS
BEGIN
-- Refresh Data Here
EXEC DataUpdate
-- Select Data for Report
WITH OrderedYTD AS
(
SELECT custextract.*, histextract.*,
ROW_NUMBER () OVER (PARTITION BY custextract.custcustno ORDER BY histextract.salesytd desc) AS RowNumber
FROM custextract
INNER JOIN histextract
ON custextract.custcustno = histextract.histcustno
WHERE (custextract.ecall = 'Y')
)
SELECT OrderedYTD.*
FROM OrderedYTD
WHERE RowNumber <= 10 and pdc = #TargetPdc;
END
I've run everything beginning at the WITH statement (minus the variable in the WHERE clause) as a query multiple times with no issue. Is there a syntactic difference using the CTE inside a stored procedure? Thanks.
You need a semicolon before your WITH, otherwise it gets treated as a modifier to the preceding statement. Just change this line and it should work:
EXEC DataUpdate;
If you don't terminate all your statements with semicolons, standard practice is to put them before your CTE definition:
;WITH OrderdYTD AS

Oracle DB: Return second query if first query is empty

I am writing an Oracle stored procedure to return the results of a database query. If the query does not produce any results, a second query must be run in its place.
In SQL Server, I can accomplish this using something similar to the following:
INSERT INTO #TableVar
SELECT <joinQuery1>;
IF (SELECT COUNT(*) FROM #TableVar) > 0
BEGIN
SELECT * FROM #TableVar; -- returns <joinQuery1>
END
ELSE
SELECT <joinQuery2>; --returns <joinQuery2>
END
However, I can not wrap my head around how to accomplish the same task in Oracle.
You can utilize WITH to make this perform better (and easier to maintain):
WITH query1 as (
select 1, 2
from dual
where 1=0
connect by level <= 10
),
query2 as (
select 3, 4
from dual
connect by level <= 10
)
select *
from query1
union all
select *
from query2
where not exists (
select null
from query1
);
As is this should return the 10 rows from query2. If you remove the where 1=0 from query1 (causing it to actually return rows), you should get the 10 rows from query1.
The answer depends very much how are you going to use results of query further. So you should either use pipelened functions, insert into GTT or return ref cursor.
At any case I would recommend you to do it in 1 SQL statement to achieve read consistency.
So please consider something like
create procedure test (pCursor out sys_refcursor) is
begin
open pCursor for
select <joinQuery1>
union all
SELECT <joinQuery2>
where not exists (select 1 from joinquery1)
;
end;

How to Log Number of Rows affected by SSIS Execute SQL Task

When I execute a sql statement like "Select ...", I can only see "...100%" completed...
I want to log the number of rows affected.
How can we do that?
run your SELECT from within a stored procedure, where you can log the rowcount into a table, or do anything else to record it...
CREATE PROCEDURE SSIS_TaskA
AS
DECLARE #Rows int
SELECT ... --your select goes here
SELECT #Rows=##ROWCOUNT
INSERT INTO YourLogTable
(RunDate,Message)
VALUES
(GETDATE(),'Selected '+CONVERT(varchar(10),ISNULL(#Rows,0))+' rows in SSIS_TaskA')
GO
When you use a SQL Task for a select most of the time you give as destination a DataSet Object, you can count the number of ligne from the DataSet
I believe you could leverage a t-sql output clause on your update or insert statement and capture that as an ssis variable....or just drop it into a sql table.
here is an example...its crappy, but it is an example
UPDATE TOP (10) HumanResources.Employee
SET VacationHours = VacationHours * 1.25
OUTPUT INSERTED.EmployeeID,
DELETED.VacationHours,
INSERTED.VacationHours,
INSERTED.ModifiedDate
INTO #MyTableVar;
You could output ##ROWCOUNT anyplace you need it to be.
Here is output syntax
http://technet.microsoft.com/en-us/library/ms177564.aspx

Resources