Are there any rules defined for grouping the T-SQL statements under the BEGIN...END block ?
Because when I try the BEGIN...END block inside the CASE statement OR IIF statement, it fails.
I need BEGIN...END block because there are multiple operations that I want to perform under the CASE result.
SELECT
CASE #ChargePaid
WHEN 1 THEN
BEGIN
SELECT 'Paid'
END
WHEN 0 THEN
BEGIN
SELECT 'Not Paid'
END
END
OR
SELECT IIF( #ChargePaid > 0, BEGIN SELECT 'Paid' END , BEGIN SELECT 'Not Paid' END )
EDIT:
IF #cond = 'First'
WITH CTE AS (
SELECT 'A missing' Result
UNION
SELECT 'B missing' Result
UNION
SELECT 'C missing' Result
)
SET #msg = SELECT Result from CTE
IF #cond = 'Second'
WITH CTE AS (
SELECT 'A missing' Result
UNION
SELECT 'B missing' Result
UNION
SELECT 'C missing' Result
)
SET #msg = SELECT Result from CTE
IF #ChargePaid = 0
...
Some code goes here to generate the message.
Then I store the actual message into #msg variable.
...
In the end I store the #msg values (I trim the #msg if it requires) to the table.
What I want is:
I want to validate the #ChargePaid condition.
If it comes false, I want to avoid further processing for optimization of code & store charge missing info to #msg variable\table.
BEGIN / END delimit program statements.
Encloses a series of Transact-SQL statements so that a group of Transact-SQL statements can be executed.
CASE blocks accept expressions.
Evaluates a list of conditions and returns one of multiple possible result expressions.
So you are trying to fit a square peg in a round hole.
Related
I want to implement this sort of logic:
select
many_columns,
case
when something then 'whatever'
else Generate Error Message and Stop the Query
end as [whatever]
from
table_1
Is this possible?
Edit #1:
Based on the comments that I got, I did some experimenting.
drop table if exists #testing;
go
with whatever as (
select 1 as [num] union
select 2 union
select 3 union
select 4 union
select 5 union
select 6 union
select 7 union
select 8 union
select 9 union
select 10
)
declare #counter INT
set #counter = 0
while (#counter <= (select count(*) from #testing))
begin
IF (#counter) < 5
print 'hi'
set #counter = #counter + 1
else
select * from #testing
print 'bye'
select #counter = #counter + 1
end
go
Hmm...the If statement is having issues with the else part...all I get is "Incorrect Syntax".
Seems the answer to my question is to combine a while loop with an if statement AFTER producing my main query to find the error message.
The final if statement will look something like this:
declare #counter INT
set #counter = 0
while (#counter <= (select count(*) from #testing))
begin
--print #counter
IF (#counter = (select [num] from #testing where [num] = #counter))
--print 'hi'
print cast(#counter as varchar) + ' ' + 'hi'
else
--select * from #testing where [num] = #counter
--print 'bye'
print cast(#counter as varchar) + ' ' + 'bye'
select #counter = #counter + 1
end
go
I can't put it better than the comment from #marc_s:
CASE in T-SQL is an expression (like a+b) that returns a single, atomic value. It is NOT a construct to deal with program flow and such - for that, you need to use IF / ELSE
👍
So let's take your original CASE expression code:
case
when something then 'whatever'
else Generate Error Message and Stop the Query
end as [whatever]
As an IF/ELSE (using BEGIN/END) flow:
IF call_that_a_knife = 'yes'
BEGIN
SELECT 'This is a knife' AS yes_i_call_that_a_knife;
END
ELSE
BEGIN
RAISERROR ('That's not a knife!', 16, 1);
END
;
RAISERROR()
The way I have implemented this kind of construct is by attempting to perform an addition operation with the error message in case the condition for the error is true:
select
many_columns,
1 + case
when <error_condition>
then 'Error Message Here will Stop the Query'
else 0 end as [success]
from
table_1
Assuming that the <error_condition> uses data from the rows fetched from table_1 or calls out some function that returns a value that may mean an error condition, this will run the query until it reaches the point the condition is true and then will error out with something like:
Msg 245, Level 16, State 1, Line 15
Conversion failed when converting the varchar value 'Error Message Here will Stop the Query' to data type int.
I have the following Select statements, I need to create a stored proc that will choose which statement to run, guessing this would have to be based on variables (newb here). I've read about Passed Parameters but have not seen an example that applies to this situation in my searches, please help me out.
I am in SQL Server 2014.
First statement
select
cast(dateadd(hour,-4,getdate())-max(esig_date) as time) as time_since_last_esig,
case
when datepart(hour,dateadd(hour,-4,getdate()))>=8 and datepart(hour,dateadd(hour,-4,getdate()))<22 and cast(dateadd(hour,-4,getdate())-max(esig_date) as time)>='00:30:00.0000000' then 'alert'
else 'no alert'
end as alert_status
from activity_table
Second Statement
select
cast(dateadd(hour,-4,getdate())-max(esig_date) as time) as time_since_last_esig,
case
when datepart(hour,dateadd(hour,-4,getdate()))<8 and datepart(hour,dateadd(hour,-4,getdate()))>=22 and cast(dateadd(hour,-4,getdate())-max(esig_date) as time)>='01:00:00.0000000' then 'alert'
else 'no alert'
end as alert_status
from activity_table
Will something like this work
CREATE PROCEDURE ChooseWhichOne
#Selection BIT
AS
BEGIN
IF #Selection = 0
BEGIN
select
cast(dateadd(hour,-4,getdate())-max(esig_date) as time) as time_since_last_esig,
case
when datepart(hour,dateadd(hour,-4,getdate()))>=8 and datepart(hour,dateadd(hour,-4,getdate()))<22 and cast(dateadd(hour,-4,getdate())-max(esig_date) as time)>='00:30:00.0000000' then 'alert'
else 'no alert'
end as alert_status
from activity_table
END
ELSE
BEGIN
select
cast(dateadd(hour,-4,getdate())-max(esig_date) as time) as time_since_last_esig,
case
when datepart(hour,dateadd(hour,-4,getdate()))<8 and datepart(hour,dateadd(hour,-4,getdate()))>=22 and cast(dateadd(hour,-4,getdate())-max(esig_date) as time)>='01:00:00.0000000' then 'alert'
else 'no alert'
end as alert_status
from activity_table
END
RETURN 0
END
AND to execute the stored PROCEDURE
EXEC dbo.ChooseWhichOne #Selection = 0 -- bit
EXEC dbo.ChooseWhichOne #Selection = 1 -- bit
I'm working on a procedure that should return a o or a 1, depending on result from parameter calculation (parameters used to interrogate 2 tables in a database).
When I excute that code in a query pane, it gives me the results i'm expecting.
code looks like:
SELECT TOP 1 state, updDate INTO #history
FROM [xxx].[dbo].[ImportHystory] WHERE (db = 'EB') ORDER BY addDate DESC;
IF (SELECT state FROM #history) = 'O'
BEGIN
SELECT TOP 1 * INTO #process_status
FROM yyy.dbo.process_status WHERE KeyName = 'eb-importer';
IF(SELECT s.EndDate FROM #process_status s) IS NOT NULL
IF (SELECT s.EndDate FROM #process_status s) > (SELECT h.updDate FROM #history h)
BEGIN
IF (SELECT MessageLog from #process_status) IS NOT NULL SELECT 1;
ELSE SELECT 0;
END
ELSE
SELECT 1;
ELSE
SELECT 1;
END
ELSE
SELECT 0
I'm in the situation where EndDate from #process_status is null, so the execution returns 1.
Once i put the SAME code in a SP, and pass 'EB' and 'eb-importer' as parameters, it returns 0.
And I exec the procedure with the data from the table right in front of me, so i know for sure that result is wrong.
Inside the procedure:
ALTER PROCEDURE [dbo].[can_start_import] (#keyName varchar, #db varchar, #result bit output)
DECLARE #result bit;
and replace every
SELECT {0|1}
with
SELECT #result = {0|1}
Executed from the Query pane:
DECLARE #result bit;
EXEC [dbo].[can_start_import] #KeyName = 'eb-importer', #db = 'EB', #result = #result OUTPUT
SELECT #result AS N'#result'
Why does this happen?
You are doing a top(1) query without an order by. That means SQL Server can pick any row from table1 that matches the where clause.
If you want to guarantee that the result is the same every time you execute that code you need an order by statement that unambiguously orders the rows.
So, apparently 2 things needed to be done:
set the length of the varchar parameter with a higher length,
filter with ' like ' instead of ' = ' for god knows what reason
Now it work as i expected to do, but i still don't get the different results between the query pane and the procedure if i use the equal...
I have the following SQL code:
IF OBJECT_ID( 'tempdb..#PropList') IS NOT NULL
DROP TABLE #PropList
DECLARE #Split CHAR(1), #propList NVARCHAR(MAX), #PropListXml XML
SET #Split = ','
SET #propList = 'NAME,DESCRIPTION'
-- SET #propList = ''
IF (#propList IS NOT NULL AND #propList != '')
BEGIN
SET #PropListXml = CONVERT(XML,'<root><s>' + REPLACE(#propList, #Split, '</s><s>') + '</s></root>')
SELECT SystemName = T.c.VALUE('.','nvarchar(36)')
INTO #PropList
FROM #PropListXml.nodes('/root/s') T(c)
END
ELSE
BEGIN
SELECT SystemName
INTO #PropList -- Stops here
FROM tblProperty
END
SELECT * FROM #PropList
Regardless of the value of #propList, this code always stops at the indicated line with this error:
There is already an object named '#PropList' in the database.
My expectation was that only one of the two IF blocks is executed, therefore there should be only one attempt to create the table with the SELECT... INTO statement. Why is this failing?
As per comment, you'll need to explicitly define your #temp table before the IF statement, then change your
SELECT ... INTO #temp
to be
INSERT INTO #temp SELECT ...
This is because when SQL Server validates the query it ignores any control flow statements. For more detail on this see the following SO question:
T-Sql appears to be evaluating "If" statement even when the condition is not true
i am trying to create sql server procedure with if statement.
i am new to the ms sql server however i tried with the following statements but it gave me the below error Msg 116, Level 16, State 1, Procedure te, Line 9
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
here is the code i wrote
CREATE PROCEDURE test as
BEGIN
SET NOCOUNT ON;
if (select COUNT(load),load,contractor_id from [test].[dbo].[cont]
group by load,contractor_id
having load = (select MIN(load)from [test].[dbo].[cont])
) > 1
begin
SELECT top 1 COUNT(*),load ,contractor_id,name
FROM [test].[dbo].[cont]
group by load,contractor_id,name
having load = (select MIN(load)from [test].[dbo].[cont])
ORDER BY NEWID()
end
ELSE
BEGIN
SELECT top 1 COUNT(*),load ,contractor_id,name
FROM [test].[dbo].[cont]
group by load,contractor_id,name
having load = (select MIN(load)from [test].[dbo].[cont])
END
END
GO
can anyone help please
As the error says you cannot have multiple column selected when you use IF condition. In your first IF condition you are selecting multiple columns, however if conditions requires to have a query that can lead to one value. Other option is you have to use IF EXISTS, that can check count >1 as below
IF (SELECT COUNT(load),load,contractor_id
FROM [test].[dbo].[cont]
GROUP BY load,contractor_id
HAVING load = (SELECT MIN(load)
FROM [test].[dbo].[cont])
AND COUNT(load) >1)
Another thing what I noticed is you are excecuting the query which calculates the min of load multiple times. You can avoid that by storing it in a variable and use it further.
I have modified the procedure as below. Check if this works or not.
CREATE PROCEDURE test as
BEGIN
SET NOCOUNT ON;
DECLARE #count INT
DECLARE #minload INT
SELECT #minload = MIN(load)from [test].[dbo].[cont]
SELECT #count = COUNT(load) from [test].[dbo].[cont]
GROUP BY load,contractor_id
HAVING load = #minload
IF (#count) > 1
BEGIN
SELECT top 1 COUNT(*),load ,contractor_id,name
FROM [test].[dbo].[cont]
WHERE load = #minload
GROUP BY load,contractor_id,name
ORDER BY NEWID()
END
ELSE
BEGIN
SELECT top 1 COUNT(*),load ,contractor_id,name
FROM [test].[dbo].[cont]
GROUP BY load,contractor_id,name
HAVING load = #minload
END
END
UPDATE
Based on your comments, I suppose you can get the result with one simple query as below.
;WITH minLoad(load)
AS
(
SELECT MIN(load)
FROM [test].[dbo].[cont]
)
SELECT TOP 1 COUNT(*),c.load ,c.contractor_id,c.name
FROM [test].[dbo].[cont] c, minLoad
WHERE c.load = minLoad.load
ORDER BY NEWID();