Why does SQL Server skip over an IF statement? - sql

Trying to run the following query:
IF LEFT(CAST(SERVERPROPERTY('ProductVersion') as varchar),2) LIKE '1[2-9]'
SELECT
##servername AS [Server]
, d.name AS [Database]
, CONVERT(char(10), d.create_date, 121) AS [Created]
, sp.name AS [Owner]
, d.recovery_model_desc AS [Recovery]
, CASE d.state_desc WHEN 'OFFLINE' THEN '***OFFLINE***' ELSE d.state_desc END AS [Status]
, d.user_access_desc AS [Access]
, CASE d.is_read_only WHEN 0 THEN 'READ_WRITE' WHEN 1 THEN 'READ_ONLY' END AS Updateability
, CASE d.is_fulltext_enabled WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [FullText]
, CASE d.is_auto_create_stats_on WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [CreateStats]
, CASE d.is_auto_update_stats_on WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [UpdateStats]
, CASE d.page_verify_option
WHEN 0 THEN '***NONE***'
WHEN 1 THEN '***TORN PAGE DETECTION***' -- outdated in 2005+. Change to checksum.
ELSE d.page_verify_option_desc
END AS [Page Verify]
, d.compatibility_level AS [Level]
, d.target_recovery_time_in_seconds as ckp_s
, d.log_reuse_wait_desc AS [Log Wait]
, d.collation_name AS [Collation]
, CASE d.is_read_committed_snapshot_on WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [RCS]
, CASE d.snapshot_isolation_state WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [SI]
, CASE d.is_query_store_on WHEN 0 THEN 'NO' WHEN 1 THEN 'YES' END AS QS
, CASE d.is_auto_close_on WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto close*/ END AS [AutoClose]
, CASE d.is_auto_shrink_on WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto shrink*/ END AS [AutoShrink]
, d.delayed_durability_desc as [Durability]
FROM sys.databases AS d
LEFT JOIN sys.server_principals AS sp /*get database owner name */ ON sp.sid = d.owner_sid
WHERE d.database_id > 4 -- exclude system DBs
ORDER BY d.name;
ELSE
SELECT
##servername AS [Server]
, d.name AS [Database]
, CONVERT(char(10), d.create_date, 121) AS [Created]
, sp.name AS [Owner]
, d.recovery_model_desc AS [Recovery]
, CASE d.state_desc WHEN 'OFFLINE' THEN '***OFFLINE***' ELSE d.state_desc END AS [Status]
, d.user_access_desc AS [Access]
, CASE d.is_read_only WHEN 0 THEN 'READ_WRITE' WHEN 1 THEN 'READ_ONLY' END AS Updateability
, CASE d.is_fulltext_enabled WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [FullText]
, CASE d.is_auto_create_stats_on WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [CreateStats]
, CASE d.is_auto_update_stats_on WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [UpdateStats]
, CASE d.page_verify_option
WHEN 0 THEN '***NONE***'
WHEN 1 THEN '***TORN PAGE DETECTION***' -- outdated in 2005+. Change to checksum.
ELSE d.page_verify_option_desc
END AS [Page Verify]
, d.compatibility_level AS [Level]
, 'N/A' AS ckp_s
, d.log_reuse_wait_desc AS [Log Wait]
, d.collation_name AS [Collation]
, CASE d.is_read_committed_snapshot_on WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [RCS]
, CASE d.snapshot_isolation_state WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [SI]
, 'N/A' AS QS
, CASE d.is_auto_close_on WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto close*/ END AS [AutoClose]
, CASE d.is_auto_shrink_on WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto shrink*/ END AS [AutoShrink]
, 'N/A' AS [Durability]
FROM sys.databases AS d
LEFT JOIN sys.server_principals AS sp /*get database owner name */ ON sp.sid = d.owner_sid
WHERE d.database_id > 4 -- exclude system DBs
ORDER BY d.name;
The issue is with SQL Server 2005/2008/2012. The columns target_recovery_time_in_seconds, is_query_store_on, and delayed_durability_desc don't exist in the sys.databases table.
The IF statement at the top finds what version of SQL Server it is. If it's 2014+, run the query with those 3 columns. If not, run the query without those 3 columns. I've used this logic in other queries and it works but in this instance it does not. I get the following errors:
Msg 207, Level 16, State 1, Line 20
Invalid column name 'target_recovery_time_in_seconds'.
Msg 207, Level 16, State 1, Line 25
Invalid column name 'is_query_store_on'.
Msg 207, Level 16, State 1, Line 25
Invalid column name 'is_query_store_on'.
Msg 207, Level 16, State 1, Line 28
Invalid column name 'delayed_durability_desc'.`
My question is why doesn't SQL Server read the IF statement? If it did, it would skip the query with 3 columns and run the one without it.

SQL Server will try and compile all statements in the batch (unless they reference an entire object that doesn't exist - when compilation will be deferred. Referencing missing columns for an existing object does not cause deferred compilation.).
There is a trick you can use though to just have one query that will work in all the versions you are targeting and avoid dynamic SQL.
The columns marked by <-- below will be resolved from sys.databases if they exist in there or fall back to the dummy derived table failing that.
WITH d
AS (SELECT x.*
FROM (SELECT 'N/A', 'N/A', 'N/A')
AS dummy (is_query_store_on, delayed_durability_desc, target_recovery_time_in_seconds)
CROSS APPLY (SELECT d.collation_name,
d.compatibility_level,
d.create_date,
d.database_id,
delayed_durability_desc, /* <-- resolved from d or dummy */
d.is_auto_close_on,
d.is_auto_create_stats_on,
d.is_auto_shrink_on,
d.is_auto_update_stats_on,
d.is_fulltext_enabled,
is_query_store_on, /* <-- resolved from d or dummy */
d.is_read_committed_snapshot_on,
d.is_read_only,
d.log_reuse_wait_desc,
d.name,
d.owner_sid,
d.page_verify_option,
d.page_verify_option_desc,
d.recovery_model_desc,
d.snapshot_isolation_state,
d.state_desc,
target_recovery_time_in_seconds, /* <-- resolved from d or dummy */
d.user_access_desc
FROM sys.databases AS d) AS x)
SELECT
##servername AS [Server]
, d.name AS [Database]
, CONVERT(char(10), d.create_date, 121) AS [Created]
, sp.name AS [Owner]
, d.recovery_model_desc AS [Recovery]
, CASE d.state_desc WHEN 'OFFLINE' THEN '***OFFLINE***' ELSE d.state_desc END AS [Status]
, d.user_access_desc AS [Access]
, CASE d.is_read_only WHEN 0 THEN 'READ_WRITE' WHEN 1 THEN 'READ_ONLY' END AS Updateability
, CASE d.is_fulltext_enabled WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [FullText]
, CASE d.is_auto_create_stats_on WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [CreateStats]
, CASE d.is_auto_update_stats_on WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [UpdateStats]
, CASE d.page_verify_option
WHEN 0 THEN '***NONE***'
WHEN 1 THEN '***TORN PAGE DETECTION***' -- outdated in 2005+. Change to checksum.
ELSE d.page_verify_option_desc
END AS [Page Verify]
, d.compatibility_level AS [Level]
, d.target_recovery_time_in_seconds as ckp_s
, d.log_reuse_wait_desc AS [Log Wait]
, d.collation_name AS [Collation]
, CASE d.is_read_committed_snapshot_on WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [RCS]
, CASE d.snapshot_isolation_state WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [SI]
, CASE d.is_query_store_on WHEN 'false' THEN 'NO' WHEN 'true' THEN 'YES' ELSE 'N/A' END AS QS
, CASE d.is_auto_close_on WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto close*/ END AS [AutoClose]
, CASE d.is_auto_shrink_on WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto shrink*/ END AS [AutoShrink]
, d.delayed_durability_desc as [Durability]
FROM d
LEFT JOIN sys.server_principals AS sp /*get database owner name */ ON sp.sid = d.owner_sid
WHERE d.database_id > 4 -- exclude system DBs
ORDER BY d.name;

When a SQL query is executed, the whole thing gets evaluated first. So when you run it on SQL2012 or earlier, the fields don't exist, so your query isn't valid, because those fields don't exist, even if that section wouldn't be executed.
You could try using some dynamic sql to work around this - build the whole command into a string with the various elements you require, and execute it using sp_executesql
eg:
declare #sql nvarchar(4000)
select #sql = 'SELECT ##servername AS [Server], d.name AS [Database] '
-- some fields omitted here for brevity
IF LEFT(CAST(SERVERPROPERTY('ProductVersion') as varchar),2) LIKE '1[2-9]'
begin
select #sql = #sql + ', CASE d.is_query_store_on WHEN 0 THEN ''NO'' WHEN 1 THEN ''YES'' END AS QS '
end
else
begin
select #sql = #sql + ', ''N/A'' as QS '
end
select #sql = #sql + ' FROM sys.databases AS d LEFT JOIN sys.server_principals AS sp /*get database owner name */ ON sp.sid = d.owner_sid WHERE d.database_id > 4 -- exclude system DBs ORDER BY d.name; '
exec sp_executesql #sql

Related

Order by calculated column with alias inside case expression

I've got a problem with my order by clause when using a calculated column with an alias as below:
This order by works without any problem
declare #Mode int = 1
declare #Sort nvarchar(max) = 'engname'
select top 10 School.Id as EntityId,
School.EnglishName as EntityEnglishName,
School.Name as EntityNativeName,
case
when #Mode = 0 then 0
when #Mode = 1 then 1
when #Mode = 2 then 2
end as ActiveStudents
from V_SchoolMinimized as School
Order By ActiveStudents
The following query has an error:
Invalid column name 'ActiveStudents'
declare #Mode int = 1
declare #Sort nvarchar(max) = 'engname'
select top 10 School.Id as EntityId,
School.EnglishName as EntityEnglishName,
School.Name as EntityNativeName,
case
when #Mode = 0 then 0
when #Mode = 1 then 1
when #Mode = 2 then 2
end as ActiveStudents
from V_SchoolMinimized as School
Order By
case when #Sort is null then School.Id end,
case when #Sort = 'engname' then ActiveStudents end
How can I use ActiveStudents within the conditional order by clause as shown?
So while you can use a calculated column in your ORDER BY clause (but not in other clauses such as GROUP BY), you cannot then apply further calculations or conditions - it must be used exactly as created.
There are a whole bunch of ways to solve this problem. Which approach you use will come down to some combination of:
Which option is clearer to you as the developer
Which option performs better
Which option fits into your existing query better
Option 1: Repeat the logic
I don't recommend this option because it violates the DRY principle thereby making it harder to maintain and easier to make mistakes.
select top 10
S.Id as EntityId
, S.EnglishName as EntityEnglishName
, S.[Name] as EntityNativeName
, case
when #Mode = 0 then 0
when #Mode = 1 then 1
when #Mode = 2 then 2
end as ActiveStudents
from V_SchoolMinimized as S
order by
case when #Sort is null then S.Id end
, case when #Sort = 'engname' then
case
when #Mode = 0 then 0
when #Mode = 1 then 1
when #Mode = 2 then 2
end
end;
The rest of the options are sub-query variations the choice of which comes down to the comments provided as the start.
Option 2: Use a derived table sub-query
select top 10
S.Id as EntityId
, S.EnglishName as EntityEnglishName
, S.[Name] as EntityNativeName
, S.ActiveStudents
from (
select *
, case
when #Mode = 0 then 0
when #Mode = 1 then 1
when #Mode = 2 then 2
end as ActiveStudents
from V_SchoolMinimized
) as S
order by
case when #Sort is null then S.Id end
, case when #Sort = 'engname' then S.ActiveStudents end;
Option 3: Use a CTE (Common Table Expression)
with cte as (
select *
, case
when #Mode = 0 then 0
when #Mode = 1 then 1
when #Mode = 2 then 2
end as ActiveStudents
from V_SchoolMinimized
)
select top 10
S.Id as EntityId
, S.EnglishName as EntityEnglishName
, S.[Name] as EntityNativeName
, S.ActiveStudents
from cte
order by
case when #Sort is null then S.Id end
, case when #Sort = 'engname' then S.ActiveStudents end;
Option 4: Use CROSS APPLY
select top 10
S.Id as EntityId
, S.EnglishName as EntityEnglishName
, S.[Name] as EntityNativeName
, A.Students
from V_SchoolMinimized as S
cross apply (
values (
case
when #Mode = 0 then 0
when #Mode = 1 then 1
when #Mode = 2 then 2
end
)
) as A (Students)
order by
case when #Sort is null then S.Id end
, case when #Sort = 'engname' then A.Students end;
Note: I suggest keeping your table aliases nice and short, 1-2 characters where possible, occasionally 3.

An expression of non-boolean type specified in a context where a condition is expected, near... TABLE

What I am trying to do is based on the company_id (#company_id) which has a corresponding database name (#db_name), trying to pull data based on those variables. I have over 30 tables and need to view data based on which company_id(s) are selected.
i.e. EXEC journal_entries_by_dbase;1'1'
ALTER PROC esh_journal_entries_by_dbase
(#company_id varchar(2))
AS
-------------------------------------------------------
BEGIN
CREATE TABLE ##journal_dbase
(company_id varchar(8)
, journal_description varchar(255)
, journal_type varchar(8)
, date_entered varchar(10)
, date_applied varchar(10)
, date_posted varchar(10)
, hold_flag varchar(8)
, reversing_flag varchar(9)
, intercompany_flag varchar(8)
, domain_username varchar(255)
, posted_flag varchar(8)
, multi_currency_flag varchar(8)
, home_credit decimal(20,2)
, home_debit decimal(20,2))
;
-------------------------------------------------------
DECLARE --#company_id varchar(8)
#db_name varchar(32)
, #sql varchar(8000)
, #drop_table varchar(200)
;
-------------------------------------------------------
SET #db_name = 'select db_name from contrl.dbo.company where company_id = 1' --#company_id';
-------------------------------------------------------
SET #sql =
'INSERT INTO ##journal_dbase
SELECT '+#company_id+'
, trx.journal_description as [Description]
, trx.journal_type as [Journal Code]
, convert(varchar(12),dateadd(dd,(trx.date_entered - 639906),''1/1/1753''),101) as [Entry Date]
, convert(varchar(12),dateadd(dd,(trx.date_applied - 639906),''1/1/1753''),101) as [Apply Date]
, convert(varchar(12),dateadd(dd,(trx.date_posted - 639906),''1/1/1753''),101) as [Post Date]
--, trx.date_entered as [Entry Date]
--, trx.date_applied as [Apply Date]
--, trx.date_posted as [Post Date]
, [Hold] = CASE trx.hold_flag
WHEN 0 THEN ''No''
WHEN 1 THEN ''Yes''
END --as hold
, [Trans Flag] = CASE trx.reversing_flag
WHEN 0 THEN ''Standard''
WHEN 1 THEN ''Reversing''
END --as trans_flag
, [InterCo] = CASE trx.intercompany_flag
WHEN 0 THEN ''No''
WHEN 1 THEN ''Yes''
END
, CASE WHEN e.domain_username NOT LIKE ''%\%''
THEN e.domain_username
ELSE SUBSTRING(e.domain_username,5,20) --SELECT DISTINCT domain_username FROM ECTRL..smusers
END AS [User Name]
, [Posted Flag] = CASE trx.posted_flag
WHEN 0 THEN ''No''
WHEN 1 THEN ''Yes''
END
, trx.source_company_code as [Org]
--, SUM(bal.home_credit) as [Total Home Credit]
--, SUM(bal.home_debit) as [Total Home Debit]
, bal.home_credit as [Total Home Credit]
, bal.home_debit as [Total Home Debit]
FROM '+#db_name+'.dbo.trx trx
LEFT OUTER JOIN '+#db_name+'.dbo.trxdet trxdet
ON trx.journal_ctrl_num = trxdet.journal_ctrl_num
LEFT OUTER JOIN '+#db_name+'.dbo.bal bal
ON trxdet.account_code = bal.account_code
--LEFT OUTER JOIN con.dbo.users e
-- ON trx.user_id = e.user_id
--WHERE trx.date_posted > 0
-- AND trx.date_applied >= ''734503''
-- AND trx.date_applied <= ''734710'''
;
-------------------------------------------------------
SET #company_id = 'select company_id from ewcomp' --where db_name in (#db_name)
-------------------------------------------------------
EXEC (#sql);
-------------------------------------------------------
SELECT * FROM ##journal_dbase;
THis is returning An expression of non-boolean type specified in a context where a condition is expected, near bal and trx and trxdet.
My problem was that I was trying to reference internally to the company table to get the db_name, when I needed to JOIN on it to the sys.databases. I removed the SET #company_id and just used the following for the #db_name. It works.
SELECT #db_name = name
FROM sys.databases
JOIN contrl.dbo.company
ON sys.databases.name = contrl.dbo.company.db_name
WHERE contrl.dbo.company.company_id in (#company_id)
You are putting the SQL queries in the variables for the company and the database name. I think that you want to query the tables for the values:
SET #company = (SELECT company FROM contrl.dbo.company)
SET #db_name = (SELECT db_name FROM contrl.dbo.company WHERE company = #company)
Or simply:
SELECT #company = company FROM contrl.dbo.company
SELECT #db_name = db_name FROM contrl.dbo.company WHERE company = #company
Edit:
With your updated code; change this:
SET #db_name = 'select db_name from contrl.dbo.company where company_id = 1'
to
SELECT #db_name = db_name from contrl.dbo.company where company_id = 1
or with the #CompnayId variable:
SELECT #db_name = db_name from contrl.dbo.company where company_id = cast(#CompanyId as int)

can you do an ELSE WHEN on a CASE

CASE WHEN P.NURSING_UNIT is not null THEN P.NURSING_UNIT ELSE '' END NURSING_UNIT
,CASE WHEN P.UNIT_CODE is not null THEN P.UNIT_CODE ELSE '' END UNIT_CODE,
CASE WHEN M.SIGN_DATE IS NOT NULL THEN 'COMPLETED' ELSE
WHEN M.SIGN_DATE IS NULL THEN 'UNCOMPLETED' AS ASSESSMENTS
error: because the sp is not compiling now. getting this error message:
Msg 156, Level 15, State 1, Procedure GET_SCHEDULE_ALL_DETAIL, Line 18
Incorrect syntax near the keyword 'WHEN'.
Msg 156, Level 15, State 1, Procedure GET_SCHEDULE_ALL_DETAIL, Line 25
Incorrect syntax near the keyword 'AND'.
----
USE [PRO]
GO
/****** Object: StoredProcedure [dbo].[GET_SCHEDULE_ALL_DETAIL] Script Date: 11/02/2011 14:14:50 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter PROC [dbo].[GET_SCHEDULE_ALL_DETAIL]
#FACILITYKEY varchar(1000),
#UNITSTR VARCHAR(100),
#FromDate datetime,
#ToDate datetime
AS
BEGIN
(SELECT S.FACILITY_KEY, S.PAT_NUMBER, S.A3A_DATE_USER, M.REFERENCE_DATE ,
RTRIM(P.LAST_NAME) + CASE WHEN RTRIM(P.FIRST_NAME) <> '' THEN ', '
ELSE ''
END + RTRIM(P.FIRST_NAME) PATIENT_NAME
,CASE WHEN P.NURSING_UNIT is not null THEN P.NURSING_UNIT ELSE '' END NURSING_UNIT
,CASE WHEN P.UNIT_CODE is not null THEN P.UNIT_CODE ELSE '' END UNIT_CODE,
CASE WHEN M.SIGN_DATE IS NOT NULL THEN 'COMPLETED' ELSE
WHEN M.SIGN_DATE IS NULL THEN 'UNCOMPLETED' AS ASSESSMENTS
FROM [PC].MDS_M_SCHEDULE S INNER JOIN OPTC.MD3_M_MAST M
ON S.PAT_NUMBER=M.PAT_NUMBER
LEFT JOIN OGEN.GEN_M_PATIENT_MAST P ON S.PAT_NUMBER = P.PAT_NUMBER
WHERE S.PAT_NUMBER=M.PAT_NUMBER AND M.REFERENCE_DATE < GETDATE()
AND S.A3A_DATE_USER BETWEEN #FromDate AND #ToDate
AND S.FACILITY_KEY IN (SELECT Value FROM dbo.ListToTable(#FACILITYKEY,','))
AND ( #UNITSTR IS NULL
OR #UNITSTR = ''
OR CHARINDEX(P.UNIT_CODE, #UNITSTR)% 2 = 1 ))
UNION ALL
(SELECT * FROM (
(SELECT S.FACILITY_KEY, S.PAT_NUMBER, S.A3A_DATE_USER, M.REFERENCE_DATE ,
RTRIM(P.LAST_NAME) + CASE WHEN RTRIM(P.FIRST_NAME) <> '' THEN ', '
ELSE ''
END + RTRIM(P.FIRST_NAME) PATIENT_NAME
,CASE WHEN P.NURSING_UNIT is not null THEN P.NURSING_UNIT ELSE '' END NURSING_UNIT
,CASE WHEN P.UNIT_CODE is not null THEN P.UNIT_CODE ELSE '' END UNIT_CODE, 'LATE' AS ASSESSMENTS
FROM [PC].MDS_M_SCHEDULE S INNER JOIN OPTC.MD3_M_MAST M
ON S.PAT_NUMBER=M.PAT_NUMBER
LEFT JOIN OGEN.GEN_M_PATIENT_MAST P ON S.PAT_NUMBER = P.PAT_NUMBER
WHERE M.REFERENCE_DATE < GETDATE() AND S.A3A_DATE_USER BETWEEN #FromDate AND #ToDate
AND ( #UNITSTR IS NULL
OR #UNITSTR = ''
OR CHARINDEX(P.UNIT_CODE, #UNITSTR)% 2 = 1 )
) --Started
UNION ALL
(SELECT S.FACILITY_KEY, S.PAT_NUMBER, S.A3A_DATE_USER, NULL AS REFERENCE_DATE,
RTRIM(P.LAST_NAME) + CASE WHEN RTRIM(P.FIRST_NAME) <> '' THEN ', '
ELSE ''
END + RTRIM(P.FIRST_NAME) PATIENT_NAME
,CASE WHEN P.NURSING_UNIT is not null THEN P.NURSING_UNIT ELSE '' END NURSING_UNIT
,CASE WHEN P.UNIT_CODE is not null THEN P.UNIT_CODE ELSE '' END UNIT_CODE, 'LATE' AS ASSESSMENTS
FROM [PC].MDS_M_SCHEDULE S INNER JOIN OPTC.MD3_M_MAST M
ON S.PAT_NUMBER=M.PAT_NUMBER
LEFT JOIN OGEN.GEN_M_PATIENT_MAST P ON S.PAT_NUMBER = P.PAT_NUMBER
WHERE S.PAT_NUMBER NOT IN (SELECT M.PAT_NUMBER FROM [PC].MD3_M_MAST M)
AND S.A3A_DATE_USER < GETDATE() AND S.A3A_DATE_USER BETWEEN #FromDate AND #ToDate
AND ( #UNITSTR IS NULL
OR #UNITSTR = ''
OR CHARINDEX(P.UNIT_CODE, #UNITSTR)% 2 = 1 )) --Not Started
) LATE
WHERE FACILITY_KEY IN (SELECT Value FROM dbo.ListToTable(#FACILITYKEY,',')))
END
GO
No, ELSE is a catch-all. In your example, it's not clear why you would want to include a condition in the ELSE clause, since you've already checked the logically opposite condition in the first WHEN expression.
However, more generally, you can nest CASE expressions, which would look something like this:
CASE
WHEN m.sign_date IS NOT NULL THEN 'COMPLETED'
ELSE
CASE WHEN m.start_date IS NOT NULL THEN 'IN PROGRESS' ELSE 'NOT STARTED' END
END
I think you can just remove that else before the when, and add an end before 'as assessments'
coalesce(P.NURSING_UNIT , '') NURSING_UNIT, -- you can use coalesce here too
coalesce(P.UNIT_CODE, '') UNIT_CODE,
CASE
WHEN M.SIGN_DATE IS NOT NULL THEN 'COMPLETED'
WHEN M.SIGN_DATE IS NULL THEN 'UNCOMPLETED' END AS ASSESSMENTS
Change this part:
CASE WHEN M.SIGN_DATE IS NOT NULL THEN 'COMPLETED' ELSE
WHEN M.SIGN_DATE IS NULL THEN 'UNCOMPLETED'
to
CASE WHEN M.SIGN_DATE IS NOT NULL THEN 'COMPLETED' ELSE 'UNCOMPLETED' END
There's no point in having if (true) { ...} else if (false) { ... }. Just make the else unconditional.
Standard SQL:
COALESCE(P.NURSING_UNIT, '') AS NURSING_UNIT,
COALESCE(P.UNIT_CODE, '') AS UNIT_CODE,
CASE
WHEN M.SIGN_DATE IS NULL THEN 'UNCOMPLETED'
ELSE 'COMPLETED'
END AS ASSESSMENTS
If your vendor provides a REPLACE() function:
COALESCE(P.NURSING_UNIT, '') AS NURSING_UNIT,
COALESCE(P.UNIT_CODE, '') AS UNIT_CODE,
COALESCE(REPLACE(M.SIGN_DATE, M.SIGN_DATE, 'COMPLETED'), 'UNCOMPLETED') AS ASSESSMENTS

How to insert unique value into non-identity field

I'm trying to do an insert into an established table which has a primary key fields and another field (call it field1) that is unique (this other unique field has a unique constraint preventing my inserts). Field1 is not an identity field, so it does NOT autonumber. Unfortunately I can't change the table. Existing inserts are made using code to increment and all involve looping/cursors. Something like SELECT MAX(field1) + 1
So, is there anyway to do this insert without looping/cursor? This field means nothing to me, but there are already 500,000+ records using their silly numbering scheme, so I must respect that.
This is simplified (ReceiptNumber is the field I want to insert unique), but:
SET XACT_ABORT ON
Begin Transaction TransMain
Declare #nvErrMsg nvarchar(4000)
--Insert inventory receipts
Insert Into Avanti_InventoryReceipts (
ReceiptNumber , ItemNumber , ReceiptDate , OrderNumber , JobNumber , Supplier ,
LineNumber , MultiLineNumber , [Status] , QtyOrdered , QtyReceived , QtyToReceive ,
QtyBackOrdered , Cost , Wholesale , LastCost , QtyToInvoice , QtyUsed ,
ReferenceNumber , [Description] , SupplierType , Processed , DateExpected , DateReceived ,
AccountNumber , Reference2 , EmployeeCode , ExtraCode , Location , RollNumber ,
QtyIssues , Notes , NumPackages , BundleSize , ConsignmentUnitPrice , RecFromProduction ,
QtyCommitted )
SELECT ( SELECT MAX(ReceiptNumber) + 1 FROM Avanti_inventoryReceipts ) , CR.ItemNumber , Convert(char(8), GETDATE(), 112) , PONum , 'FL-INV' , PH.POVendor ,
0 , 0 , 'O' , CR.QtyOrdered , QtyReceivedToday , QtyReceivedToday ,
Case #closePO
When 'N' Then Case When ( QtyOrdered - QtyReceivedToday ) < 0 Then 0 Else ( QtyOrdered - QtyReceivedToday) End
When 'Y' Then 0
Else 0 End
, PD.TransCost * QtyReceivedToday , IH.PriceWholeSale , IH.CostLast , QtyReceivedToday , 0 ,
'' , PODetailDescription , '' , '' , '' , Convert(char(8), GETDATE(), 112) ,
'' , '' , #employeeCode , '' , 'F L E X O' , '' ,
0 , 'Flexo Materials' , 0 , 0 , 0 , '' , 0
FROM FI_CurrentReceiptData CR
LEFT JOIN Avanti_PODetails PD ON CR.PONum = PD.PONumber
LEFT JOIN Avanti_POHeader PH ON CR.PONum = PH.PONumber
LEFT JOIN Avanti_InventoryHeader IH ON CR.ItemNumber = IH.ItemNumber
IF ##ERROR <> 0
Begin
Select #nvErrMsg = 'Error entering into [InventoryReceipts] -' + [description]
From master..sysmessages
Where [error] = ##ERROR
RAISERROR ( #nvErrMsg , 16, 1 )
Goto Err_
End
Commit Transaction TransMain
Goto Exit_
Err_:
Rollback Transaction TransMain
Exit_:
SET XACT_ABORT OFF
You could do this:
insert into mytable (field1, field2, ...)
values (( SELECT MAX(field1) + 1 from mytable), 'value2', ...);
Why not looping? It should be quite efficient.
Since you already have a UNIQUE constraint on the field, you can:
Simply try to insert MAX(field1) + 1. Since there is index on UNIQUE field, MAX is fast.
If its passes, great you are done.
If it fails (which will typically be manifested as an exception in your client code), just try again until you succeed.
Most of the time, the INSERT will succeed right away. In rare instances where a concurrent user tries to insert the same value, you'll handle that gracefully by trying the "next" value.
I added an autonumber starting from 0 in client code and passed that in. Now I'm adding that value to the max receiptnumber to get a unique one. Also, I realized I already had an identity column in FI_CurrentReceiptData, but I didn't want to use that one because it won't start at 0 for each receipt set, and reseeding the identity each time seems like a waste of processor time.

Condition in sql query

I want to insert in sql query something like that:
Select * from Users where id=[if #userId>3 then #userId else "donnt use this condition"] and Name=[switch #userId
case 1:"Alex"
case 2:"John"
default:"donnt use this condition"];
How can i do it?
yet another similar question
When showAll is false it works ok but when showAll is true it returns nothing. Why and how to make it working right? IsClosed column has a bit type.
Select * from orders where IsClosed=CASE WHEN #showAll='false' THEN 'false' ELSE NULL END;
This will perform horribly:
Select *
from Users
where (#userid > 3 AND id = #userId)
OR (#userId BETWEEN 1 AND 2 AND name = CASE
WHEN #userId = 1 THEN 'Alex'
ELSE 'John'
END)
The best performing option is dynamic SQL:
SQL Server 2005+
DECLARE #SQL NVARCHAR(4000)
SET #SQL = 'SELECT u.*
FROM USERS u
WHERE 1 = 1 '
SET#SQL = #SQL + CASE
WHEN #userId > 3 THEN ' AND u.id = #userId '
ELSE ''
END
SET#SQL = #SQL + CASE #userId
WHEN 1 THEN ' AND u.name = ''Alex'' '
WHEN 2 THEN ' AND u.name = ''John'' '
ELSE ''
END
BEGIN
EXEC sp_executesql #SQL, N'#userId INT', #userId
END
For more info on SQL Server's dynamic SQL support, read "The Curse and Blessings of Dynamic SQL"
Select *
from Users
where id = CASE WHEN #userId>3 THEN #userId ELSE NULL END
OR name = CASE WHEN #userId = 1 THEN 'Alex' WHEN #UserId = 2 THEN 'John' ELSE NULL END
Please try this:
select *
from Users
where id = (case when #userId > 3 then #userId
else id end)
and Name = (case cast(#userId as varchar)
when '1' then 'Alex'
when '2' then 'John'
else Name end)
Or I think this will perform better:
select aa.*
from (select *
, case when #userId > 3 then #userId
else id end as UserID
, case cast(#userId as varchar)
when '1' then 'Alex'
when '2' then 'John'
else Name end as UserName
from Users) aa
where aa.id = aa.UserID
and aa.Name = aa.UserName
You might want to define each field that you only need on your select, instead of using asterisk(*).