I keep getting a column ambiguously defined error when joining two sub queries. However I have defined all my columns properly. I want to get all the data from the first query and add some data to it where available. How can this be fixed?
SELECT
sq2.month,
sq1.PRIMARY_MER_NUM ,
sq1.PRIMARY_EXT_MID ,
sq1.MER_DBA_NAM,
sq1.CLG_NUM,
sq1.ENT_NUM,
sq1.ENT_NAM,
sq1.MER_OPN_DTE,
sq1.MER_CLS_DTE,
sq1.MER_FST_DPST_DTE,
sq1.CLG_NUM ,
sq1.ENT_NUM,
sq2.gross_volume,
sq2.transaction_count
FROM
(SELECT DISTINCT
PRIMARY_MER_NUM ,
PRIMARY_EXT_MID ,
MER_DBA_NAM,
CLG_NUM,
ENT_NUM,
ENT_NAM,
MER_OPN_DTE,
MER_CLS_DTE,
MER_FST_DPST_DTE,
CLG_NUM ,
ENT_NUM
FROM
bi.t_mer_dim_na
WHERE
CLG_NUM = 7
AND ENT_NUM IN ('45810', '45811', '46849', '45948', '45824',
'46911', '45509', '46845', '48902')
) sq1
LEFT JOIN
(SELECT
TRUNC(BAT_REF_DTE, 'MM') AS month,
MER_NUM,
SUM(bat_prd_trn_dr_amt + bat_prd_trn_cr_amt) AS gross_volume,
SUM(bat_item_num) AS transaction_count
FROM
TDS.BAT_T3
WHERE
1 = 1
AND bat_ref_dte >= TRUNC(sysdate, 'MM')
GROUP BY
TRUNC(BAT_REF_DTE, 'MM'), MER_NUM) SQ2 ON sq1.primary_mer_num = sq2.MER_NUM;
You have CLG_NUM and ENT_NUM selected twice in your first derived table SQL1
FROM (
select DISTINCT
PRIMARY_MER_NUM ,
PRIMARY_EXT_MID ,
MER_DBA_NAM,
CLG_NUM, --1
ENT_NUM, --1
ENT_NAM,
MER_OPN_DTE,
MER_CLS_DTE,
MER_FST_DPST_DTE,
CLG_NUM, --2
ENT_NUM --2
from bi.t_mer_dim_na
That makes selecting sql1.CLG_NUM and sql1.ENT_NUM ambiguous in your outer select (where you also select both twice)
Related
my table: "tfr_general_charges" has a column called MANDANT_ID. The column can have only two different values:
001 and 002
There are many records with the value 002 in MANDANT_ID column and my SELECT shows it as follows:
I marked red the missing row, which also has to be displayed. So far, it has been returning number of rows with MANDANT_ID = '002', but zero rows with MANDANT_ID '001' should also be visible.
Here is my code:
SELECT
"tfr_gen_ch" AS tabnam
, run_date
, mandant_id
, count(*) as total
FROM tfr_general_charges
GROUP BY
run_date
, mandant_id
having mandant_id = '002'
union
SELECT
"tfr_gen_ch" AS tabnam
, run_date
, mandant_id
, count(*) as total
FROM tfr_general_charges
GROUP BY
run_date
, mandant_id
having mandant_id = '001'
In addition, I work with HIVE SQL and tried to use ISNULL() function, but without success.
Can You please help?
Use UNION ALL to create a resultset with only 2 rows with 1 column containing the values '001' and '002' and do a LEFT join to your table before you aggregate:
SELECT "tfr_gen_ch" tabnam,
tcg.run_date,
t.mandant_id,
COUNT(tcg.mandant_id) AS total
FROM (SELECT '001' AS mandant_id UNION ALL SELECT '002') t
LEFT JOIN tfr_general_charges tcg
ON t.mandant_id = tcg.mandant_id
GROUP BY tcg.run_date, t.mandant_id;
My SQL code is removing duplicate values of "Time" specific to Project Description. For example, if a time value for a specific project is included two or more times, the data is only pulling the value once skewing the results.
I've tried adding SUM(PMTT_DailyTime.Time) as 'Sum of Time" and this creates a different problem and inaccurate results. It multiplies the sum values by the number of an irrelevant field.
SELECT View_ProjectsInfoDecoded.ProjectNbr
, View_ProjectsInfoDecoded.Department
, View_ProjectsInfoDecoded.ProjectDesc
, View_ProjectsInfoDecoded.ProjectStartDate
, View_ProjectsInfoDecoded.ProjectCompletionDate
, View_ProjectsInfoDecoded.VoidInd
, View_ProjectsInfoDecoded.ProjectStatus
, View_ProjectsInfoDecoded.ProjectType
, DatePart("yyyy", PMTT_DailyTime.ReportDate) AS [ReportYear]
, PMTT_DailyTime.Time
, PMTT_DailyTime.VoidInd
, View_ProjectsBuilderInfoDecoded.ProjectHealth
, View_ProjectsBuilderInfoDecoded.PrimaryBuilder
, View_ProjectsBuilderInfoDecoded.CurrentProjectStatus
FROM View_ProjectsInfoDecoded
LEFT JOIN View_ProjectsBuilderInfoDecoded ON View_ProjectsInfoDecoded.Department = View_ProjectsBuilderInfoDecoded.Department AND View_ProjectsInfoDecoded.ProjectNbr = View_ProjectsBuilderInfoDecoded.ProjectNbr
LEFT JOIN PMTT_DailyTime ON (View_ProjectsBuilderInfoDecoded.Department = PMTT_DailyTime.Department) AND (View_ProjectsBuilderInfoDecoded.ProjectNbr= PMTT_DailyTime.ProjectNbr)
WHERE (View_ProjectsInfoDecoded.Department IN ('107'))
And (View_ProjectsInfoDecoded.ProjectStatus <>'Cancel')
And (dbo.View_ProjectsInfoDecoded.VoidInd = 'N' OR dbo.View_ProjectsInfoDecoded.VoidInd IS NULL)
AND (PMTT_DailyTime.VoidInd = 'N' OR PMTT_DailyTime.VoidInd IS NULL)
AND ((DATEDIFF(MONTH, View_ProjectsInfoDecoded.ProjectCompletionDate,GETDATE()) <= 12) OR (View_ProjectsInfoDecoded.ProjectCompletionDate IS NULL) OR (View_ProjectsInfoDecoded.ProjectCompletionDate='' ))
GROUP BY View_ProjectsInfoDecoded.Department, View_ProjectsInfoDecoded.ProjectNbr
, View_ProjectsInfoDecoded.ProjectDesc, View_ProjectsInfoDecoded.ProjectStatus
, View_ProjectsInfoDecoded.EstStartDate, View_ProjectsInfoDecoded.ProjectStartDate
, View_ProjectsInfoDecoded.ProjectCompletionDate, View_ProjectsInfoDecoded.Complexity
, View_ProjectsInfoDecoded.ProjectType, View_ProjectsInfoDecoded.VoidInd
, View_ProjectsBuilderInfoDecoded.ProjectHealth, View_ProjectsBuilderInfoDecoded.PrimaryBuilder
, View_ProjectsBuilderInfoDecoded.CurrentProjectStatus, PMTT_DailyTime.VoidInd
, DatePart("yyyy", PMTT_DailyTime.ReportDate), PMTT_DailyTime.Time
I think this is an easy fix in the Group function or the type of joins used. But not sure...
With a re-factoring of your query to use aliases, include line breaks and re-order columns, you will notice you have two additional GROUP BY fields that are not included in SELECT: EstStartDate and p.Complexity. As a result, the SELECT columns may show repeated values over the distinct groupings of these omitted two fields.
For a more readable aggregate query, consider including the same columns in GROUP BY also in SELECT clause without omitting any. Do note: per SQL standard, you cannot have a column in SELECT that does not appear in GROUP BY. However, the reverse as your query does is valid. Alternatively, simply run the analogous SELECT DISTINCT without GROUP BY.
SELECT p.ProjectNbr, p.Department, p.ProjectDesc, p.ProjectStartDate, p.ProjectCompletionDate,
p.VoidInd, p.ProjectStatus, p.ProjectType, DatePart("yyyy", d.ReportDate) AS [ReportYear],
d.Time, d.VoidInd, b.ProjectHealth, b.PrimaryBuilder, b.CurrentProjectStatus
FROM (View_ProjectsInfoDecoded p
LEFT JOIN View_ProjectsBuilderInfoDecoded b
ON (p.Department = b.Department) AND (p.ProjectNbr = b.ProjectNbr))
LEFT JOIN PMTT_DailyTime d
ON (b.Department = d.Department) AND (b.ProjectNbr = d.ProjectNbr)
WHERE (p.Department IN ('107'))
AND (p.ProjectStatus <> 'Cancel')
AND (dbo.p.VoidInd = 'N' OR dbo.p.VoidInd IS NULL)
AND (d.VoidInd = 'N' OR d.VoidInd IS NULL)
AND ((DATEDIFF(MONTH, p.ProjectCompletionDate, GETDATE()) <= 12)
OR (p.ProjectCompletionDate IS NULL)
OR (p.ProjectCompletionDate='')
)
GROUP BY p.ProjectNbr, p.Department, p.ProjectDesc, p.ProjectStartDate, p.ProjectCompletionDate,
p.VoidInd, p.ProjectStatus, p.ProjectType, DatePart("yyyy", d.ReportDate),
d.Time, d.VoidInd, b.ProjectHealth, b.PrimaryBuilder, b.CurrentProjectStatus,
p.EstStartDate, p.Complexity -- ADDITIONAL NON-SELECT FIELDS
You are using the Group By clause, but have no aggregate function in your Select statement. This results in the same behavior as using Select Distinct. Removing the Group By clause will include the duplicate records you seem to be looking for.
SELECT View_ProjectsInfoDecoded.ProjectNbr, View_ProjectsInfoDecoded.Department, View_ProjectsInfoDecoded.ProjectDesc, View_ProjectsInfoDecoded.ProjectStartDate, View_ProjectsInfoDecoded.ProjectCompletionDate, View_ProjectsInfoDecoded.VoidInd, View_ProjectsInfoDecoded.ProjectStatus, View_ProjectsInfoDecoded.ProjectType, DatePart("yyyy", PMTT_DailyTime.ReportDate) AS [ReportYear], PMTT_DailyTime.Time, PMTT_DailyTime.VoidInd, View_ProjectsBuilderInfoDecoded.ProjectHealth, View_ProjectsBuilderInfoDecoded.PrimaryBuilder, View_ProjectsBuilderInfoDecoded.CurrentProjectStatus
FROM (View_ProjectsInfoDecoded LEFT JOIN View_ProjectsBuilderInfoDecoded ON (View_ProjectsInfoDecoded.Department = View_ProjectsBuilderInfoDecoded.Department) AND (View_ProjectsInfoDecoded.ProjectNbr = View_ProjectsBuilderInfoDecoded.ProjectNbr)) LEFT JOIN
PMTT_DailyTime ON (View_ProjectsBuilderInfoDecoded.Department = PMTT_DailyTime.Department) AND (View_ProjectsBuilderInfoDecoded.ProjectNbr= PMTT_DailyTime.ProjectNbr)
WHERE (View_ProjectsInfoDecoded.Department IN ('107')) And (View_ProjectsInfoDecoded.ProjectStatus <>'Cancel') And
(dbo.View_ProjectsInfoDecoded.VoidInd = 'N' OR dbo.View_ProjectsInfoDecoded.VoidInd IS NULL) AND (PMTT_DailyTime.VoidInd = 'N' OR PMTT_DailyTime.VoidInd IS NULL)
AND ((DATEDIFF(MONTH, View_ProjectsInfoDecoded.ProjectCompletionDate,GETDATE()) <= 12) OR (View_ProjectsInfoDecoded.ProjectCompletionDate IS NULL) OR (View_ProjectsInfoDecoded.ProjectCompletionDate='' ))
I am pretty new at SQL!
I have two querys from different tables. This is my first query:
SELECT cli.CLIENTE as clientet,cli.RAZON as nom,
SUM(distinct par.[RECAPTACIO]*0.9) AS recaudacionSINIVA,
SUM(distinct par.canvi) as cambiocargado,
SUM(distinct par.consum) as CC_recaptacio,count(distinct par.DATA) as visita,
SUM((c.quantitat + c.caixes * c.uxcaja) * c.pvp) as CC_Caducados
FROM [V30].[dbo].[parmaq] as par,[V30].[dbo].[clientes] as cli , V30.dbo.parcons as c
where cli.CLIENTE=par.EMPRESA and par.enllas=c.enllas
and par.data > '13-11-2015' and par.data < '20-11-2015'
group by cli.CLIENTE,cli.RAZON
And this is the result:
This is my second query:
SELECT cli.cliente as clientet, cli.RAZON, SUM( distinct m1.IMPORTE) as FACTURACION,
SUM(distinct m2.coste * m2.canti) as CC_facturacio
FROM [V30].[dbo].[clientes] as cli, [V30].[dbo].[MESTA1] as m1,V30.dbo.MESTA2 as m2
where m2.albaran=m1.albaran and m1.CLIENTE=cli.CLIENTE
and m1.FECHA > '13-11-2015' and m1.FECHA < '30-11-2015'
group by cli.CLIENTE,cli.razon order by cli.cliente
And the result of the second query:
On the sql there is no way of linking the tables with primary key! and the results from the querys one and two are fine. What I want to do is combining the results using the column "clientet". I have to say that you can get different numbers of rows.
The goal is to have all this information on the same result. For example, if "clientet" have results on both querys, the final result should be all the columns from the first query + "FACTURACION" and "CC_facturacio" from the second query.
Hope you can help me, I have been trying Inner Joins and sub-querys but there is no way to get this.
Two options:
As jarlh suggested, you could do a union as long as you put place holders in each query for the missing columns that don't exist and make sure they are in the same order.
You could do a full outer join of your two queries. You may want to add coalesce to each other column, depending on whether you want nulls to appear for columns when a row doesn't exist in both tables.
The example below assumes clientet is the joining column:
SELECT COALESCE(TBL_1.clientet, TBL_2.clientet) as clientet
, TBL_1.nom
, TBL_1.recaudacionSINIVA
, TBL_1.cambiocargado
, TBL_1.CC_recaptacio
, TBL_1.visita
, TBL_1.CC_Caducados
, TBL_2.FACTURACION
, TBL_2.CC_facturacio
FROM
(SELECT cli.CLIENTE as clientet
, cli.RAZON as nom
, SUM(distinct par.[RECAPTACIO]*0.9) AS recaudacionSINIVA
, SUM(distinct par.canvi) as cambiocargado
, SUM(distinct par.consum) as CC_recaptacio
, count(distinct par.DATA) as visita
, SUM((c.quantitat + c.caixes * c.uxcaja) * c.pvp) as CC_Caducados
FROM [V30].[dbo].[parmaq] as par,[V30].[dbo].[clientes] as cli , V30.dbo.parcons as c
where cli.CLIENTE=par.EMPRESA and par.enllas=c.enllas
and par.data > '13-11-2015' and par.data < '20-11-2015'
group by cli.CLIENTE,cli.RAZON) TBL_1
FULL OUTER JOIN
(SELECT cli.cliente as clientet
, cli.RAZON
, SUM( distinct m1.IMPORTE) as FACTURACION
, SUM(distinct m2.coste * m2.canti) as CC_facturacio
FROM [V30].[dbo].[clientes] as cli, [V30].[dbo].[MESTA1] as m1,V30.dbo.MESTA2 as m2
where m2.albaran=m1.albaran and m1.CLIENTE=cli.CLIENTE
and m1.FECHA > '13-11-2015' and m1.FECHA < '30-11-2015'
group by cli.CLIENTE,cli.razon) TBL_2
ON TBL_1.clientet = TBL_2.clientet
ORDER BY COALESCE(TBL_1.clientet, TBL_2.clientet)
UPDATE :
-----
the error might be in sum(si.amt_pd) from item table (as there is no relation) :
select SUM(si.amt_pd)amt_pd from [HMIS_REPORTING].HMIS_RPT_ME.dbo.item i
where
is there a work around?
----------
I am trying to run this query. The query just fetches the amount of a month based on some tables. It is just a part of a big query.
select s.sales_Contract_Nbr
, s.Sales_Id
, s.Sale_Dt
, YEAR(s.Sale_Dt) 'YEAR'
, MONTH(s.Sale_Dt) 'MONTH'
, s.Sales_Need_TYpe_Cd
, s.Sales_Status_Cd
, si.Posted
, s.location_Cd
, jan2011 = (
select SUM(si.amt_pd)amt_pd
from [HMIS_REPORTING].HMIS_RPT_ME.dbo.item i
where i.Item_Id = si.Product_Item_ID
and i.Item_Cd <> '*INT'
and convert(varchar(10),SI.Sales_Item_Dt,126) >= '2011-01-01'
and convert(varchar(10),SI.Sales_Item_Dt,126) >= '2011-01-31'
) INTO dbo.#a_acomparision
FROM [HMIS_REPORTING].HMIS_RPT_ME.dbo.Sales S
, [HMIS_REPORTING].HMIS_RPT_ME.dbo.Sales_Item SI
WHERE SI.Sales_Id = S.Sales_Id
and s.Sales_Contract_Nbr in (
select distinct (Sales_Contract_Nbr)
from mountainviewContracts
where Sales_Contract_Nbr <> '')
but I am getting the following error message.
Msg 8120, Level 16, State 1, Line 1
Column 'HMIS_REPORTING.HMIS_RPT_ME.dbo.Sales.Sales_Contract_Nbr' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I just can't understand why my query should have a group by for sales_contract_nbr and even if I put in the group by clause it tells me that inner query si.Product_item_id and SI.sales_item_dt should also be contained in group by clause.
Please help me out.
Thanks in advance
This is a very subtle problem. However, I think the subquery should be:
select SUM(i.amt_pd)amt_pd from [HMIS_REPORTING].HMIS_RPT_ME.dbo.item i
That is, the alias should be i not si.
What is happening is that the sum in the subquery is on a value in the outer query. So, the SQL compiler assumes an aggregation query. As soon as the first column is found that is not an aggregation, it complains with the message that you have.
By the way, you should use proper join syntax, so you from clause looks like:
FROM [HMIS_REPORTING].HMIS_RPT_ME.dbo.Sales S join
[HMIS_REPORTING].HMIS_RPT_ME.dbo.Sales_Item SI
on SI.Sales_Id = S.Sales_Id
As #Gordon Linoff says, this is almost certainly because the query optimizer is treating this like a SUM operation, normalizing away the subquery for "jan2001".
If the amt_pd column is present in the ITEM table, Gordon's solution is the right one.
If not, you have to add the group by statement, as below.
select s.sales_Contract_Nbr
, s.Sales_Id
, s.Sale_Dt
, YEAR(s.Sale_Dt) 'YEAR'
, MONTH(s.Sale_Dt) 'MONTH'
, s.Sales_Need_TYpe_Cd
, s.Sales_Status_Cd
, si.Posted
, s.location_Cd
, jan2011 = (
select SUM(si.amt_pd)amt_pd
from [HMIS_REPORTING].HMIS_RPT_ME.dbo.item i
where i.Item_Id = si.Product_Item_ID
and i.Item_Cd <> '*INT'
and convert(varchar(10),SI.Sales_Item_Dt,126) >= '2011-01-01'
and convert(varchar(10),SI.Sales_Item_Dt,126) >= '2011-01-31'
) INTO dbo.#a_acomparision
FROM [HMIS_REPORTING].HMIS_RPT_ME.dbo.Sales S
, [HMIS_REPORTING].HMIS_RPT_ME.dbo.Sales_Item SI
WHERE SI.Sales_Id = S.Sales_Id
and s.Sales_Contract_Nbr in (
select distinct (Sales_Contract_Nbr)
from mountainviewContracts
where Sales_Contract_Nbr <> '')
GROUP BY s.sales_Contract_Nbr
, s.Sales_Id
, s.Sale_Dt
, YEAR
, MONTH
, s.Sales_Need_TYpe_Cd
, s.Sales_Status_Cd
, si.Posted
, s.location_Cd
I have a query which is taking some serious time to execute on anything older than the past, say, hours worth of data. This is going to create a view which will be used for datamining, so the expectations are that it would be able to search back weeks or months of data and return in a reasonable amount of time (even a couple minutes is fine... I ran for a date range of 10/3/2011 12:00pm to 10/3/2011 1:00pm and it took 44 minutes!)
The problem is with the two LEFT OUTER JOINs in the bottom. When I take those out, it can run in about 10 seconds. However, those are the bread and butter of this query.
This is all coming from one table. The ONLY thing this query returns differently than the original table is the column xweb_range. xweb_range is a calculated field column (range) which will only use the values from [LO,LC,RO,RC]_Avg where their corresponding [LO,LC,RO,RC]_Sensor_Alarm = 0 (do not include in range calculation if sensor alarm = 1)
WITH Alarm (sub_id,
LO_Avg, LO_Sensor_Alarm, LC_Avg, LC_Sensor_Alarm, RO_Avg, RO_Sensor_Alarm, RC_Avg, RC_Sensor_Alarm) AS (
SELECT sub_id, LO_Avg, LO_Sensor_Alarm, LC_Avg, LC_Sensor_Alarm, RO_Avg, RO_Sensor_Alarm, RC_Avg, RC_Sensor_Alarm
FROM dbo.some_table
where sub_id <> '0'
)
, AddRowNumbers AS (
SELECT rowNumber = ROW_NUMBER() OVER (ORDER BY LO_Avg)
, sub_id
, LO_Avg, LO_Sensor_Alarm
, LC_Avg, LC_Sensor_Alarm
, RO_Avg, RO_Sensor_Alarm
, RC_Avg, RC_Sensor_Alarm
FROM Alarm
)
, UnPivotColumns AS (
SELECT rowNumber, value = LO_Avg FROM AddRowNumbers WHERE LO_Sensor_Alarm = 0
UNION ALL SELECT rowNumber, LC_Avg FROM AddRowNumbers WHERE LC_Sensor_Alarm = 0
UNION ALL SELECT rowNumber, RO_Avg FROM AddRowNumbers WHERE RO_Sensor_Alarm = 0
UNION ALL SELECT rowNumber, RC_Avg FROM AddRowNumbers WHERE RC_Sensor_Alarm = 0
)
SELECT rowNumber.sub_id
, cds.equipment_id
, cds.read_time
, cds.LC_Avg
, cds.LC_Dev
, cds.LC_Ref_Gap
, cds.LC_Sensor_Alarm
, cds.LO_Avg
, cds.LO_Dev
, cds.LO_Ref_Gap
, cds.LO_Sensor_Alarm
, cds.RC_Avg
, cds.RC_Dev
, cds.RC_Ref_Gap
, cds.RC_Sensor_Alarm
, cds.RO_Avg
, cds.RO_Dev
, cds.RO_Ref_Gap
, cds.RO_Sensor_Alarm
, COALESCE(range1.range, range2.range) AS xweb_range
FROM AddRowNumbers rowNumber
LEFT OUTER JOIN (SELECT rowNumber, range = MAX(value) - MIN(value) FROM UnPivotColumns GROUP BY rowNumber HAVING COUNT(*) > 1) range1 ON range1.rowNumber = rowNumber.rowNumber
LEFT OUTER JOIN (SELECT rowNumber, range = AVG(value) FROM UnPivotColumns GROUP BY rowNumber HAVING COUNT(*) = 1) range2 ON range2.rowNumber = rowNumber.rowNumber
INNER JOIN dbo.some_table cds
ON rowNumber.sub_id = cds.sub_id
It's difficult to understand exactly what your query is trying to do without knowing the domain. However, it seems to me like your query is simply trying to find, for each row in dbo.some_table where sub_id is not 0, the range of the following columns in the record (or, if only one matches, that single value):
LO_AVG when LO_SENSOR_ALARM=0
LC_AVG when LC_SENSOR_ALARM=0
RO_AVG when RO_SENSOR_ALARM=0
RC_AVG when RC_SENSOR_ALARM=0
You constructed this query assigning each row a sequential row number, unpivoted the _AVG columns along with their row number, computed the range aggregate grouping by row number and then joining back to the original records by row number. CTEs don't materialize results (nor are they indexed, as discussed in the comments). So each reference to AddRowNumbers is expensive, because ROW_NUMBER() OVER (ORDER BY LO_Avg) is a sort.
Instead of cutting this table up just to join it back together by row number, why not do something like:
SELECT cds.sub_id
, cds.equipment_id
, cds.read_time
, cds.LC_Avg
, cds.LC_Dev
, cds.LC_Ref_Gap
, cds.LC_Sensor_Alarm
, cds.LO_Avg
, cds.LO_Dev
, cds.LO_Ref_Gap
, cds.LO_Sensor_Alarm
, cds.RC_Avg
, cds.RC_Dev
, cds.RC_Ref_Gap
, cds.RC_Sensor_Alarm
, cds.RO_Avg
, cds.RO_Dev
, cds.RO_Ref_Gap
, cds.RO_Sensor_Alarm
--if the COUNT is 0, xweb_range will be null (since MAX will be null), if it's 1, then use MAX, else use MAX - MIN (as per your example)
, (CASE WHEN stats.[Count] < 2 THEN stats.[MAX] ELSE stats.[MAX] - stats.[MIN] END) xweb_range
FROM dbo.some_table cds
--cross join on the following table derived from values in cds - it will always contain 1 record per row of cds
CROSS APPLY
(
SELECT COUNT(*), MIN(Value), MAX(Value)
FROM
(
--construct a table using the column values from cds we wish to aggregate
VALUES (LO_AVG, LO_SENSOR_ALARM),
(LC_AVG, LC_SENSOR_ALARM),
(RO_AVG, RO_SENSORALARM),
(RC_AVG, RC_SENSOR_ALARM)
) x (Value, Sensor_Alarm) --give a name to the columns for _AVG and _ALARM
WHERE Sensor_Alarm = 0 --filter our constructed table where _ALARM=0
) stats([Count], [Min], [Max]) --give our derived table and its columns some names
WHERE cds.sub_id <> '0' --this is a filter carried over from the first CTE in your example