can you do an ELSE WHEN on a CASE - sql

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

Related

Get the value of END AS column in case when in where clause

I have a query where i used case when to KNOWN_AS column stating when its null then 'null' else 'not null' end as known_as2. Now in where clause i want to bring rows which only contain 'Not null' .
SELECT i.individual_ref, 0, 'KNOWNAS', i.FORENAMES, i.KNOWN_AS,
case when KNOWN_AS is null then 'Null' else ' Not null' end as known_as
FROM TestDatabase.dbo.INDIVIDUAL I
JOIN TestDatabase.dbo.MEMBER M ON M.INDIVIDUAL_REF=I.INDIVIDUAL_REF
WHERE m.member_status IN(33,1316)
AND i.KNOWN_AS IS null or i.KNOWN_AS=''
and m.MEMBER_STATUS in (33,1316)
and LEN(i.FORENAMES) > '1' and i.FORENAMES !=''
AND i.FORENAMES IS NOT NULL
Reason i'm want help is :-
I have a table which contain Forename, surname and known_as field.
I want to get members who's known_as field is blank/null and forename is not null or blank and forename length is >1 . How can i achieve it. the member status is from another table call member where i want member who are in active and pending status hence i said WHERE m.member_status IN (33,1316). Any solution please.
Finally I have solved it using
SELECT i.individual_ref,0,'KNOWNAS',
case when KNOWN_AS is null then 'Null' else ' Not null' end as knownas2
FROM TestDatabase.dbo.INDIVIDUAL I
JOIN TestDatabase.dbo.MEMBER M ON M.INDIVIDUAL_REF=I.INDIVIDUAL_REF
WHERE m.member_status IN(33,1316)
and len(i.forenames)>2 and
(IsNull(i.forenames, '') <> '') and (i.known_as is null or i.known_as='')
I had to take len(i.forenames, '')>2 instead of 1 because some members also has forename by mistakenly updated as Mr.
Now in where clause i want to bring rows which only contain 'Not null' .
Just modify your WHERE clause with IS NOT NULL as :
SELECT i.individual_ref, 0, 'KNOWNAS', i.FORENAMES, i.KNOWN_AS
FROM DiTestDatabase.dbo.INDIVIDUAL I JOIN
DiTestDatabase.dbo.MEMBER M
ON M.INDIVIDUAL_REF = I.INDIVIDUAL_REF
WHERE m.member_status IN (33,1316) AND
LEN(i.FORENAMES) > 1 AND i.FORENAMES != '' AND
i.FORENAMES IS NOT NULL AND i.KNOWN_AS IS NOT NULL;
Note :
LEN() will return INT type. So, you don't need to use ''.
Might be below query will help you.
SELECT i.individual_ref, 0, 'KNOWNAS', i.FORENAMES, i.KNOWN_AS
,CASE WHEN i.KNOWN_AS IS NULL THEN 'null'
ELSE 'Not null' END AS KNOWN_AS2
FROM DiTestDatabase.dbo.INDIVIDUAL I JOIN
DiTestDatabase.dbo.MEMBER M
ON M.INDIVIDUAL_REF = I.INDIVIDUAL_REF
WHERE m.member_status IN (33,1316) AND
LEN(i.FORENAMES) > 1 AND i.FORENAMES != '' AND
i.FORENAMES IS NOT NULL AND i.KNOWN_AS IS NOT NULL;
this way we can get solution
SELECT * FROM (
SELECT i.individual_ref, 0, 'KNOWNAS', i.FORENAMES, i.KNOWN_AS,
case when KNOWN_AS is null then 'Null' else 'Not null' end as known_as
FROM DiTestDatabase.dbo.INDIVIDUAL I
JOIN DiTestDatabase.dbo.MEMBER M ON M.INDIVIDUAL_REF=I.INDIVIDUAL_REF
WHERE m.member_status IN(33,1316)
AND i.KNOWN_AS IS null or i.KNOWN_AS=''
and m.MEMBER_STATUS in (33,1316)
and LEN(i.FORENAMES) > 1 and i.FORENAMES !=''
AND i.FORENAMES IS NOT NULL) t
WHERE t.known_as='Not null'

Why does SQL Server skip over an IF statement?

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

Optimizing a Postgres query

I have following query
SELECT
ca.sfid,
CASE WHEN p.Name IS NOT NULL THEN p.Name ELSE '' END AS Property,
CASE WHEN uc.Name IS NOT NULL THEN uc.Name ELSE '' END AS UnitofInterest,
CASE WHEN fp.Name IS NOT NULL THEN fp.Name ELSE '' END AS FloorplanofInterest,
CASE WHEN ca.Status IS NOT NULL THEN ca.Status ELSE '' END AS Status,
CASE WHEN ca.Origin IS NOT NULL THEN ca.Origin ELSE '' END AS Origin,
CASE
WHEN ca.IC_Call_Answered_by_AH__c = 'true' THEN 'Anyone Home'
ELSE 'Property'
END AS AnswerBy,
CASE WHEN ca.CaseNumber IS NOT NULL THEN ca.CaseNumber ELSE '' END AS CaseNumber,
CASE WHEN ca.Ad_Source_Type__c IS NOT NULL THEN ca.Ad_Source_Type__c ELSE '' END AS Source,
CONCAT(c.FirstName,' ',c.LastName) AS contactname,
CASE WHEN (c.Phone IS NOT NULL OR c.Phone != '' ) THEN c.Phone ELSE '' END AS Phone,
CASE WHEN c.MobilePhone IS NOT NULL THEN c.MobilePhone ELSE '' END AS Mobile,
CASE WHEN c.Email IS NOT NULL THEN c.Email ELSE '' END AS Email,
CASE WHEN c.most_recent_military_pay_grade__c IS NOT NULL THEN c.most_recent_military_pay_grade__c ELSE '' END AS MilitaryPayGrade,
CASE WHEN ca.Price_Quoted_1__c IS NOT NULL THEN ca.Price_Quoted_1__c ELSE '' END AS "price/termquoted",
CASE WHEN ca.Move_in_Date__c IS NOT NULL THEN to_char(ca.Move_in_Date__c AT TIME ZONE 'US/Pacific', 'MM/DD/YYYY') ELSE '' END AS MoveinDate,
CASE WHEN ca.Of_Occupants__c::varchar IS NOT NULL THEN ca.Of_Occupants__c::varchar ELSE '' END AS "#occupants",
CASE WHEN ca.Bed_Count_Pref__c IS NOT NULL THEN ca.Bed_Count_Pref__c ELSE '' END AS BedCountPref,
CASE WHEN ca.Bath_Count_Pref__c IS NOT NULL THEN ca.Bath_Count_Pref__c ELSE '' END AS BathCountPref,
CASE WHEN ca.Pet_Count__c::varchar IS NOT NULL THEN ca.Pet_Count__c::varchar ELSE '' END AS "#pets",
CASE WHEN ca.Pet_Type__c IS NOT NULL THEN ca.Pet_Type__c ELSE '' END AS PetTypes,
CASE WHEN ca.Breed__c IS NOT NULL THEN ca.Breed__c ELSE '' END AS Breed,
CASE WHEN ca.Pet_Name__c IS NOT NULL THEN ca.Pet_Name__c ELSE '' END AS PetName,
CASE
WHEN (ca.Desired_Rent_Start__c IS NOT NULL AND ca.Desired_Rent_Range_End__c IS NOT NULL) THEN CONCAT(ca.Desired_Rent_Start__c,' - ',ca.Desired_Rent_Range_End__c)
ELSE ''
END AS DesiredRentRange,
CASE WHEN ca.Desired_Lease_length__c::varchar IS NOT NULL THEN ca.Desired_Lease_length__c::varchar ELSE '' END AS DesiredLeaseLength,
CASE WHEN ca.Reason_for_Moving__c IS NOT NULL THEN ca.Reason_for_Moving__c ELSE '' END AS ReasonforMoving,
CASE WHEN ca.Notes__c IS NOT NULL THEN ca.Notes__c ELSE '' END AS Notes,
CASE WHEN ca.Reasons_For_Not_Setting_a_Showing__c IS NOT NULL THEN ca.Reasons_For_Not_Setting_a_Showing__c ELSE '' END AS ReasonforNotSettingShowing,
CASE WHEN ca.CreatedDate IS NOT NULL THEN to_char(ca.CreatedDate AT TIME ZONE 'US/Pacific', 'MM/DD/YYYY HH:MI AM') ELSE '' END AS "date/timeopened",
CASE
WHEN app.appointment_date__c IS NOT NULL THEN CONCAT(to_char(app.appointment_date__c AT TIME ZONE 'US/Pacific', 'MM/DD/YYYY'),' ',app.from__c,'-',app.to__c)
ELSE ''
END AS "appointmentdate/time",
CASE WHEN ca.Yardi_Guest_Card_ID__c IS NOT NULL THEN ca.Yardi_Guest_Card_ID__c ELSE '' END AS PMSGuestCardID,
rank() OVER (PARTITION BY ca.contactid, ca.property_of_interest__c ORDER BY ca.createddate DESC)
FROM
salesforce.Case ca
INNER JOIN salesforce.Contact c on ca.ContactId = c.sfid AND c.accountId = ca.accountId
LEFT JOIN salesforce.Appointment__c app ON ca.sfid = app.case__c
LEFT JOIN salesforce.Property__c p ON p.sfid = ca.Property_of_Interest__c AND p.account__c = ca.accountId
LEFT JOIN salesforce.Floor_Plan__c fp ON ca.Floor_Plan_of_Interest__c = fp.sfid AND fp.account__c = ca.accountId
LEFT JOIN salesforce.Unit__c uc ON ca.Unit_of_Interest__c = uc.sfid AND uc.account__c = ca.accountId
WHERE
ca.Guest_Card_Status__c = 'Sent via Workflow'
AND ca.accountId = '001i000000ESO3CAAX'
AND to_char(to_char(ca.createddate AT TIME ZONE 'UTC' AT TIME ZONE 'US/Pacific','YYYY-MM-DD HH24:MI:SS')::date, 'YYYY-MM-DD') BETWEEN '2016-06-02' AND '2016-07-02'
AND to_char(c.Last_Activity__c AT TIME ZONE 'US/Pacific', 'YYYY-MM-DD') BETWEEN '2016-03-04' AND '2016-07-02'
AND ( ca.Status IN ( 'Inquiry', 'Showing Set', 'Showing Completed', 'Application Pending', 'Resident' ) )
AND ( ca.IC_Call_Answered_by_AH__c IN ( 'false', 'true' ) )
AND ( ca.origin IN ( 'Phone', 'Email', 'Voicemail', 'Chat', 'Walk-In', 'Web' ) OR ca.origin IS NULL OR ca.origin = '' ) LIMIT 20 OFFSET 0
And following is the query plan for it
We have indexes on following columns:
AccountId
createddate
Status
Origin
Using PostgreSQL.
But query is taking long time to run. Can you please suggest any optimization in it?
Thanks
Without knowing much about your data set and being unable to read the screenshot of the query plan, I see a couple easy improvements you can make.
First, your use of the indexed columns accountId, status, and origin columns is fine. However, your usage of the createddate column is flawed. By converting the column to a string and then performing a comparison after it has been converted to a string, you are no longer using the index -- Postgres must perform a full scan and run two costly to_char conversions.
Qualify on your createddate column with a comparison native to the datatype of the column.
For example, if the datatype of createdate is timestamp, then you could qualify on it like this:
AND ca.createdate BETWEEN '2016-06-02'::timestamp AND '2016-07-02'::timestamp
This will use the index and it will perform much better.
Second, make sure that you've created one index that uses all four of the columns you've listed. If you have created four separate indexes for each of those columns, then you are not realizing the full performance gains possible from indexing. An index that uses all four of the columns will allow Postgres to progressively narrow down the result set with each column. If you have four separate indexes, then Postgres can only narrow down the result set with one column.

SQL query causing error due to group by statement (INVALID COLUMNS)

I have following SQL:
DECLARE #EmpId AS Varchar(20),
#CompanyId as VARCHAR(20),
#DepartmentId AS VARCHAR(20),
#DesignationId AS VARCHAR(20),
#GradeId AS VARCHAR(20),
#FromDate AS DATE,
#TillDate AS DATE
SET #EmpId = null
SET #CompanyId = NULL
SET #DepartmentId = NULL
SET #DesignationId = NULL
SET #GradeId = NULL
SET #FromDate = '1-1-2015'
SET #TillDate = '1-1-2016'
SELECT
LA.EmpId,AT.IsPaid AS 'IsPaid',
AT.AttendanceTypeCode,
(SELECT DISTINCT IsPaid
FROM LeaveApproval
WHERE empid = LA.EmpId) AS 'testPAID',
SUM(CASE WHEN AT.IsPaid = 1 THEN 1 END) AS Paid,
COUNT(CASE WHEN AT.IsPaid = 0 THEN AT.AttendanceTypeCode END) AS UnPaid,
COUNT(AT.AttendanceTypeCode) AS LeaveCount
FROM
LeaveApproval LA
INNER JOIN
AttendanceTypes AT ON LA.AttendanceTypeId = AT.AttendanceTypeId
INNER JOIN
EmpMaster EM ON LA.Empid = EM.EmpId
WHERE
EM.ActiveInActive <> 1 AND
EM.EmpId = CASE WHEN ISNULL(#EmpId ,'-1') <> '-1' AND #EmpId <> ''
THEN #EmpId
ELSE EM.EmpId
END
AND EM.CompanyId = CASE WHEN ISNULL(#CompanyId ,'-1') <> '-1' AND #CompanyId <> ''
THEN #CompanyId
ELSE EM.CompanyId
END
AND EM.DepartmentId = CASE WHEN ISNULL(#DepartmentId,'-1') <> '-1' AND #DepartmentId<> ''
THEN #DepartmentId
ELSE EM.DepartmentId
END
AND ISNULL(EM.DesignationId, '') = CASE WHEN ISNULL(#DesignationId ,'-1') <> '-1' AND #DesignationId <> '' THEN #DesignationId ELSE ISNULL(EM .DesignationId,'') END
AND ISNULL(EM.GradeId,'') = CASE WHEN ISNULL(#GradeId ,'-1') <> '-1' AND #GradeId <> '' THEN #GradeId ELSE ISNULL(EM .GradeId,'') END
AND FromDate BETWEEN #FromDate AND #TillDate
GROUP BY
LA.EmpID, AT.AttendanceTypeCode, AT.IsPaid, Paid, UnPaid
The above SQL is not working.
I get an error
Column Paid and InPaid are invalid.
What I know is that 'Paid' and Unpaid are from subquery and are NOT available in select list's group by.
My question is how can I achieve the above outcome after running my SQL my outcome should repeat same value which is sum for Paid for each empid
Any help will be appreciated
You cannot use an alias of a column of the current SELECT in its GROUP BY. You have to either do this:
Group By LA.EmpID,AT.AttendanceTypeCode,AT.IsPaid,SUM(CASE WHEN AT.IsPaid=1 Then 1 END), COUNT(CASE WHEN AT.IsPaid=0 Then AT.AttendanceTypeCode END)
Or use all your SELECT as a subquery and group by as you planned in the outer query.
DECLARE #EmpId AS Varchar(20),
#CompanyId as VARCHAR(20),
#DepartmentId AS VARCHAR(20),
#DesignationId AS VARCHAR(20),
#GradeId AS VARCHAR(20),
#FromDate AS DATE,
#TillDate AS DATE
Set #EmpId=null
SET #CompanyId= NULL
SET #DepartmentId=NULL
SET #DesignationId=NULL
SET #GradeId=NULL
SET #FromDate='1-1-2015'
SET #TillDate='1-1-2016';
with LeaveApprovalCTE as
(
Select
AT.IsPaid as 'IsPaid',
AT.AttendanceTypeCode, (select distinct IsPaid from LeaveApproval where empid=LA.EmpId) as 'testPAID',
CASE WHEN AT.IsPaid=1 Then 1 END as Paid,
CASE WHEN AT.IsPaid=0 Then AT.AttendanceTypeCode END as UnPaid,
AT.AttendanceTypeCode AS LeaveCount
From
LeaveApproval LA
INNER JOIN AttendanceTypes AT ON LA.AttendanceTypeId = AT.AttendanceTypeId
INNER JOIN EmpMaster EM ON LA.Empid = EM.EmpId
WHERE
EM.ActiveInActive <> 1 AND
EM.EmpId = CASE WHEN ISNULL(#EmpId ,'-1') <> '-1' AND #EmpId <> '' THEN #EmpId ELSE EM .EmpId END
AND
EM.CompanyId = CASE WHEN ISNULL(#CompanyId ,'-1') <> '-1' AND #CompanyId <> '' THEN #CompanyId ELSE EM .CompanyId END
AND
EM.DepartmentId = CASE WHEN ISNULL(#DepartmentId,'-1') <> '-1' AND #DepartmentId<> '' THEN #DepartmentId ELSE EM .DepartmentId END
AND
ISNULL(EM.DesignationId,'') = CASE WHEN ISNULL(#DesignationId ,'-1') <> '-1' AND #DesignationId <> '' THEN #DesignationId ELSE ISNULL(EM .DesignationId,'') END
AND
ISNULL(EM.GradeId,'') = CASE WHEN ISNULL(#GradeId ,'-1') <> '-1' AND #GradeId <> '' THEN #GradeId ELSE ISNULL(EM .GradeId,'') END
AND
FromDate BETWEEN #FromDate AND #TillDate
)
Select
AttendanceTypeCode,
SUM(Paid) as paid ,
COUNT(UnPaid) as unpaid,
COUNT(LeaveCount) AS LeaveCount
from LeaveApprovalCTE
Group By AttendanceTypeCode,IsPaid,Paid,UnPaid
Use CTE for add new columns in query . Modify your query like this . hope it will work for you

Execution of sql query takes a long time

I have this problem with my query that it is really slow. I am using MSSQL server 2008 and have 3 DB with hundreds of sample data in it. The query will return a name and value and a computed percentage based on the 3 DBs. But the query I have will take almost 10mins to execute which is really a long time to take. I am still learning SQL and still not that good so I think the query I have is not using the best practice and not organized. Can anybody point to me where or how I can improve my query to run faster?
SELECT data.Ret,
case
when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5') and (data.rowid % 50) = 0 then (data.rowid / 50)-1
when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5') then (data.rowid / 50)
else 0 end as batchStore
,data.MajorName,data.MinorName,data.MajorVal,data.MinorVal,data.Version
,data.A_Percent,data.T_Percent,data.F_Percent
from
(
SELECT report.Ret,
CASE when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5')
then row_number() over (PARTITION BY report.Ret,report.Version order by report.Ret, report.MajorName)
else 0 end as rowid
,report.MajorName,report.MinorName,report.MajorVal,report.MinorVal,report.Version
,report.GTotal_A,report.GTotal_T,report.GTotal_F
,ISNULL(sum(report.Abn) / NULLIF(cast(report.GTotal_A as decimal),0),0) * 100 as A_Percent
,ISNULL(sum(report.Trn) / NULLIF(cast(report.GTotal_T as decimal),0),0) * 100 as T_Percent
,ISNULL(sum(report.Fld)/ NULLIF(cast(report.GTotal_F as decimal),0) * 100,0) as F_Percent
From
(
Select
CASE #group_by
WHEN 'object' THEN csl.s_name
WHEN 'site' THEN csl.s_name
WHEN 'year' THEN CAST(YEAR(dy.Day_Stamp) AS VARCHAR(50))
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeName,'') AS VARCHAR(50))
ELSE ''
END as MajorName,
CASE #group_by
WHEN 'object' THEN l.l_name
WHEN 'site' THEN ''
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeName,'') AS VARCHAR(50))
ELSE ''
END as MinorName,
CASE #group_by
WHEN 'object' THEN csl.s_name
WHEN 'site' THEN csl.s_name
WHEN 'year' THEN CAST(YEAR(dy.Day_Stamp) AS VARCHAR(50))
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeValue,'') AS VARCHAR(50))
ELSE ''
END as MajorVal,
CASE #group_by
WHEN 'object' THEN l.l_name
WHEN 'site' THEN ''
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeValue,'') AS VARCHAR(50))
ELSE ''
END as MinorVal,
csl.Cust_Name as Ret,l.SWVersion as Version
,d.Abn,d.Trn,d.Fld,data.GTotal_A ,data.GTotal_T,data.GTotal_F
From db_mon.dbo.CustSL csl
join db_tax.dbo.vwLane l
on (l.externalid = csl.custsl_id)
join db_mon.dbo.DaySummary dy
on (dy.Str = csl.s_name and dy.Lne = csl.l_name and year(dy.day_stamp) = year(#time_start_date) and year(dy.day_stamp) =year(#time_end_date))
Left Outer Join
(
Select a.id As AttributeId, a.attribute_name As AttributeName,
(Case When a.attribute_value_type = 'string' Then ea.string_value
Else (Case When a.attribute_value_type = 'integer' Then cast(ea.integer_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'date' Then cast(ea.date_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'boolean' Then cast(ea.boolean_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'entity' Then cast(ea.ref_entity_id as nvarchar(100)) Else null End)
End)
End)
End)
End) As AttributeValue,
e.id As EntityId
From db_tax.dbo.entity_type et
Inner Join db_tax.dbo.entity As e on et.id = e.entity_type_id
Inner Join db_tax.dbo.entity_attribute As ea on e.id = ea.entity_id
Inner Join db_tax.dbo.attribute As a on ea.attribute_id = a.id
WHERE et.entity_type_name in ('Sticker','Label') And
a.id = (case WHEN #attribute_id = '' then 1 else cast(#attribute_id as int) end)
) AS attrib
On attrib.EntityId = l.L_Id
inner join db_mon.dbo.DaySummary d
on (csl.Cust_Name = d.Ret and csl.s_name = d.stckr and csl.l_name = d.label and l.SWVersion = d.Version)
join (
SELECT Ret,version,sum(Abn) as GTotal_A,sum(Trn) as GTotal_T,sum(Fld) as GTotal_F
from db_mon.dbo.DaySummary
where day_stamp >= #time_start_date and day_stamp <=#time_end_date
GROUP BY Ret,version
) data
on (d.Ret = data.Ret and l.SWVersion = data.Version)
WHERE (CHARINDEX(',' + CONVERT(VARCHAR,l.S_Id) + ',','xxx,' + #entities + ',xxx')>0 OR CHARINDEX(',' + CONVERT(VARCHAR,l.L_Id) + ',','xxx,' + #entities + ',xxx')>0)
and d.day_stamp >= #time_start_date
and d.day_stamp <=#time_end_date
) As report
Group By report.Ret,report.Version,report.MajorName,report.MinorName,report.MajorVal,report.MinorVal
,report.GTotal_A,report.GTotal_T,report.GTotal_F
)data
order By data.Ret,data.Version,batchStore,data.MajorName,data.MinorName,data.MajorVal,data.MinorVal
Does using a lot of join causes the slow execution?
SUB Select queries will always be slower then proper joins.
You are running 3 sub selects deep. This is going to impact your performance regardless of changing indexes etc.
You need to rewrite the whole thing to stop using sub selects.