How to optimize this SQL Server query - Multiple subqueries - sql

I have this query, with 4 subqueries, in SQL Server and I'm looking a way to optimize it:
DECLARE #INICIO DATE
DECLARE #FIN DATE
SET #INICIO='2020-06-17'
SET #FIN='2020-07-27'
SELECT VALO.FECHA_VALORACION,
VALO.CODIGO_PORTAFOLIO,
VALO.CUSIP,
VALO.NUMERO_INVERSION,
VALO.SM_GRUPO
SM_TIPO,
VALO.TIPO_INSTRUMENTO DESCRIPCION_INSTMT,
VALO.CODIGO_MONEDA CODIGO_MONEDA_PAGAR,
VALO.CODIGO_MONEDA CODIGO_MONEDA_RECIBIR,
VALO.ID_CONTRAPARTE,
OP.PRECIO
PRECIO_FX,
VALO.VALOR_NOMINAL,
VALO.VALOR_DERECHO,
VALO.VALOR_OBLIGACION,
VALO.VALOR_UTILIDAD_PERDIDA,
OP.FECHA FECHA_OPERACION,
VALO.TIPO_OPERACION,
OP.VALOR_OPERACION VALOR_OPERACION_COP,
OP.FECHA_VENCIMIENTO,
VALO.SM_GRUPO,
VALO.VALOR_UTILIDAD_PERDIDA_DER,
VALO.VALOR_UTILIDAD_PERDIDA_OBL,
(SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
FROM Spirit.TSPT_VALORACION_FUT NESTED
WHERE NESTED.CUSIP=VALO.CUSIP
AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
AND FECHA_VALORACION>=dateadd(month, datediff(month, 0, #INICIO), 0)
AND FECHA_VALORACION<=VALO.FECHA_VALORACION
AND VALOR_UTILIDAD_PERDIDA>0
GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS UTILIDAD_MENSUAL,
(SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
FROM Spirit.TSPT_VALORACION_FUT NESTED
WHERE NESTED.CUSIP=VALO.CUSIP
AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
AND FECHA_VALORACION>=dateadd(month, datediff(month, 0, #INICIO), 0)
AND FECHA_VALORACION<=VALO.FECHA_VALORACION
AND VALOR_UTILIDAD_PERDIDA<0
GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS PERDIDA_MENSUAL,
(SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
FROM Spirit.TSPT_VALORACION_FUT NESTED
WHERE NESTED.CUSIP=VALO.CUSIP
AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
AND NESTED.FECHA_VALORACION<=VALO.FECHA_VALORACION
AND NESTED.VALOR_UTILIDAD_PERDIDA>0
GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS UTILIDAD_ACUMULADA,
(SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
FROM Spirit.TSPT_VALORACION_FUT NESTED
WHERE NESTED.CUSIP=VALO.CUSIP
AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
AND FECHA_VALORACION<=VALO.FECHA_VALORACION
AND VALOR_UTILIDAD_PERDIDA<0
GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS PERDIDA_ACUMULADA
FROM Spirit.TSPT_VALORACION_FUT VALO
INNER JOIN Spirit.TSPT_OPERACIONES OP ON OP.NUMERO_INVERSION = VALO.NUMERO_INVERSION
AND OP.TIPO_OPERACION = VALO.TIPO_OPERACION
AND OP.SM_GRUPO IN ('OPTION')
WHERE VALO.SM_GRUPO IN ('OPTION')
AND VALO.CODIGO_PORTAFOLIO IN ('AFP-P','AFP-F')
AND VALO.FECHA_VALORACION >= #INICIO
AND VALO.FECHA_VALORACION <= #FIN
ORDER BY VALO.CUSIP,VALO.FECHA_VALORACION
But I don't know how to integrate it and get the best. Thank you so much.
This is the result of a previous optimization process.
I've been trying some like this:
(SELECT sum (case when NESTED.VALOR_UTILIDAD_PERDIDA > 0 then NESTED.VALOR_UTILIDAD_PERDIDA else 0 end) as UTILIDAD_MENSUAL,
sum (case when NESTED.VALOR_UTILIDAD_PERDIDA < 0 then NESTED.VALOR_UTILIDAD_PERDIDA else 0 end) as PERDIDA_MENSUAL
FROM Spirit.TSPT_VALORACION_FUT NESTED
WHERE NESTED.CUSIP=VALO.CUSIP
AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
AND FECHA_VALORACION>=dateadd(month, datediff(month, 0, #INICIO), 0)
AND FECHA_VALORACION<=VALO.FECHA_VALORACION
AND VALOR_UTILIDAD_PERDIDA>0
GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS ACUMULADOS

Since all your sub-queries seem to be coming from the same table, you can consolidate them into a single query in the FROM clause ... Try this ... I really can't debug the syntax without a table schema to reference ...
DECLARE #INICIO DATE
DECLARE #FIN DATE
SET #INICIO='2020-06-17'
SET #FIN='2020-07-27'
SELECT
VALO.FECHA_VALORACION,
VALO.CODIGO_PORTAFOLIO,
VALO.CUSIP,
VALO.NUMERO_INVERSION,
VALO.SM_GRUPO
SM_TIPO,
VALO.TIPO_INSTRUMENTO DESCRIPCION_INSTMT,
VALO.CODIGO_MONEDA CODIGO_MONEDA_PAGAR,
VALO.CODIGO_MONEDA CODIGO_MONEDA_RECIBIR,
VALO.ID_CONTRAPARTE,
OP.PRECIO
PRECIO_FX,
VALO.VALOR_NOMINAL,
VALO.VALOR_DERECHO,
VALO.VALOR_OBLIGACION,
VALO.VALOR_UTILIDAD_PERDIDA,
OP.FECHA FECHA_OPERACION,
VALO.TIPO_OPERACION,
OP.VALOR_OPERACION VALOR_OPERACION_COP,
OP.FECHA_VENCIMIENTO,
VALO.SM_GRUPO,
VALO.VALOR_UTILIDAD_PERDIDA_DER,
VALO.VALOR_UTILIDAD_PERDIDA_OBL,
S.UTILIDAD_MENSUAL,
S.PERDIDA_MENSUAL,
S.UTILIDAD_ACUMULADA,
S.PERDIDA_ACUMULADA
FROM
Spirit.TSPT_VALORACION_FUT VALO
INNER JOIN Spirit.TSPT_OPERACIONES OP ON
OP.NUMERO_INVERSION = VALO.NUMERO_INVERSION
AND OP.TIPO_OPERACION = VALO.TIPO_OPERACION
AND OP.SM_GRUPO IN ('OPTION')
OUTER APPLY (
SELECT
SUM(CASE WHEN FECHA_VALORACION>=dateadd(month, datediff(month, 0, #INICIO), 0) AND VALOR_UTILIDAD_PERDIDA>0
THEN NESTED.VALOR_UTILIDAD_PERDIDA
ELSE 0
END) UTILIDAD_MENSUAL,
SUM(CASE WHEN FECHA_VALORACION>=dateadd(month, datediff(month, 0, #INICIO), 0) AND VALOR_UTILIDAD_PERDIDA<0
THEN NESTED.VALOR_UTILIDAD_PERDIDA
ELSE 0
END) PERDIDA_MENSUAL,
SUM(CASE WHEN NESTED.VALOR_UTILIDAD_PERDIDA>0
THEN NESTED.VALOR_UTILIDAD_PERDIDA
ELSE 0
END) UTILIDAD_ACUMULADA,
SUM(CASE WHEN VALOR_UTILIDAD_PERDIDA<0
THEN NESTED.VALOR_UTILIDAD_PERDIDA
ELSE 0 END
) PERDIDA_ACUMULADA
FROM
Spirit.TSPT_VALORACION_FUT NESTED
WHERE
FECHA_VALORACION<=VALO.FECHA_VALORACION AND
NESTED.CUSIP = VALO.CUSIP AND
NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
GROUP BY
CUSIP,
CODIGO_PORTAFOLIO
) S
WHERE
VALO.SM_GRUPO IN ('OPTION')
AND VALO.CODIGO_PORTAFOLIO IN ('AFP-P','AFP-F')
AND VALO.FECHA_VALORACION >= #INICIO
AND VALO.FECHA_VALORACION <= #FIN
ORDER BY
VALO.CUSIP,
VALO.FECHA_VALORACION

Related

How can I include more columns other than just percentage column in my sql query result?

When I use the below query I only get percentage column but I want the (buyer_id, buyer_name, created_date,total_work_orders_with_gtv_first_60_days, total_gtv_first_60_days, total_net_amount_first_60_days) to show as columns too. Would really appreciate your help please.
WITH results_cte AS (
SELECT
b.buyer_id,
b.buyer_name,
CAST(b.created_date AS DATE) AS created_date,
COALESCE(wo.total_work_orders_with_gtv_first_60_days, 0) AS total_work_orders_with_gtv_first_60_days,
COALESCE(wo.total_gtv_first_60_days, 0) AS total_gtv_first_60_days,
COALESCE(wo.total_net_amount_first_60_days, 0) AS total_net_amount_first_60_days
FROM dw.buyer b
LEFT JOIN (SELECT wo.buyer_id,
COUNT(CASE WHEN wo.gtv_date < DATEADD(DAY, 60, b.created_date) THEN wo.work_order_id ELSE NULL END) AS total_work_orders_with_gtv_first_60_days,
SUM(CASE WHEN wo.gtv_date < DATEADD(DAY, 60, b.created_date) THEN wo.gtv ELSE NULL END) AS total_gtv_first_60_days,
SUM(CASE WHEN wo.gtv_date < DATEADD(DAY, 60, b.created_date) THEN wo.net_amount ELSE NULL END) AS total_net_amount_first_60_days
FROM dw.work_order wo
JOIN dw.buyer b
ON wo.buyer_id = b.buyer_id
WHERE wo.gtv > 0
GROUP BY wo.buyer_id) wo
ON b.buyer_id = wo.buyer_id
WHERE b.buyer_segmentation = 'S - Self-Service'
AND b.status = 'Active'
AND b.created_date >= DATEADD(YEAR, -1, GETDATE())
)
SELECT (SELECT CAST(count(DISTINCT buyer_id) AS float) FROM results_cte WHERE total_work_orders_with_gtv_first_60_days > 0)
/ (SELECT CAST(count(DISTINCT buyer_id) AS float) FROM results_cte ) AS percentage

SQL Server issue with select and group by with calculated columns

I have this SQL I am trying to build:
select
a.Name,
(SELECT COUNT(b.PlannedCollectionDate) WHERE b.PlannedCollectionDate < GETDATE()) AS Due,
(SELECT COUNT(b.PlannedCollectionDate) WHERE b.PlannedCollectionDate = GETDATE()) AS Today,
(SELECT COUNT(b.PlannedCollectionDate) WHERE b.PlannedCollectionDate = DATEADD(DAY, 1, GETDATE())) AS Expected,
(SELECT COUNT(b.PlannedCollectionDate) WHERE b.PlannedCollectionDate > DATEADD(DAY, 1, GETDATE())) AS Planned
from Centers AS a
INNER JOIN Collections AS b
ON a.Id = b.CenterId
GROUP BY a.Name
But I get an error:
Column 'Collections.PlannedCollectionDate' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I know I could do something like this:
select
a.Name,
(SELECT COUNT(Id) FROM Collections WHERE CenterId = a.Id AND PlannedCollectionDate < GETDATE()) AS Due,
(SELECT COUNT(Id) FROM Collections WHERE CenterId = a.Id AND PlannedCollectionDate = GETDATE()) AS Today,
(SELECT COUNT(Id) FROM Collections WHERE CenterId = a.Id AND PlannedCollectionDate = DATEADD(DAY, 1, GETDATE())) AS Expected,
(SELECT COUNT(Id) FROM Collections WHERE CenterId = a.Id AND PlannedCollectionDate > DATEADD(DAY, 1, GETDATE())) AS Planned
from Centers AS a
But I assume that is slower because I have to do multiple selects from the same table (Collections).
So, my question is, what can I do to make my first query work? I don't think grouping by PlannedCollectionDate is right, because it will mess up my count
I think you want conditional aggregation:
select ce.Name,
SUM(CASE WHEN co.PlannedCollectionDate < GETDATE() THEN 1 ELSE 0 END) AS Due,
SUM(CASE WHEN co.PlannedCollectionDate = GETDATE() THEN 1 ELSE 0 END) AS Today,
SUM(CASE WHEN co.PlannedCollectionDate = DATEADD(DAY, 1, GETDATE()) THEN 1 ELSE 0 END) AS Expected,
SUM(CASE WHEN co.PlannedCollectionDate > DATEADD(DAY, 1, GETDATE()) THEN 1 ELSE 0 END) AS Planned
from Centers ce join
Collections co
on ce.Id = co.CenterId
group by ce.Name;
This implements what you have written. Do note the use of meaningful table aliases.
However, it will not do what you want, because GETDATE() has a time component. To fix that, convert it to a date:
select ce.Name,
SUM(CASE WHEN co.PlannedCollectionDate < CONVERT(DATE, GETDATE()) THEN 1 ELSE 0 END) AS Due,
SUM(CASE WHEN co.PlannedCollectionDate = CONVERT(DATE, GETDATE()) THEN 1 ELSE 0 END) AS Today,
SUM(CASE WHEN co.PlannedCollectionDate = DATEADD(DAY, 1, CONVERT(DATE, GETDATE())) THEN 1 ELSE 0 END) AS Expected,
SUM(CASE WHEN co.PlannedCollectionDate > DATEADD(DAY, 1, CONVERT(DATE, GETDATE())) THEN 1 ELSE 0 END) AS Planned
from Centers ce join
Collections co
on ce.Id = co.CenterId
group by ce.Name;
Note that this assumes that PlannedCollectionDate does not have a time component.

SQL counting based on date comparison

I've got the following SQL query which gives me all of my assets which are older than two years, broken down by organization. Then I have to run it again and just remove the date comparison part in the WHERE clause to find out my total number of assets, so I can give a count of old, a count of total, and then a % old.
Is there a way to do this all as a single query? I'm thinking some type of case statement in the query maybe?
SELECT o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, COUNT(DISTINCT a.LabAssetSerialNbr) TotalAssets
FROM vw_DimLabAsset a
INNER JOIN vw_DimWorker w ON w.WorkerKey = a.LabAssetAssignedToWorkerKey
INNER JOIN vw_DimOrganizationHierarchy o ON o.OrganizationHierarchyUnitCd = w.WorkerOrganizationUnitCd
AND o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
WHERE a.SystemCreatedOnDtm < DATEADD(day, DATEDIFF(day, 0, DATEADD(yy, -2, GETDATE())), 0)
AND a.LabAssetTypeNm IN ('u_cmdb_ci_prototype_system', 'u_cmdb_ci_silicon')
AND a.LabAssetHardwareStatus <> 'retired'
AND (a.LabAssetHardwareSubStatus IS NULL OR a.LabAssetHardwareSubStatus <> 'archive')
GROUP BY o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm
ORDER BY 1, 2
I tried adding this to the select: `
SUM(CASE WHEN a.SystemCreatedOnDtm < DATEADD(day, DATEDIFF(day, 0, DATEADD(yy, -2, GETDATE())), 0) THEN 1 ELSE 0 END)
but that doesn't return the same count as the TotalAssets value.
Update
Here's the final query I ended up with:
DECLARE #date DateTime
SELECT #date = DATEADD(day, DATEDIFF(day, 0, DATEADD(yy, -2, GETDATE())), 0);
WITH pphw AS
(
SELECT DISTINCT o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr, MIN(a.SystemCreatedOnDtm) MinCreated
FROM vw_DimLabAsset a
INNER JOIN vw_DimWorker w ON a.LabAssetAssignedToWorkerKey = w.WorkerKey
INNER JOIN vw_DimOrganizationHierarchy o ON w.WorkerOrganizationUnitCd = o.OrganizationHierarchyUnitCd
AND o.OrganizationHierarchyUnitLevelThreeNm IS NOT NULL
AND o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
WHERE LabAssetHardwareStatus <> 'Retired'
AND (LabAssetHardwareSubStatus IS NULL OR LabAssetHardwareSubStatus <> 'Archive')
AND a.LabAssetTypeNm IN ('u_cmdb_ci_prototype_system', 'u_cmdb_ci_silicon')
GROUP BY o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr
)
SELECT OrganizationHierarchyUnitLevelThreeNm, OrganizationHierarchyUnitLevelFourNm,
SUM(CASE WHEN MinCreated < #date THEN 1 ELSE 0 END) AssetsOverTwoYears,
COUNT(DISTINCT LabAssetSerialNbr) TotalAssets
FROM pphw
GROUP BY OrganizationHierarchyUnitLevelThreeNm, OrganizationHierarchyUnitLevelFourNm
HAVING SUM(CASE WHEN MinCreated < #date THEN 1 ELSE 0 END) > 0
ORDER BY 1, 2
My answer is similar to tysonwright, but I think the GROUP BY clause should be outside of the sub-select. But, I would want sample data to validate this. The bottom line is that you should first gather all of the records that you want calculate metrics on via a sub-select. From there, you can perform your SUMs and COUNTs.
SELECT TMP1.OrganizationHierarchyUnitLevelThreeNm
,TMP1.OrganizationHierarchyUnitLevelFourNm
,TotalAssets = COUNT(TMP1.LabAssetSerialNbr)
,AssetsOver2YearsOld = SUM(TMP1.AssetOver2YearsOldInd)
,PercAssetsOver2YearsOld = SUM(TMP1.AssetOver2YearsOldInd) / COUNT(TMP1.LabAssetSerialNbr)
FROM (SELECT DISTINCT o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr
,AssetOver2YearsOldInd = CASE WHEN a.SystemCreatedOnDtm < DATEADD(d, DATEDIFF(d, 0, DATEADD(yy, -2, GETDATE())), 0) THEN 1 ELSE 0 END
FROM vw_DimLabAsset a
INNER JOIN vw_DimWorker w
ON w.WorkerKey = a.LabAssetAssignedToWorkerKey
INNER JOIN vw_DimOrganizationHierarchy o
ON o.OrganizationHierarchyUnitCd = w.WorkerOrganizationUnitCd
AND o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
WHERE a.LabAssetTypeNm IN ('u_cmdb_ci_prototype_system', 'u_cmdb_ci_silicon')
AND a.LabAssetHardwareStatus <> 'retired'
AND (a.LabAssetHardwareSubStatus IS NULL
OR a.LabAssetHardwareSubStatus <> 'archive')
) TMP1
GROUP BY TMP1.OrganizationHierarchyUnitLevelThreeNm, TMP1.OrganizationHierarchyUnitLevelFourNm
ORDER BY 1, 2
Update:
To remove the duplicates by date time, you can use either the MIN or MAX function, depending one what your requirement is:
SELECT TMP1.OrganizationHierarchyUnitLevelThreeNm
,TMP1.OrganizationHierarchyUnitLevelFourNm
,TotalAssets = COUNT(TMP1.LabAssetSerialNbr)
,AssetsOver2YearsOld = SUM(CASE WHEN TMP1.MaxSystemCreatedOnDtm < DATEADD(d, DATEDIFF(d, 0, DATEADD(yy, -2, GETDATE())), 0) THEN 1 ELSE 0 END)
,PercAssetsOver2YearsOld = SUM(CASE WHEN TMP1.MaxSystemCreatedOnDtm < DATEADD(d, DATEDIFF(d, 0, DATEADD(yy, -2, GETDATE())), 0) THEN 1 ELSE 0 END) / COUNT(TMP1.LabAssetSerialNbr)
FROM (SELECT DISTINCT o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr, MaxSystemCreatedOnDtm = MAX(a.SystemCreatedOnDtm)
FROM vw_DimLabAsset a
INNER JOIN vw_DimWorker w
ON w.WorkerKey = a.LabAssetAssignedToWorkerKey
INNER JOIN vw_DimOrganizationHierarchy o
ON o.OrganizationHierarchyUnitCd = w.WorkerOrganizationUnitCd
AND o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
WHERE a.LabAssetTypeNm IN ('u_cmdb_ci_prototype_system', 'u_cmdb_ci_silicon')
AND a.LabAssetHardwareStatus <> 'retired'
AND (a.LabAssetHardwareSubStatus IS NULL
OR a.LabAssetHardwareSubStatus <> 'archive')
GROUP BY o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr
) TMP1
GROUP BY TMP1.OrganizationHierarchyUnitLevelThreeNm, TMP1.OrganizationHierarchyUnitLevelFourNm
ORDER BY 1, 2
I think this will get you what you need:
SELECT
s.OrganizationHierarchyUnitLevelThreeNm,
s.OrganizationHierarchyUnitLevelFourNm,
COUNT(*) TotalAssets,
SUM(CASE WHEN s.SystemCreatedOnDtm < DATEADD(day, DATEDIFF(day, 0, DATEADD(yy, -2, GETDATE())), 0)
THEN 1 ELSE 0 END) AssetsOver2YearsOld,
SUM(CASE WHEN s.SystemCreatedOnDtm < DATEADD(day, DATEDIFF(day, 0, DATEADD(yy, -2, GETDATE())), 0)
THEN 1 ELSE 0 END) / COUNT(*) PercAssetsOver2YearsOld
FROM
(
SELECT
o.OrganizationHierarchyUnitLevelThreeNm,
o.OrganizationHierarchyUnitLevelFourNm
a.LabAssetSerialNbr,
a.SystemCreatedOnDtm
FROM
vw_DimLabAsset a
INNER JOIN
vw_DimWorker w
ON
w.WorkerKey = a.LabAssetAssignedToWorkerKey
INNER JOIN
vw_DimOrganizationHierarchy o
ON
o.OrganizationHierarchyUnitCd = w.WorkerOrganizationUnitCd
AND
o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
WHERE
a.LabAssetTypeNm IN ('u_cmdb_ci_prototype_system', 'u_cmdb_ci_silicon')
AND
a.LabAssetHardwareStatus <> 'retired'
AND
(a.LabAssetHardwareSubStatus IS NULL OR a.LabAssetHardwareSubStatus <> 'archive')
GROUP BY
o.OrganizationHierarchyUnitLevelThreeNm,
o.OrganizationHierarchyUnitLevelFourNm
a.LabAssetSerialNbr,
a.SystemCreatedOnDtm
) AS s

Can I use sum with case statement on a max/min function?

I would like to sum the occurrence of a case.I tried to use the sum on the case statement but I get this error, how can it be solved?
Msg 130, Level 15, State 1, Line 3
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
My code example:
select
sum(case when cast(max(ptl.RowDate)as int) = cast(Min(ptl.RowDate) as int) then 1 else 0 end)
,DATEPART(WEEK, rowdate) week_
from m.dbo.tblLog ptl (nolock)
where rowdate > GETDATE()-91
group by DATEPART(WEEK, rowdate)
Update:
Based on comments: I would like to count distinct users that were visiting the webpage only once.I would like to get the counts based on weekly time frame.
You can not use aggregate functions inside another. You need to use sub-query or CTE:
SELECT SUM(something) as s,
week_
FROM (
select case when cast(max(ptl.RowDate)as int) = cast(Min(ptl.RowDate) as int) then 1 else 0 end as something,
DATEPART(WEEK, rowdate) week_
from m.dbo.tblLog ptl (nolock)
where rowdate > GETDATE()-91
group by DATEPART(WEEK, rowdate)
) as res
GROUP BY week_
Alternative way to your query
SELECT SUM(CASE WHEN CAST(MaxRowDate AS INT) = cast(MinRowDate AS INT) THEN 1 ELSE 0 END)
week_
FROM
(
SELECT MAX(ptl.RowDate) MaxRowDate,MIN(ptl.RowDate) MinRowDate,DATEPART(WEEK, rowdate) week_
FROM m.dbo.tblLog ptl (NOLOCK)
WHERE rowdate > GETDATE()-91
GROUP BY DATEPART(WEEK, rowdate)
)M
GROUP BY week_
If you just want a flag, why would you want a sum():
select (case when cast(max(ptl.RowDate)as int) = cast(Min(ptl.RowDate) as int)
then 1 else 0
end) as OneValueFlag,
DATEPART(WEEK, rowdate) as week_
from m.dbo.tblLog ptl (nolock)
where rowdate > GETDATE() - 91
group by DATEPART(WEEK, rowdate);
It is also entirely unclear why the value would be converted to a date:
select (case when max(ptl.RowDate) = Min(ptl.RowDate)
then 1 else 0
end) as OneValueFlag,
DATEPART(WEEK, rowdate) as week_
from m.dbo.tblLog ptl (nolock)
where rowdate > GETDATE() - 91
group by DATEPART(WEEK, rowdate);

Revenue for two months date wise

I am trying to get data for last 2 month ...but the query does not give perfect result....
SELECT DAY(table_A.PaymentDate) as date1 ,
(case when MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP) - 1
then CAST(SUM(table_A.Total_Amount) AS INT)
else 0
end) AS last_month_CNT,
(case when MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP)
then CAST(SUM(table_A.Total_Amount) As INT)
else 0
end) as This_month_CNT
FROM Tbl_Pan_Paymentdetails table_A
FULL OUTER JOIN Tbl_Pan_Paymentdetails table_B
ON table_A.PaymentDate=table_B.PaymentDate
WHERE YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP)
AND
table_A.PaymentDate >= DATEADD(MONTH, -1, GETDATE())
GROUP BY
DAY(table_A.PaymentDate) ,MONTH(table_A.PaymentDate)
order by
DAY(table_A.PaymentDate);
Move the entire case expression inside the sum function and don't include the month in the group by. Also, the full outer join seems unnecessary so I removed it.
This should be what you are looking for:
SELECT
DAY(PaymentDate) as date1 ,
SUM(CASE WHEN MONTH(PaymentDate) = MONTH(CURRENT_TIMESTAMP)-1 THEN CAST(Total_Amount AS INT) ELSE 0 END) AS last_month_CNT,
SUM(CASE WHEN MONTH(PaymentDate) = MONTH(CURRENT_TIMESTAMP) THEN CAST(Total_Amount AS INT) ELSE 0 END) AS This_month_CNT
FROM Tbl_Pan_Paymentdetails
WHERE YEAR(PaymentDate) = YEAR(CURRENT_TIMESTAMP)
AND PaymentDate >= DATEADD(MONTH, -1, GETDATE())
GROUP BY DAY(PaymentDate)
ORDER BY DAY(PaymentDate);