Optimizing a Postgres query - sql

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.

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'

SSRS - Empty value

I have a parameter #Destinataire in SSRS that has a list of values plus an empty string
I've created a query that I set as available values, which gives me the drop down list
SELECT code_name FROM tableA UNION ALL SELECT ''
When running the reports with the empty string, I have no results
I tried to set the parameter as text box and it does not do anything too
Yet when running the sql query I'm using to run this report, things are fine as I have all my rows retrieved (see query below)
DECLARE #DateCmt DATE = '05/09/2015',
#DateFin DATE = '05/09/2016',
#Restriction INT = 1,
#Destinataire VARCHAR(5) = ''
--
;
--SELECT #DateCmt,#DateFin
SELECT DISTINCT
CFE_EDI.IU_LIASSE
,CFE_EDI.ETAT
,CFE_EDI.DATHRMAJ -- nouveau
,CFE_EDI.ESP_APPLI
,CFE_EDI.NOM_RS
,PARTENAIRES.LIBEL
,PARTENAIRES.CODE_INSEE
,CFE_EDI.DATHR_ENV -- nouveau
,CFE_EDI.DATHR_MEF -- nouveau
,CFE_EDI.DATHR_PRE -- nouveau
,CFE_EDI.DATHR_OUV -- nouveau
--,CFE_EDI.DATEHR_DEPOT-- mettre l'heure
,CFE_EDI.GESTDEL
--,CFE_SERVICE_DEST.IU_DEST
--,CFE_SERVICE.IU_LIASSE
,CASE WHEN CFE_EDI.ETAT = 'MEF' THEN 'En Attente le'
WHEN CFE_EDI.ETAT = 'PRE' THEN 'Préparé le'
WHEN CFE_EDI.ETAT = 'ENV' THEN 'Envoyé le'
WHEN CFE_EDI.ETAT = 'OUV' THEN 'Réceptionné le'
WHEN CFE_EDI.ETAT = 'NRM' THEN 'Non remis le'
WHEN CFE_EDI.ETAT = 'NAQ' THEN 'Non acquitté le'
END AS ChampEtat
,CASE WHEN CFE_EDI.ETAT = 'OUV' THEN 'Date d''envoi : ' + CONVERT(VARCHAR,CFE_EDI.DATHR_ENV,103)
END AS Date_Envoi,
CASE
WHEN CFE_EDI.ETAT='MEF' THEN CONVERT(VARCHAR,CFE_EDI.DATHR_MEF,103)
WHEN CFE_EDI.ETAT='PRE' THEN CONVERT(VARCHAR,CFE_EDI.DATHR_PRE,103)
WHEN CFE_EDI.ETAT='ENV' THEN CONVERT(VARCHAR,CFE_EDI.DATHR_ENV,103)
WHEN CFE_EDI.ETAT='OUV' THEN CONVERT(VARCHAR,CFE_EDI.DATHR_OUV,103)
ELSE CONVERT(VARCHAR,CFE_EDI.DATHR_DEPOT,103) END AS DateMaj ,
CASE
WHEN CFE_EDI.ETAT='MEF' then CONVERT(VARCHAR,CFE_EDI.DATHR_MEF,108)
WHEN CFE_EDI.ETAT='PRE' then CONVERT(VARCHAR,CFE_EDI.DATHR_PRE,108)
WHEN CFE_EDI.ETAT='ENV' then CONVERT(VARCHAR,CFE_EDI.DATHR_ENV,108)
WHEN CFE_EDI.ETAT='OUV' then CONVERT(VARCHAR,CFE_EDI.DATHR_OUV,108)
ELSE CONVERT(VARCHAR,CFE_EDI.DATHR_DEPOT,108) END AS HeureMaj,
PARTENAIRES.LIBEL + '(' + CFE_EDI.CODE_INSEE + ')' AS LibelDestinataire
--,CASE WHEN #Restriction = 1 THEN '1'
-- WHEN #Restriction = 0 THEN '0' END AS Restriction
,CASE WHEN #DateCmt != #DateFin AND #DateCmt < #DateFin THEN 'Diffusion Xml du ' + CONVERT(VARCHAR,(#DateCmt),103) + ' au ' + CONVERT(VARCHAR,(#DateFin),103) ELSE
'Diffusion EDI Xml du ' + CONVERT(VARCHAR,#DateCmt,103) END AS Plage_Diffusion
-- INTO
FROM
(PARTENAIRES
INNER JOIN dbo.CFE_EDI ON PARTENAIRES.CODE_INSEE = CFE_EDI.CODE_INSEE)
INNER JOIN dbo.CFE_SERVICE ON CFE_EDI.IU_LIASSE = CFE_SERVICE.IU_LIASSE
INNER JOIN dbo.CFE_SERVICE_DEST ON (PARTENAIRES.IU_PART = CFE_SERVICE_DEST.IU_PART_CFE)
WHERE
case when #Restriction = 1
then case when CFE_EDI.ETAT in('ENV','OUV') then 1 else 0 end
when #Restriction = 0
then case when CFE_EDI.ETAT not in('ENV','OUV') then 1 else 0 end
else case when CFE_EDI.ETAT <> '' then 1 else 0 end
end = 1
AND
CFE_EDI.CODE_INSEE IS NOT NULL AND CFE_EDI.CODE_INSEE != ''
AND CASE --WHEN CFE_EDI.CODE_INSEE IS NOT NULL AND CFE_EDI.CODE_INSEE !=''
--THEN CASE
WHEN #Destinataire != '' AND (#Destinataire) IS NOT NULL
THEN CASE WHEN CFE_EDI.CODE_INSEE = #Destinataire THEN 1 ELSE 0 END
ELSE CASE WHEN CFE_EDI.CODE_INSEE = PARTENAIRES.CODE_INSEE
AND cfe_edi.dathrmaj > #DateCmt AND cfe_edi.dathrmaj < #DateFin
AND CFE_EDI.GESTDEL = '1' THEN 1 ELSE 0 END
END = 1
First question would be to know if there is way to setup the parameter without using my stupid trick.
Second question is why the query with parameter with an empty string does the trick and once you use SSRS, nothing.
Thanks in advance for your help
Update I tried to set the WHEN LEN(#Destinataire) > 0 with the #Destinataire = '' but no luck on that one.
Update 2 My aim now is to have a solution that will retrieve all the datas, in case the #Destinataire is equal to '' or NULL. However, thinking about it, this solution is equivalent to having all the values populated in #Destinataire. So one way or another, I would say.
Final update I've recreated everything from scratch and oh! magic, the grouping or the everything option worked as wish. I still don't know what was wrong but I'm fine with the results. Many thanks for your help and support.
looking at your query and where you pass #Destinataire you should be able to pass a null value according to the where clause and get the same effect as passing ''
CASE --WHEN CFE_EDI.CODE_INSEE IS NOT NULL AND CFE_EDI.CODE_INSEE !=''
--THEN CASE
WHEN #Destinataire != '' AND (#Destinataire) IS NOT NULL
THEN CASE WHEN CFE_EDI.CODE_INSEE = #Destinataire THEN 1 ELSE 0 END
ELSE CASE WHEN CFE_EDI.CODE_INSEE = PARTENAIRES.CODE_INSEE
AND cfe_edi.dathrmaj > #DateCmt AND cfe_edi.dathrmaj < #DateFin
AND CFE_EDI.GESTDEL = '1' THEN 1 ELSE 0 END
END = 1
I would try to just set that particular paramter to allow nulls in the ssrs report which can be found as a checkbox in your parameter settings window.
There is a hybrid option, where you can keep your visible parameter just as you have it, but then use a hidden cascaded parameter to reference in the query. So if you really are having trouble with formulating your query with blank or null values as a parameter, this will work around that. Here are the steps:
Create a new dataset.
A slight catch, you do need to make sure that the changing the selection always adds a new value to force a refresh of the cascaded parameter, but that's easy to do:
SELECT code_name FROM tableA WHERE #Destinataire='' OR #Destinataire=code_name
--Dummy value needed to force update of parameter value in some cases:
UNION SELECT 'zz' + #Destinataire AS code_name
Set up a new parameter, #MultiDestataire. Allow it to accept multiple values and use the new dataset as its available and default values. Set its visibility to Hidden.
Running the report before hiding the new parameter shows how it works:
Edit the query to use the new multivalue parameter in its WHERE clause.
From here on, this is just altering the query to use the IN statement, which should look like this:
CFE_EDI.CODE_INSEE IS NOT NULL AND CFE_EDI.CODE_INSEE != ''
AND CFE_EDI.CODE_INSEE IN (#MultiDestinataire)
...
Attempting this may end up being an intermediary step if you've got some other issue in the query that's responsible for unexpected results, as you should be able to test for an empty value there.
This is just my two cents, basically you have two options here.
Multivalue parameter Option
Define your parameter to allow multivalues, use the same dataset in Available values and Default values properties. So when your user doesn't select any value the parameter will be populated with all values. Otherwise your parameter will be populated only with values your users select.
In this case you will have to use IN operator since your parameter represent multiple values seleted or not by your user.
...
WHERE CFE_EDI.CODE_INSEE IN (#Destinataire)
...
When you use Default values property all drop down list values are selected by default and your report run without any filter being applied (at least if your user doesn't select any value or values).
Additional, I'd avoid use '' (blank), it is uninformative and your user might think it is some kind of error or your parameter was not populated properly.
Why use a single value parameters when you want to show data from more than one value (in your case all)?
Single value Option (No sense IMO)
In order to this works you have to set your parameter to Allow blank value ("") and Allow null value. Your query should look like this:
WHERE
CASE WHEN #Destinataire = '' OR #Destinataire is null THEN 1 ELSE 0 END = 1
OR
CFE_EDI.CODE_INSEE = #Destinataire
In your query I think it could be something like this:
WHERE CASE
WHEN #Restriction = 1 THEN
CASE
WHEN cfe_edi.etat IN( 'ENV', 'OUV' ) THEN 1
ELSE 0
END
WHEN #Restriction = 0 THEN
CASE
WHEN cfe_edi.etat NOT IN( 'ENV', 'OUV' ) THEN 1
ELSE 0
END
ELSE
CASE
WHEN cfe_edi.etat <> '' THEN 1
ELSE 0
END
END = 1
AND cfe_edi.code_insee IS NOT NULL
AND cfe_edi.code_insee != ''
AND ( CASE
--WHEN CFE_EDI.CODE_INSEE IS NOT NULL AND CFE_EDI.CODE_INSEE !=''
--THEN CASE
WHEN ( #Destinataire = ''
OR #Destinataire IS NULL )
AND cfe_edi.code_insee = partenaires.code_insee
AND cfe_edi.dathrmaj > #DateCmt
AND cfe_edi.dathrmaj < #DateFin
AND cfe_edi.gestdel = '1' THEN 1
ELSE 0
END = 1
OR cfe_edi.code_insee = #Destinataire )
Also consider this evaluation AND cfe_edi.code_insee = partenaires.code_insee, is it necessary even if your JOIN operator is forcing to meet the condition? INNER JOIN dbo.CFE_EDI ON PARTENAIRES.CODE_INSEE = CFE_EDI.CODE_INSEE
A third option could be use a hidden parameter to clean the null and '' option of the user to produce a parameter populated with all values. Try the options above before get involved with hidden/internal parameter approach.
Let me know if this helps.

CASE statement giving wrong results inside my stored procedure

I have a case inside my stored procedure which I use before executing the data.
DECLARE #Setup nvarchar(50)
SELECT
#ZipCode = CASE
WHEN REPLACE(#ZipCode, '0', '') = ''
THEN NULL ELSE #ZipCode
END,
#ZipCodeEND = CASE
WHEN REPLACE(#ZipCodeEND, '0', '') = ''
THEN NULL ELSE #ZipCodeEND
END,
SELECT
#Setup = CASE WHEN (LEN(ISNULL(#ZipCode, ''))) > 0 THEN '1' ELSE '0' END +
CASE WHEN (LEN(ISNULL(#ZipCodeEND,''))) > 0 THEN '1' ELSE '0' END
IF ISNULL(#ID, 0) = 0
BEGIN
INSERT INTO dbo.MapToStaticValuesTable(ZipCode, ZipCodeEND, Setup)
VALUES(#ZipCode, #ZipCodeEND, #Setup)
END
The problem here is even if zipcode and zipcodeEnd are empty and set to null after being saved into the table I keep getting the value "11" instead of getting "00".
Now if I do the same example with nvarchar values it would work, but since ZipCode and ZipCodeEnd are set to int it's acting weird.
It is acting weird because you are using string functions on integers. Not sure what you are trying to achieve with your code but I'm sure it can be done just by checking the values as integers.
I guess this could be what you are looking for.
select case when nullif(#ZipCode, 0) is null then '0' else '1' end +
case when nullif(#ZipCodeEND, 0) is null then '0' else '1' end
One example of weird
select isNull(#ZipCode, '')
return 0 if #ZipCode is null.

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.

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