Bad bind variables in oracle stored procedure - database

I am totally new to stored procedures. I have a query and I wanna use it for a web service. I am going to use Nhibernate. I have tried couple of procedures and worked well. But this one giving me problems. I tried to compile the stored procedure but giving me errors.
create or replace
PROCEDURE GET_RSM_LIFE_AGENT_DUES (p_recordset OUT SYS_REFCURSOR, :Year IN number, :Month IN number, :Branch IN number, :Agency IN number) AS
BEGIN
OPEN p_recordset for
select :Year as required_year, :Month as required_month,
case when pmagt = 0 then D.branch_code else E.branch_code end as branch_code,
case when pmagt = 0 then D.branch_name else E.branch_name end as branch_name,
case when pmagt = 0 then D.region else E.region end as region,
pmagt as agency,
status || ' ' || int || ' ' || name as agent_name,
pmpol as policy_no,
pmcom as commence_date,
pmtrm as term,
pmmod as policy_mode,
case WHEN pmtbl not in (51,22,74,75,76) and ((:Year - SUBSTR (pmcom,1,4)) * 12 + to_number(:Month) - SUBSTR (pmcom,-4,2)) < 12 then 'FYR'
WHEN pmtbl not in (51,22,74,75,76) and ((:Year - SUBSTR (pmcom,1,4)) * 12 + to_number(:Month) - SUBSTR (pmcom,-4,2)) >= 12 then 'Renewal' else '' end as premium_type,
case when llprm is not null and pmprm < llprm then llprm else pmprm end as due_Premium,
case when llprm is not null then llprm else 0 end as due_paid_premium
FROM lphs.premast A left outer join lclm.ledger B on (A.pmpol = B.llpol) and (to_number(:Year || :Month) = lldue)
left outer join agent.agent C on (A.pmagt = C.agency)
left outer join BAU.SLIC_BRANCH_LIST D on (A.pmobr = D.csp_code)
left outer join BAU.SLIC_BRANCH_LIST E on (C.branch = E.csp_code)
WHERE add_months(to_date(PMCOM,'YYYYMMDD'),PMTRM*12) >= add_months( to_date(:Year || :Month || 01 ,'YYYYMMDD'),1)
and to_date(pmcom,'yyyymmdd') < to_date(:Year || :Month || 01 ,'YYYYMMDD')
and pmmod <> 5
and stid in ('Ag' , 'ME', 'Or')
and case when to_date(pmcom,'yyyymmdd') >= to_date(:Year || :Month || 01 ,'YYYYMMDD') then 'N'
when pmmod = 4 then 'Y'
when pmmod = 3 and remainder ( abs( to_number ( substr (pmcom, 5,2) ) - to_number ( :Month ) ) , 3 ) =0 then 'Y'
when pmmod = 2 and remainder ( abs( to_number ( substr (pmcom, 5,2) ) - to_number ( :Month ) ) , 6 ) =0 then 'Y'
when pmmod = 1 and remainder ( abs( to_number ( substr (pmcom, 5,2) ) - to_number ( :Month ) ) , 12 ) =0 then 'Y' else 'N' end = 'Y'
and case when pmagt = 0 then D.branch_code else E.branch_code end = :Branch
and pmagt = :Agency
END GET_RSM_LIFE_AGENT_DUES;
Error.....
Error(2,67): PLS-00049: bad bind variable 'YEAR'
Error(2,67): PLS-00103: Encountered the symbol "" when expecting one of the following: <an identifier> <a double-quoted delimited-identifier> current delete exists prior
Error(2,84): PLS-00049: bad bind variable 'MONTH'

Remove colons from within the procedure. Those are procedure's parameters, so use them as such. Pass their values as e.g.
declare
l_out sys_refcursor;
begin
GET_RSM_LIFE_AGENT_DUES (l_out, :Year, :Month, :Branch, :Agency);
end;

Related

Cant able to create view with following snowflake query

Needs to create view with below columns. Need to understand how to create view using with clause inside the query.
create
or replace view TEST_RRX.DW_RRX.V_SIL_RRX_PTS_BusinessLocation_Dim(
--ROW_WID,
--ADDRESS_TYPE,
BUSN_LOC_NAME,
BUSN_LOC_NUM,
BUSN_LOC_TYPE,
ST_ADDRESS1,
ST_ADDRESS2,
CITY_NAME,
POSTAL_CODE,
STATE_CODE,
COUNTRY_CODE,
ACTIVE_FLG,
CREATED_BY_WID,
CHANGED_BY_WID,
CREATED_ON_DT,
CHANGED_ON_DT,
AUX1_CHANGED_ON_DT,
AUX2_CHANGED_ON_DT,
AUX3_CHANGED_ON_DT,
AUX4_CHANGED_ON_DT,
SRC_EFF_FROM_DT,
SRC_EFF_TO_DT,
EFFECTIVE_FROM_DT,
EFFECTIVE_TO_DT,
DELETE_FLG,
CURRENT_FLG,
W_INSERT_DT,
W_UPDATE_DT,
DATASOURCE_NUM_ID,
--ETL_PROC_WID,
INTEGRATION_ID,
--TENANT_ID,
--X_CUSTOM,
--GEO_COUNTRY_WID,
--GEO_WID,
UPD_FLG
) as WITH CODE AS (
SELECT
W_CODE_D.MASTER_CODE AS MASTER_CODE,
W_CODE_D.MASTER_VALUE AS MASTER_VALUE,
W_CODE_D.SOURCE_CODE AS SOURCE_CODE,
W_CODE_D.DATASOURCE_NUM_ID AS DATASOURCE_NUM_ID,
W_CODE_D.SOURCE_CODE_1 as SOURCE_CODE_1,
W_CODE_D.SOURCE_CODE_2 as SOURCE_CODE_2,
W_CODE_D.SOURCE_NAME_1 as SOURCE_NAME_1,
W_CODE_D.CATEGORY
FROM
W_CODE_D
WHERE
W_CODE_D.LANGUAGE_CODE = 'E'
),
USER_TAB as (
SELECT
LOOKUP_TABLE.ROW_WID as ROW_WID,
LOOKUP_TABLE.DATASOURCE_NUM_ID as DATASOURCE_NUM_ID,
LOOKUP_TABLE.INTEGRATION_ID as INTEGRATION_ID,
LOOKUP_TABLE.EFFECTIVE_FROM_DT as EFFECTIVE_FROM_DT,
LOOKUP_TABLE.EFFECTIVE_TO_DT as EFFECTIVE_TO_DT
FROM
DW_RRX.W_USER_D LOOKUP_TABLE
),
BUSN_LOCATION as (
SELECT
sq.BUSN_LOC_NAME,
sq.BUSN_LOC_NUM,
sq.BUSN_LOC_TYPE,
sq.ST_ADDRESS1,
sq.ST_ADDRESS2,
case when CITY.MASTER_VALUE is null then (
case when sq.CITY_NAME is null
OR LENGTH(sq.CITY_NAME) = 0
OR REGEXP_INSTR(sq.CITY_NAME, ' ')> 0 then 'Unspecified' else sq.CITY_NAME end
) else CITY.MASTER_VALUE end as city_name,
sq.POSTAL_CODE,
case when STATE.MASTER_CODE is null then (
case when sq.STATE_CODE is null
OR LENGTH(sq.STATE_CODE) = 0
OR REGEXP_INSTR(sq.STATE_CODE, ' ')> 0 then 'Unspecified' else sq.STATE_CODE end
) else STATE.MASTER_CODE end as STATE_CODE,
case when COUNTRY.MASTER_CODE is null then (
case when sq.COUNTRY_CODE is null
OR LENGTH(sq.COUNTRY_CODE) = 0
OR REGEXP_INSTR(sq.COUNTRY_CODE, ' ')> 0 then 'Unspecified' else sq.COUNTRY_CODE end
) else COUNTRY.MASTER_VALUE end as COUNTRY_CODE,
'Y' as ACTIVE_FLG,
CREATED_BY.ROW_WID AS CREATED_BY_WID,
CHANGED_BY.ROW_WID AS CREATED_BY_WID,
sq.AUX1_CHANGED_ON_DT,
sq.AUX2_CHANGED_ON_DT,
sq.AUX3_CHANGED_ON_DT,
sq.AUX4_CHANGED_ON_DT,
sq.SRC_EFF_FROM_DT,
sq.SRC_EFF_TO_DT,
case when W_BUSN_LOCATION_D.INTEGRATION_ID is null then current_date else W_BUSN_LOCATION_D.W_INSERT_DT end as EFFECTIVE_FROM_DT,
TO_DATE('01013714', 'DDMMYYYY') as EFFECTIVE_TO_DT,
'N' As DELETE_FLG,
'Y' AS CURRENT_FLG,
case when W_BUSN_LOCATION_D.INTEGRATION_ID is null then current_date else W_BUSN_LOCATION_D.W_INSERT_DT end as W_INSERT_DT,
W_BUSN_LOCATION_D.W_UPDATE_DT as current_date,
sq.DATASOURCE_NUM_ID,
--sq.ETL_PROC_WID,
sq.INTEGRATION_ID,
CASE WHEN (
SELECT
ETL_PROC_WID
FROM
TEST_RRX.DW_RRX.W_PARAM_G
WHERE
ROW_WID = 1
) = W_BUSN_LOCATION_D.ETL_PROC_WID THEN 'X' WHEN W_BUSN_LOCATION_D.INTEGRATION_ID IS NULL THEN 'I' WHEN W_BUSN_LOCATION_D.INTEGRATION_ID IS NOT NULL
AND (
sq.CHANGED_ON_DT <> W_BUSN_LOCATION_D.CHANGED_ON_DT
OR sq.AUX1_CHANGED_ON_DT <> W_BUSN_LOCATION_D.AUX1_CHANGED_ON_DT
OR sq.AUX2_CHANGED_ON_DT <> W_BUSN_LOCATION_D.AUX2_CHANGED_ON_DT
OR sq.AUX3_CHANGED_ON_DT <> W_BUSN_LOCATION_D.AUX3_CHANGED_ON_DT
OR sq.AUX4_CHANGED_ON_DT <> W_BUSN_LOCATION_D.AUX4_CHANGED_ON_DT
) THEN 'U' END as UPD_FLG
FROM
DW_RRX.W_BUSN_LOCATION_DS sq
LEFT OUTER JOIN CODE COUNTRY ON COUNTRY.SOURCE_CODE = sq.country_code
AND COUNTRY.DATASOURCE_NUM_ID = sq.DATASOURCE_NUM_ID
AND COUNTRY.CATEGORY = 'COUNTRY'
LEFT OUTER JOIN CODE CITY ON CITY.SOURCE_CODE_1 = sq.country_code
AND CITY.DATASOURCE_NUM_ID = sq.DATASOURCE_NUM_ID
AND CITY.SOURCE_CODE_2 = sq.STATE_CODE
AND CITY.SOURCE_NAME_1 = sq.CITY_NAME
AND CITY.CATEGORY = 'CITY'
LEFT OUTER JOIN CODE STATE ON STATE.DATASOURCE_NUM_ID = sq.DATASOURCE_NUM_ID
AND STATE.CATEGORY = 'STATE'
LEFT OUTER JOIN USER_TAB CREATED_BY ON sq.DATASOURCE_NUM_ID = CREATED_BY.DATASOURCE_NUM_ID
AND CREATED_BY.INTEGRATION_ID = sq.CREATED_BY_ID
and CREATED_BY.EFFECTIVE_FROM_DT <= sq.CREATED_ON_DT
and CREATED_BY.EFFECTIVE_TO_DT >= sq.CREATED_ON_DT
LEFT OUTER JOIN USER_TAB CHANGED_BY ON sq.DATASOURCE_NUM_ID = CHANGED_BY.DATASOURCE_NUM_ID
AND CHANGED_BY.INTEGRATION_ID = sq.CHANGED_BY_ID
and CHANGED_BY.EFFECTIVE_FROM_DT <= sq.CHANGED_ON_DT
and CHANGED_BY.EFFECTIVE_TO_DT >= sq.CHANGED_ON_DT
LEFT OUTER JOIN W_BUSN_LOCATION_D ON sq.INTEGRATION_ID = W_BUSN_LOCATION_D.INTEGRATION_ID
AND sq.DATASOURCE_NUM_ID = W_BUSN_LOCATION_D.DATASOURCE_NUM_ID
)
SELECT
*
FROM
BUSN_LOCATION
WHERE
UPD_FLG <> 'X'
Getting SQL compilation error: Invalid column definition list
Needs to create view with above columns

Issue with >= in the WHERE clause

I'm at my whit's end with this one, frustrated because I'm sure it's something simple and I need a second set of eyes. I've tried this several different ways and I continue to run into an issue where the query will run for a full 24 hours with no results...
I've narrowed the issue down to this section of the query:
WHERE sub.[Savings (%)] >= 10
I ran into so many issues that I ended up nesting the entire query into a sub query, trying to take most of my calculations out of the "Where" clause, but to no effect.
This is all part of a much larger query, so I'll post the abbreviated portion that is relevant.
Here's the very beginning of the query:
SELECT *
FROM
(
SELECT
LD.Region
,DM.ShortName AS DM
,D.Lcode
,LD.locationname
,D.UnitID
,D.dPlaced
,D.dCancelled
,D.sRentalType
,D.[Quoted Rate]
,Calcs.MinStdRate AS [Current Rate]
,-(Calcs.MinStdRate - D.[Quoted Rate]) AS [Savings ($)]
,((-(Calcs.MinStdRate - D.[Quoted Rate]))/NULLIF(D.[Quoted Rate],0))*100 AS [Savings (%)]
,D.sPlanName
,Calcs.[# Vacant]
FROM...
Then this is the WHERE clause at the very end of the query that causes the issue. The entire query beneath "SELECT * FROM" (shown up above) is called "Sub":
) AS sub
WHERE sub.[Savings (%)] >= 10
AND sub.[Current Rate] <> 0
AND sub.[Quoted Rate] <> 0
When I notate "sub.[Savings (%)] >= 10 AND" out of the query, the whole thing runs in about 5 seconds. With it, it runs for hours on end and never produces results...
What am I missing?
Updating to show whole query per request:
SELECT *
FROM
(
SELECT
LD.Region
,DM.ShortName AS DM
,D.Lcode
,LD.locationname
,D.UnitID
,D.dPlaced
,D.dCancelled
,D.sRentalType
,D.[Quoted Rate]
,Calcs.MinStdRate AS [Current Rate]
,-(Calcs.MinStdRate - D.[Quoted Rate]) AS [Savings ($)]
,CAST(((-(Calcs.MinStdRate - D.[Quoted Rate]))/NULLIF(D.[Quoted Rate],0))*100 AS DECIMAL (18,2)) AS [Savings (%)]
,D.sPlanName
,Calcs.[# Vacant]
FROM
(SELECT
s.sLocationCode AS lcode
,w.dPlaced
,L.dLease
,u.UnitID
,CASE
WHEN w.dCancelled IS NOT NULL THEN w.dCancelled
WHEN (w.dCancelled IS NULL AND w.dExpires <GETDATE()) THEN w.dExpires
ELSE NULL
END AS dCancelled
,CASE
WHEN (w.dCancelled IS NOT NULL OR w.dExpires <GETDATE()) THEN 'Lost'
WHEN w.QTRentalTypeID = 3 THEN 'Rented'
WHEN (w.QTRentalTypeID = 2 OR w.QTRentalTypeID = 1) THEN 'Active'
END AS sRentalType
,w.dcRate_Quoted AS 'Quoted Rate'
,c.sPlanName
,CONCAT(U.dcWidth,'x',U.dcLength) AS sSize
,UT.sTypeName
FROM CompanyDBs.dbo.waitings AS W
LEFT OUTER JOIN CompanyDBs.dbo.Ledgers AS L
ON W.LedgerID = L.LedgerID
JOIN CompanyDBs.dbo.sites AS S
ON W.SiteID = S.SiteID
JOIN CompanyDBs.dbo.units AS U
ON W.UnitID1 = U.UnitID
JOIN CompanyDBs.dbo.UnitTypes AS UT
ON U.UnitTypeID = UT.UnitTypeID
JOIN CompanyDBs.dbo.ConcessionPlans AS C
ON W.ConcessionID = C.ConcessionID
WHERE W.dCancelled < GETDATE() AND W.dCancelled >= DATEADD(DD,-60,CAST(GETDATE() AS DATE))
UNION ALL
SELECT
s.sLocationCode AS lcode
,w.dPlaced
,L.dLease
,u.UnitID
,CASE
WHEN w.dCancelled IS NOT NULL THEN w.dCancelled
WHEN (w.dCancelled IS NULL AND w.dExpires <GETDATE()) THEN w.dExpires
ELSE NULL
END AS dCancelled
,CASE
WHEN (w.dCancelled IS NOT NULL OR w.dExpires <GETDATE()) THEN 'Lost'
WHEN w.QTRentalTypeID = 3 THEN 'Rented'
WHEN (w.QTRentalTypeID = 2 OR w.QTRentalTypeID = 1) THEN 'Active'
END AS sRentalType
,w.dcRate_Quoted AS 'Quoted Rate'
,c.sPlanName
,CONCAT(U.dcWidth,'x',U.dcLength) AS sSize
,UT.sTypeName
FROM CompanyDBs1.dbo.waitings AS W
LEFT OUTER JOIN CompanyDBs1.dbo.Ledgers AS L
ON W.LedgerID = L.LedgerID
JOIN CompanyDBs1.dbo.sites AS S
ON W.SiteID = S.SiteID
JOIN CompanyDBs1.dbo.units AS U
ON W.UnitID1 = U.UnitID
JOIN CompanyDBs1.dbo.UnitTypes AS UT
ON U.UnitTypeID = UT.UnitTypeID
JOIN CompanyDBs1.dbo.ConcessionPlans AS C
ON W.ConcessionID = C.ConcessionID
WHERE W.dCancelled < GETDATE() AND W.dCancelled >= DATEADD(DD,-60,CAST(GETDATE() AS DATE))) AS D
LEFT OUTER JOIN
(SELECT
P.SiteID
,P.sLocationCode
,P.UnitID
,p.UnitCODE
,groupeddata.[# Vacant]
,GroupedData.MinStdRate
FROM
(SELECT
S2.sLocationCode
,S2.SiteID
,R2.UnitID
,CONCAT(S2.sLocationCode
,'-'
,S2.sSiteName
,' '
,R2.stypename
,' '
,CASE WHEN R2.iFloor > 1 THEN 'Up ' WHEN R2.ifloor < 1 THEN 'Down ' WHEN R2.ifloor = 1 THEN '1 ' END
,CASE WHEN R2.bPower = 1 THEN 'Power ' ELSE 'No Power ' END
,CASE WHEN R2.bClimate = 1 THEN 'CC ' ELSE 'No CC ' END
,CASE WHEN R2.bInside = 1 THEN 'In ' ELSE 'Out ' END
,CASE WHEN R2.bAlarm = 1 THEN 'Alarm ' ELSE 'No Alarm ' END
,CAST(R2.dcWidth AS FLOAT)
,'x'
,CAST(R2.dcLength AS FLOAT)) AS UnitCODE
FROM Operations.dbo.RentRoll AS R2
JOIN
(
SELECT *
FROM CompanyDBs.dbo.sites
UNION ALL
SELECT *
FROM CompanyDBs1.dbo.sites
) AS S2
ON R2.siteid = S2.SiteID
WHERE
R2.ddeleted is NULL
AND R2.bRentable = 1
AND R2.brented = 0 ) AS P
JOIN
(
SELECT
S.SiteID
,s.sLocationCode
,UnitCode.UnitCODE
,SUM(CASE
WHEN R.brented = 1 THEN 0
ELSE 1
END) AS [# Vacant]
,MIN(R.dcStdRate) AS MinStdRate
FROM Operations.dbo.RentRoll AS R
JOIN
(
SELECT *
FROM CompanyDBs.dbo.sites
UNION ALL
SELECT *
FROM CompanyDBs1.dbo.sites
) AS S
ON R.siteid = S.SiteID
JOIN
(
SELECT
S1.SiteID
,UnitID
,CONCAT(S1.sLocationCode
,'-'
,S1.sSiteName
,' '
,R1.stypename
,' '
,CASE WHEN R1.iFloor > 1 THEN 'Up ' WHEN R1.ifloor < 1 THEN 'Down ' WHEN R1.ifloor = 1 THEN '1 ' END
,CASE WHEN R1.bPower = 1 THEN 'Power ' ELSE 'No Power ' END
,CASE WHEN R1.bClimate = 1 THEN 'CC ' ELSE 'No CC ' END
,CASE WHEN R1.bInside = 1 THEN 'In ' ELSE 'Out ' END
,CASE WHEN R1.bAlarm = 1 THEN 'Alarm ' ELSE 'No Alarm ' END
,CAST(R1.dcWidth AS FLOAT)
,'x'
,CAST(R1.dcLength AS FLOAT)) AS UnitCODE
FROM Operations.dbo.RentRoll AS R1
JOIN
(
SELECT *
FROM CompanyDBs.dbo.sites
UNION ALL
SELECT *
FROM CompanyDBs1.dbo.sites
) AS S1
ON R1.siteid = S1.SiteID
) AS UnitCode
ON CONCAT(R.siteid, R.unitid) = CONCAT(UnitCode.siteid,UnitCode.UnitID)
WHERE
s.sLocationCode <> 'L003'
AND s.sLocationCode <> 'L021'
AND s.sLocationCode <> 'LSETUP'
AND s.sLocationCode <> 'LTRAIN'
AND R.bRented = 0
GROUP BY s.siteid, s.slocationcode, UnitCode.UnitCODE
) AS GroupedData
ON P.UnitCODE = GroupedData.UnitCODE
) AS Calcs
ON CONCAT(D.lcode,D.unitid) = CONCAT(Calcs.slocationcode,Calcs.unitid)
JOIN operations.dbo.westport_locationdata AS LD
ON D.lcode = ld.lcode
JOIN operations.dbo.Westport_DMs AS DM
ON LD.DMID = DM.DMID
) AS sub
WHERE sub.[Savings (%)] >= CAST(10.0 AS DECIMAL (18,2))
AND sub.[Current Rate] <> 0
AND sub.[Quoted Rate] <> 0
Unfortunately you are posting not the whole query. I could image that some indexes are missing.
I give you the strong advice to run your query in SQL Server Management Studio with the option "Query" -> "Include Actual Execution Plan" checked.
With this, SSMS will execute the query and tell you afterwards if indexes are missing and how much you could improve by setting them. You will get also a picture oh how the query is running.
Cast your where clause filter value WHERE sub.[Savings (%)] >= cast(10.0 as decimal(18,2)) so there isn't an implicit conversion from int to decimal.
https://learn.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine?view=sql-server-ver15#:~:text=Implicit%20conversions%20are%20not%20visible,converts%20to%20date%20style%200.

COUNT(DISTINCT()) Return false value

I try to count total employee in my subquery table. Suppose the count result will return 0, but it keeps returning 1.
If I try to return only employee_id and month together, I didn't get any return value for may which is correct, but each time I try to count(distinct), I will get 1 as my return value. This is my sql
SELECT
count (distinct(CASE WHEN (x.month =5 and x.employee_id <> 0) THEN
x.employee_id
ELSE 0 END)) as test_may
FROM(
(
SELECT
h.month,
h.employee_id,
eb.employee_no,
ee.company_code,
h.amount,
h.year,
h.trx_type,
h.trx_code,
v.trx_desc,
h.frequency,
h.run_sequence
FROM
v_employee h,
v_trans v,
employee_emp ee,
employee eb
WHERE
( h.year = 2014 ) AND
( h.employee_id = ee.employee_id ) AND
( ee.employee_id = eb.employee_id ) AND
( h.employee_no = eb.employee_no ) AND
( h.trx_code = v.trx_code ) AND
( h.trx_type = v.trx_type ) AND
( v.company_code = ee.company_code OR v.company_code is NULL) AND
( h.trx_type IN ('S','B','N','O','A','D','L') )
)
)x,
employee_emp ee,
employee eb
WHERE
( x.employee_id = ee.employee_id ) AND
( ee.employee_id = eb.employee_id ) AND
( x.employee_no = eb.employee_no ) AND
( x.year = 2014 )
The count as you have it now will also count the 0 that is in the ELSE clause of the CASE expression. Even with DISTINCT still one instance of that 0 will be counted.
Remove the ELSE 0 so that you have NULL -- which is not counted:
count (distinct(CASE WHEN x.month =5 and x.employee_id <> 0
THEN x.employee_id
END)) as test_may
Note that with NULLIF you can shorten this expression to:
count (distinct(CASE x.month WHEN 5 THEN NULLIF(x.employee_id, 0) END)) as test_may
Your count will return the same count even in both cases. Because you are giving the value for Count function in both the cases.
Change from
count (distinct(CASE WHEN (x.month =5 and x.employee_id <> 0) THEN
x.employee_id
ELSE 0 END))
To
count (distinct(CASE WHEN (x.month =5 and x.employee_id <> 0) THEN
x.employee_id
ELSE NULL END))
Count will just count the values whether it is 0 or 100 as 1 & skip null values while counting. So in the Else condition NULL will give you correct output.

Group By OrgName but rollup by TotalCount

I would like to use the code below to group results by OrgName but rollup the count using TotalCount
Results would look similar to the screenshot below:(sorry I had to redact information due to confidentiality agreement).
The Orgname is grouped correctly. However, I am having a little troubling rolling up totalCount.
Thanks
WITH
ctePreAgg AS
(
SELECT (ElectionName + ' - ' + CAST(ClosingDate AS VARCHAR(12))) electionName, CASE WHEN Position='Member' THEN '' ELSE Position END As Position, CASE WHEN c.CurrentOfficeHolder='Incumbent' THEN CandidateName + '('+ c.CurrentOfficeHolder + ')' ELSE CandidateName END As CandidateName , c.PositionId,COUNT(*) TotalVotes
FROM Candidates c
JOIN Positions p ON c.PositionId = p.PositionId
JOIN Elections e on c.ElectionId = e.ElectionId
WHERE c.ElectionId IN (1,2,3)
GROUP BY Position, CandidateId, CandidateName,c.PositionId,CurrentOfficeHolder,AnswerType,ElectionName, ClosingDate
)
SELECT [OrgName] = CASE WHEN GROUPING(mh.PositionId) = 0 THEN MAX(mh.Position) ELSE mh.ElectionName END
,Names = CASE WHEN GROUPING(mh.PositionId) = 0 THEN MAX(mh.CandidateName) ELSE '' END
,PositionId = CASE WHEN GROUPING(mh.PositionId) = 0 THEN mh.PositionId ELSE '' END
,TotalCount = CASE WHEN GROUPING(mh.PositionId) = 0 THEN COUNT(*) ELSE '' END
FROM ctePreAgg mh
GROUP BY ElectionName,PositionId WITH ROLLUP
HAVING GROUPING(mh.ElectionName) = 0
ORDER BY mh.ElectionName, GROUPING(mh.PositionId) DESC, mh.PositionID;

How to use conditional columns values in the same select statement?

I have something like
(COMPLEX_EXPRESSION_N stands for a long subquery)
select
ID_Operation,
FirstCheck = CASE WHEN (COMPLEX_EXPRESSION_1)= 0 then 0 else 1 end,
SecondCheck = CASE WHEN (COMPLEX_EXPRESSION_2)= 0 then 0 else 1 end,
ThirdCheck = CASE WHEN (COMPLEX_EXPRESSION_3)= 0 then 0 else 1 end,
AllChecksOk = Case WHEN
(FirstCheck + SecondCheck + Third CHeck = 3)
Then 'OK' Else 'No' End
from
AllOperationsTable
Is it possible to use FirstCheck, SecondCheck, ThirdCheck as I did in the AllChecksOk line?
I am not concerned about performance, this is something that is manually run once a day on a very small number of records, I just want to avoid to create views, tables or temporary tables and keep all in a single select statement.
As an altenrative I can do this, but it makes the query less readable (as I need to write twice every complex expression):
select
ID_Operation,
FirstCheck = CASE WHEN (COMPLEX_EXPRESSION_1)= 0 then 0 else 1 end,
SecondCheck = CASE WHEN (COMPLEX_EXPRESSION_2)= 0 then 0 else 1 end,
ThirdCheck = CASE WHEN (COMPLEX_EXPRESSION_3)= 0 then 0 else 1 end,
AllChecksOk = Case WHEN
(COMPLEX_EXPRESSION_1+ COMPLEX_EXPRESSION_2+
COMPLEX_EXPRESSION_3CHeck = 3) Then 'OK' Else 'No' End
from
AllOperationsTable
You can't reference a column alias in the select but you can use a CTE as below.
;WITH CTE AS
(
select
ID_Operation,
FirstCheck = CASE WHEN (COMPLEX_EXPRESSION_1)= 0 then 0 else 1 end,
SecondCheck = CASE WHEN (COMPLEX_EXPRESSION_2)= 0 then 0 else 1 end,
ThirdCheck = CASE WHEN (COMPLEX_EXPRESSION_3)= 0 then 0 else 1 end
from
AllOperationsTable
)
SELECT *,
AllChecksOk = Case WHEN
(COMPLEX_EXPRESSION_1+ COMPLEX_EXPRESSION_2+
COMPLEX_EXPRESSION_3CHeck = 3) Then 'OK' Else 'No' End
FROM CTE
You can also use CROSS APPLY to define the 3 column aliases then reference them in the main SELECT list as in this example.
Below is a derived table solution
SELECT
T.ID_Operation,
FirstCheck = CASE WHEN T.Expr1 = 0 THEN 0 ELSE 1 END,
SecondCheck = CASE WHEN T.Expr2 = 0 THEN 0 ELSE 1 END,
ThirdCheck = CASE WHEN T.Expr3 = 0 THEN 0 ELSE 1 END,
AllChecksOk = CASE WHEN T.Expr1 + T.Expr2 + T.Expr3 = 3 THEN 'OK' ELSE 'No' END
FROM
(
SELECT
ID_Operation,
Expr1 = (COMPLEX_EXPRESSION_1),
Expr2 = (COMPLEX_EXPRESSION_2),
Expr3 = (COMPLEX_EXPRESSION_3)
FROM
AllOperationsTable
) T
Personally, I find using CTE or derived tables a bit confusing for this purpose, as you have to nest things one level and think about the nesting impliciations. A much simpler approach (at least in my opinion) is to use APPLY (or standard SQL LATERAL in other RDBMS) to generate column expression aliases:
SELECT
ID_Operation,
FirstCheck,
SecondCheck,
ThirdCheck,
AllChecksOk = CASE
WHEN FirstCheck + SecondCheck + ThirdCheck = 3 THEN 'OK' ELSE 'NO'
END
FROM
AllOperationsTable
CROSS APPLY (
SELECT
FirstCheck = CASE WHEN COMPLEX_EXPRESSION_1 = 0 THEN 0 ELSE 1 END,
SecondCheck = CASE WHEN COMPLEX_EXPRESSION_1 = 0 THEN 0 ELSE 1 END,
ThirdCheck = CASE WHEN COMPLEX_EXPRESSION_1 = 0 THEN 0 ELSE 1 END
) t

Resources